academic-refchecker 1.2.66__py3-none-any.whl → 1.2.67__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.
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/METADATA +1 -1
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/RECORD +15 -10
- backend/cli.py +11 -3
- backend/database.py +27 -2
- backend/main.py +105 -4
- backend/static/assets/index-2P6L_39v.css +1 -0
- backend/static/assets/index-hk21nqxR.js +25 -0
- backend/static/favicon.svg +6 -0
- backend/static/index.html +15 -0
- backend/static/vite.svg +1 -0
- refchecker/__version__.py +2 -2
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/WHEEL +0 -0
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/entry_points.txt +0 -0
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/licenses/LICENSE +0 -0
- {academic_refchecker-1.2.66.dist-info → academic_refchecker-1.2.67.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
academic_refchecker-1.2.
|
|
1
|
+
academic_refchecker-1.2.67.dist-info/licenses/LICENSE,sha256=Kwrx3fePVCeEFDCZvCW4OuoTNBiSoYbpGBI6qzGhWF0,1067
|
|
2
2
|
backend/__init__.py,sha256=TFVkOx5tSp3abty15RzUbaSwQ9ZD0kfUn7PDh63xkYY,521
|
|
3
3
|
backend/__main__.py,sha256=74V7yUMsRSZaaRyXYm-rZVc3TVUcUgwsoTQTUbV5EqM,211
|
|
4
|
-
backend/cli.py,sha256=
|
|
4
|
+
backend/cli.py,sha256=xV3l9M5OdNQQYOcrzj2d_7RmCgj7CXP_1oi0TPe6zNo,1672
|
|
5
5
|
backend/concurrency.py,sha256=2KY9I_8dDkyl_HTGx27ZxU4rFXx2vqbGOlo5RrRbPjA,3223
|
|
6
|
-
backend/database.py,sha256=
|
|
7
|
-
backend/main.py,sha256=
|
|
6
|
+
backend/database.py,sha256=1jLP1m9vNk5sEs4bh_xmX0T5ilZkUTX1c7nOVz5XnNc,30681
|
|
7
|
+
backend/main.py,sha256=ntz5PbEfG65ENFTHVQlY-c8hP5UPM_hdFjl60YMNh78,54371
|
|
8
8
|
backend/models.py,sha256=El2F-RTHgxQ7-WODmiYCpjsTFDpjwF9PBt-JDa_XipE,2591
|
|
9
9
|
backend/refchecker_wrapper.py,sha256=B8oERiF81Pbrv0bS9CWUiFIzUQyfXCv8k4dz_jojaYk,51935
|
|
10
10
|
backend/thumbnail.py,sha256=wPFXp3RlmcL9jVKZmSBRB7Pfy9Ti7nCnzNtL4osfNtM,17618
|
|
11
11
|
backend/websocket_manager.py,sha256=l-Wou-rKV6n7t6Gcf5fR6s_4G-mssSrba0davNnYS70,4247
|
|
12
|
+
backend/static/favicon.svg,sha256=R0oQauh16Uy0D7JlT27k-zdjJtrvfPKOe9La5vKYwuM,395
|
|
13
|
+
backend/static/index.html,sha256=eJDL5t98ZJOl85d1_kJNNSUhmgGft_PCKcgbdG0UvCw,598
|
|
14
|
+
backend/static/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
|
|
15
|
+
backend/static/assets/index-2P6L_39v.css,sha256=KC3Wa6jfD1qwmEoVpqTovlzf8fsn5oHYz3NKta6BJxw,27469
|
|
16
|
+
backend/static/assets/index-hk21nqxR.js,sha256=z2agP8ZFYw4AfYi-GJ5E_8_k-lPF-frXOJtPk-I0hDs,369533
|
|
12
17
|
refchecker/__init__.py,sha256=Pg5MrtLxDBRcNYcI02N-bv3tzURVd1S3nQ8IyF7Zw7E,322
|
|
13
18
|
refchecker/__main__.py,sha256=agBbT9iKN0g2xXtRNCoh29Nr7z2n5vU-r0MCVJKi4tI,232
|
|
14
|
-
refchecker/__version__.py,sha256=
|
|
19
|
+
refchecker/__version__.py,sha256=QbiiKfrg5J0KRTqnyydeu-Z_bfxMSCxJSVP-REY-I5M,89
|
|
15
20
|
refchecker/checkers/__init__.py,sha256=T0PAHTFt6UiGvn-WGoJU8CdhXNmf6zaHmcGVoWHhmJQ,533
|
|
16
21
|
refchecker/checkers/crossref.py,sha256=88moAyTudBqf9SKqTQkNAq1yyuRe95f8r4EpmJznupQ,20937
|
|
17
22
|
refchecker/checkers/enhanced_hybrid_checker.py,sha256=2jIeUX7hankPok3M4de9o2bsJZ17ZomuLkdfdr9EV0s,28671
|
|
@@ -52,8 +57,8 @@ refchecker/utils/mock_objects.py,sha256=QxU-UXyHSY27IZYN8Sb8ei0JtNkpGSdMXoErrRLH
|
|
|
52
57
|
refchecker/utils/text_utils.py,sha256=v5beDt_fyx4ETfTXLYrDMp3CuUGoDoLs7-d1H2GdySE,228585
|
|
53
58
|
refchecker/utils/unicode_utils.py,sha256=-WBKarXO756p7fd7gCeNsMag4ztDNURwFX5IVniOtwY,10366
|
|
54
59
|
refchecker/utils/url_utils.py,sha256=7b0rWCQJSajzqOvD7ghsBZPejiq6mUIz6SGhvU_WGDs,9441
|
|
55
|
-
academic_refchecker-1.2.
|
|
56
|
-
academic_refchecker-1.2.
|
|
57
|
-
academic_refchecker-1.2.
|
|
58
|
-
academic_refchecker-1.2.
|
|
59
|
-
academic_refchecker-1.2.
|
|
60
|
+
academic_refchecker-1.2.67.dist-info/METADATA,sha256=WdOCHtCuQm9wB9VnBXGAE9ExURgnzyPvBL4cMsq1TO4,25778
|
|
61
|
+
academic_refchecker-1.2.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
62
|
+
academic_refchecker-1.2.67.dist-info/entry_points.txt,sha256=9cREsaKwlp05Ql0CBIjKrNHk5IG2cHY5LvJPsV2-SxA,108
|
|
63
|
+
academic_refchecker-1.2.67.dist-info/top_level.txt,sha256=FfNvrvpj25gfpUBjW0epvz7Qrdejhups5Za_DBiSRu4,19
|
|
64
|
+
academic_refchecker-1.2.67.dist-info/RECORD,,
|
backend/cli.py
CHANGED
|
@@ -7,12 +7,13 @@ This module provides the console script entry point for the refchecker-webui com
|
|
|
7
7
|
|
|
8
8
|
import sys
|
|
9
9
|
import argparse
|
|
10
|
+
from pathlib import Path
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def main():
|
|
13
14
|
"""Main entry point for the refchecker-webui command."""
|
|
14
15
|
parser = argparse.ArgumentParser(
|
|
15
|
-
description="Start the RefChecker Web UI
|
|
16
|
+
description="Start the RefChecker Web UI server"
|
|
16
17
|
)
|
|
17
18
|
parser.add_argument(
|
|
18
19
|
"--host",
|
|
@@ -40,8 +41,15 @@ def main():
|
|
|
40
41
|
print("Install it with: pip install 'academic-refchecker[webui]'")
|
|
41
42
|
sys.exit(1)
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
# Check if static frontend is bundled
|
|
45
|
+
static_dir = Path(__file__).parent / "static"
|
|
46
|
+
has_frontend = static_dir.exists() and (static_dir / "index.html").exists()
|
|
47
|
+
|
|
48
|
+
print(f"Starting RefChecker Web UI on http://{args.host}:{args.port}")
|
|
49
|
+
if has_frontend:
|
|
50
|
+
print(f"Open http://localhost:{args.port} in your browser")
|
|
51
|
+
else:
|
|
52
|
+
print("Note: Frontend not bundled. Start it separately: cd web-ui && npm run dev")
|
|
45
53
|
print()
|
|
46
54
|
|
|
47
55
|
uvicorn.run(
|
backend/database.py
CHANGED
|
@@ -4,15 +4,38 @@ Database module for storing check history and LLM configurations
|
|
|
4
4
|
import aiosqlite
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
|
+
import sys
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from typing import List, Optional, Dict, Any
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from cryptography.fernet import Fernet
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
def get_data_dir() -> Path:
|
|
15
|
+
"""Get platform-appropriate user data directory for refchecker.
|
|
16
|
+
|
|
17
|
+
Windows: %LOCALAPPDATA%\refchecker
|
|
18
|
+
macOS: ~/Library/Application Support/refchecker
|
|
19
|
+
Linux: ~/.local/share/refchecker
|
|
20
|
+
"""
|
|
21
|
+
if sys.platform == "win32":
|
|
22
|
+
# Windows: use LOCALAPPDATA
|
|
23
|
+
base = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local"))
|
|
24
|
+
elif sys.platform == "darwin":
|
|
25
|
+
# macOS: use Application Support
|
|
26
|
+
base = Path.home() / "Library" / "Application Support"
|
|
27
|
+
else:
|
|
28
|
+
# Linux/Unix: use XDG_DATA_HOME or ~/.local/share
|
|
29
|
+
base = Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share"))
|
|
30
|
+
|
|
31
|
+
data_dir = base / "refchecker"
|
|
32
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
return data_dir
|
|
34
|
+
|
|
35
|
+
|
|
13
36
|
def get_encryption_key() -> bytes:
|
|
14
37
|
"""Get or create encryption key for API keys"""
|
|
15
|
-
key_file =
|
|
38
|
+
key_file = get_data_dir() / ".encryption_key"
|
|
16
39
|
if key_file.exists():
|
|
17
40
|
return key_file.read_bytes()
|
|
18
41
|
else:
|
|
@@ -24,7 +47,9 @@ def get_encryption_key() -> bytes:
|
|
|
24
47
|
class Database:
|
|
25
48
|
"""Handles SQLite database operations for check history and LLM configs"""
|
|
26
49
|
|
|
27
|
-
def __init__(self, db_path: str =
|
|
50
|
+
def __init__(self, db_path: Optional[str] = None):
|
|
51
|
+
if db_path is None:
|
|
52
|
+
db_path = str(get_data_dir() / "refchecker_history.db")
|
|
28
53
|
self.db_path = db_path
|
|
29
54
|
self._fernet = Fernet(get_encryption_key())
|
|
30
55
|
|
backend/main.py
CHANGED
|
@@ -7,9 +7,10 @@ import os
|
|
|
7
7
|
import tempfile
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Optional
|
|
10
|
-
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, UploadFile, File, Form, HTTPException, Body
|
|
10
|
+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, UploadFile, File, Form, HTTPException, Body, Request
|
|
11
11
|
from fastapi.middleware.cors import CORSMiddleware
|
|
12
|
-
from fastapi.responses import FileResponse
|
|
12
|
+
from fastapi.responses import FileResponse, HTMLResponse
|
|
13
|
+
from fastapi.staticfiles import StaticFiles
|
|
13
14
|
from pydantic import BaseModel
|
|
14
15
|
import logging
|
|
15
16
|
|
|
@@ -69,10 +70,13 @@ class CheckLabelUpdate(BaseModel):
|
|
|
69
70
|
# Create FastAPI app
|
|
70
71
|
app = FastAPI(title="RefChecker Web UI API", version="1.0.0")
|
|
71
72
|
|
|
73
|
+
# Static files directory for bundled frontend
|
|
74
|
+
STATIC_DIR = Path(__file__).parent / "static"
|
|
75
|
+
|
|
72
76
|
# Configure CORS for local development
|
|
73
77
|
app.add_middleware(
|
|
74
78
|
CORSMiddleware,
|
|
75
|
-
allow_origins=["http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5174", "http://localhost:5175", "http://127.0.0.1:5174", "http://127.0.0.1:5175"],
|
|
79
|
+
allow_origins=["http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5174", "http://localhost:5175", "http://127.0.0.1:5174", "http://127.0.0.1:5175", "http://localhost:8000", "http://127.0.0.1:8000"],
|
|
76
80
|
allow_credentials=True,
|
|
77
81
|
allow_methods=["*"],
|
|
78
82
|
allow_headers=["*"],
|
|
@@ -117,7 +121,12 @@ async def startup_event():
|
|
|
117
121
|
|
|
118
122
|
@app.get("/")
|
|
119
123
|
async def root():
|
|
120
|
-
"""
|
|
124
|
+
"""Serve frontend if available, otherwise return API health check"""
|
|
125
|
+
# If static frontend is bundled, serve it
|
|
126
|
+
index_path = STATIC_DIR / "index.html"
|
|
127
|
+
if index_path.exists():
|
|
128
|
+
return FileResponse(str(index_path), media_type="text/html")
|
|
129
|
+
# Otherwise return API health check
|
|
121
130
|
return {"status": "ok", "message": "RefChecker Web UI API"}
|
|
122
131
|
|
|
123
132
|
|
|
@@ -985,6 +994,27 @@ async def validate_llm_config(config: LLMConfigValidate):
|
|
|
985
994
|
Validate an LLM configuration by making a test API call.
|
|
986
995
|
Returns success or error message.
|
|
987
996
|
"""
|
|
997
|
+
# Map providers to their required packages
|
|
998
|
+
PROVIDER_PACKAGES = {
|
|
999
|
+
"anthropic": ("anthropic", "pip install anthropic"),
|
|
1000
|
+
"openai": ("openai", "pip install openai"),
|
|
1001
|
+
"google": ("google.generativeai", "pip install google-generativeai"),
|
|
1002
|
+
"gemini": ("google.generativeai", "pip install google-generativeai"),
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
# Check if required package is installed for this provider
|
|
1006
|
+
provider_lower = config.provider.lower()
|
|
1007
|
+
if provider_lower in PROVIDER_PACKAGES:
|
|
1008
|
+
module_name, install_cmd = PROVIDER_PACKAGES[provider_lower]
|
|
1009
|
+
try:
|
|
1010
|
+
__import__(module_name.split('.')[0])
|
|
1011
|
+
except ImportError:
|
|
1012
|
+
raise HTTPException(
|
|
1013
|
+
status_code=400,
|
|
1014
|
+
detail=f"The '{config.provider}' provider requires the '{module_name.split('.')[0]}' package. "
|
|
1015
|
+
f"Please install it with: {install_cmd}"
|
|
1016
|
+
)
|
|
1017
|
+
|
|
988
1018
|
try:
|
|
989
1019
|
import sys
|
|
990
1020
|
from pathlib import Path
|
|
@@ -1005,6 +1035,18 @@ async def validate_llm_config(config: LLMConfigValidate):
|
|
|
1005
1035
|
if not provider:
|
|
1006
1036
|
raise HTTPException(status_code=400, detail=f"Failed to create {config.provider} provider")
|
|
1007
1037
|
|
|
1038
|
+
# Check if provider is available (has required client initialized)
|
|
1039
|
+
if hasattr(provider, 'is_available') and not provider.is_available():
|
|
1040
|
+
# Provider was created but client failed to initialize
|
|
1041
|
+
if provider_lower in PROVIDER_PACKAGES:
|
|
1042
|
+
_, install_cmd = PROVIDER_PACKAGES[provider_lower]
|
|
1043
|
+
raise HTTPException(
|
|
1044
|
+
status_code=400,
|
|
1045
|
+
detail=f"Provider '{config.provider}' is not available. "
|
|
1046
|
+
f"Make sure the required package is installed: {install_cmd}"
|
|
1047
|
+
)
|
|
1048
|
+
raise HTTPException(status_code=400, detail=f"Provider '{config.provider}' is not available")
|
|
1049
|
+
|
|
1008
1050
|
# Make a simple test call using _call_llm
|
|
1009
1051
|
test_response = provider._call_llm("Say 'ok' if you can hear me.")
|
|
1010
1052
|
|
|
@@ -1025,6 +1067,16 @@ async def validate_llm_config(config: LLMConfigValidate):
|
|
|
1025
1067
|
raise HTTPException(status_code=400, detail="Invalid API key")
|
|
1026
1068
|
elif "rate" in error_msg.lower():
|
|
1027
1069
|
raise HTTPException(status_code=400, detail="Rate limited - but API key is valid")
|
|
1070
|
+
elif "'NoneType'" in error_msg:
|
|
1071
|
+
# This usually means the provider library isn't installed
|
|
1072
|
+
if provider_lower in PROVIDER_PACKAGES:
|
|
1073
|
+
_, install_cmd = PROVIDER_PACKAGES[provider_lower]
|
|
1074
|
+
raise HTTPException(
|
|
1075
|
+
status_code=400,
|
|
1076
|
+
detail=f"The '{config.provider}' provider requires additional packages. "
|
|
1077
|
+
f"Please install with: {install_cmd}"
|
|
1078
|
+
)
|
|
1079
|
+
raise HTTPException(status_code=400, detail=f"Provider initialization failed. Check that required packages are installed.")
|
|
1028
1080
|
else:
|
|
1029
1081
|
raise HTTPException(status_code=400, detail=f"Validation failed: {error_msg}")
|
|
1030
1082
|
|
|
@@ -1261,6 +1313,55 @@ async def clear_database():
|
|
|
1261
1313
|
raise HTTPException(status_code=500, detail=str(e))
|
|
1262
1314
|
|
|
1263
1315
|
|
|
1316
|
+
# Mount static files for bundled frontend (if available)
|
|
1317
|
+
# This must be after all API routes to avoid conflicts
|
|
1318
|
+
if STATIC_DIR.exists() and (STATIC_DIR / "index.html").exists():
|
|
1319
|
+
# Mount assets directory for JS/CSS files
|
|
1320
|
+
if (STATIC_DIR / "assets").exists():
|
|
1321
|
+
app.mount("/assets", StaticFiles(directory=str(STATIC_DIR / "assets")), name="assets")
|
|
1322
|
+
|
|
1323
|
+
@app.get("/favicon.svg")
|
|
1324
|
+
async def favicon():
|
|
1325
|
+
"""Serve favicon"""
|
|
1326
|
+
favicon_path = STATIC_DIR / "favicon.svg"
|
|
1327
|
+
if favicon_path.exists():
|
|
1328
|
+
return FileResponse(str(favicon_path), media_type="image/svg+xml")
|
|
1329
|
+
raise HTTPException(status_code=404)
|
|
1330
|
+
|
|
1331
|
+
@app.get("/{full_path:path}")
|
|
1332
|
+
async def serve_spa(request: Request, full_path: str):
|
|
1333
|
+
"""
|
|
1334
|
+
Serve the SPA frontend for all non-API routes.
|
|
1335
|
+
This enables client-side routing.
|
|
1336
|
+
"""
|
|
1337
|
+
# Don't serve SPA for API routes (they're handled above)
|
|
1338
|
+
if full_path.startswith("api/"):
|
|
1339
|
+
raise HTTPException(status_code=404, detail="API endpoint not found")
|
|
1340
|
+
|
|
1341
|
+
# Try to serve the exact file if it exists
|
|
1342
|
+
file_path = STATIC_DIR / full_path
|
|
1343
|
+
if file_path.exists() and file_path.is_file():
|
|
1344
|
+
# Determine content type
|
|
1345
|
+
suffix = file_path.suffix.lower()
|
|
1346
|
+
media_types = {
|
|
1347
|
+
".html": "text/html",
|
|
1348
|
+
".css": "text/css",
|
|
1349
|
+
".js": "application/javascript",
|
|
1350
|
+
".json": "application/json",
|
|
1351
|
+
".png": "image/png",
|
|
1352
|
+
".jpg": "image/jpeg",
|
|
1353
|
+
".jpeg": "image/jpeg",
|
|
1354
|
+
".svg": "image/svg+xml",
|
|
1355
|
+
".ico": "image/x-icon",
|
|
1356
|
+
}
|
|
1357
|
+
media_type = media_types.get(suffix, "application/octet-stream")
|
|
1358
|
+
return FileResponse(str(file_path), media_type=media_type)
|
|
1359
|
+
|
|
1360
|
+
# For all other paths, serve index.html (SPA routing)
|
|
1361
|
+
index_path = STATIC_DIR / "index.html"
|
|
1362
|
+
return FileResponse(str(index_path), media_type="text/html")
|
|
1363
|
+
|
|
1364
|
+
|
|
1264
1365
|
if __name__ == "__main__":
|
|
1265
1366
|
import uvicorn
|
|
1266
1367
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-400:oklch(70.4% .191 22.216);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-purple-400:oklch(71.4% .203 305.504);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--leading-tight:1.25;--radius-md:.375rem;--radius-lg:.5rem;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentColor}::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::-moz-placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing)*2)}.top-4{top:calc(var(--spacing)*4)}.top-full{top:100%}.right-0{right:calc(var(--spacing)*0)}.right-2{right:calc(var(--spacing)*2)}.right-4{right:calc(var(--spacing)*4)}.bottom-4{bottom:calc(var(--spacing)*4)}.bottom-16{bottom:calc(var(--spacing)*16)}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.float-left{float:left}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-1{margin:calc(var(--spacing)*1)}.m-2{margin:calc(var(--spacing)*2)}.m-3{margin:calc(var(--spacing)*3)}.m-4{margin:calc(var(--spacing)*4)}.m-5{margin:calc(var(--spacing)*5)}.mx-1{margin-inline:calc(var(--spacing)*1)}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-3{margin-inline:calc(var(--spacing)*3)}.mx-4{margin-inline:calc(var(--spacing)*4)}.mx-5{margin-inline:calc(var(--spacing)*5)}.mx-auto{margin-inline:auto}.my-0\.5{margin-block:calc(var(--spacing)*.5)}.my-1{margin-block:calc(var(--spacing)*1)}.my-2{margin-block:calc(var(--spacing)*2)}.my-3{margin-block:calc(var(--spacing)*3)}.my-4{margin-block:calc(var(--spacing)*4)}.my-5{margin-block:calc(var(--spacing)*5)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-5{margin-top:calc(var(--spacing)*5)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-3{margin-right:calc(var(--spacing)*3)}.mr-4{margin-right:calc(var(--spacing)*4)}.mr-5{margin-right:calc(var(--spacing)*5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.-ml-1{margin-left:calc(var(--spacing)*-1)}.ml-0\.5{margin-left:calc(var(--spacing)*.5)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-5{margin-left:calc(var(--spacing)*5)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-24{margin-left:calc(var(--spacing)*24)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1{height:calc(var(--spacing)*1)}.h-2{height:calc(var(--spacing)*2)}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-14{height:calc(var(--spacing)*14)}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:calc(var(--spacing)*48)}.min-h-0{min-height:calc(var(--spacing)*0)}.w-1{width:calc(var(--spacing)*1)}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-7{width:calc(var(--spacing)*7)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-48{width:calc(var(--spacing)*48)}.w-64{width:calc(var(--spacing)*64)}.w-\[600px\]{width:600px}.w-full{width:100%}.w-px{width:1px}.max-w-4xl{max-width:var(--container-4xl)}.max-w-\[90vw\]{max-width:90vw}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[140px\]{min-width:140px}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-y{resize:vertical}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.bg-gray-600{background-color:var(--color-gray-600)}.bg-white\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.bg-white\/10{background-color:color-mix(in oklab,var(--color-white)10%,transparent)}}.p-1{padding:calc(var(--spacing)*1)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-5{padding-block:calc(var(--spacing)*5)}.py-8{padding-block:calc(var(--spacing)*8)}.pt-0\.5{padding-top:calc(var(--spacing)*.5)}.pt-1{padding-top:calc(var(--spacing)*1)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-5{padding-top:calc(var(--spacing)*5)}.pr-1{padding-right:calc(var(--spacing)*1)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-3{padding-right:calc(var(--spacing)*3)}.pr-4{padding-right:calc(var(--spacing)*4)}.pr-5{padding-right:calc(var(--spacing)*5)}.pr-8{padding-right:calc(var(--spacing)*8)}.pb-1{padding-bottom:calc(var(--spacing)*1)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pb-5{padding-bottom:calc(var(--spacing)*5)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-5{padding-left:calc(var(--spacing)*5)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-gray-200{color:var(--color-gray-200)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-purple-400{color:var(--color-purple-400)}.text-red-400{color:var(--color-red-400)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.line-through{text-decoration-line:line-through}.overline{text-decoration-line:overline}.underline{text-decoration-line:underline}.opacity-25{opacity:.25}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.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,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}@media(hover:hover){.hover\:border-blue-400:hover{border-color:var(--color-blue-400)}.hover\:bg-\[var\(--color-bg-tertiary\)\]:hover{background-color:var(--color-bg-tertiary)}.hover\:bg-black\/10:hover{background-color:#0000001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-black\/10:hover{background-color:color-mix(in oklab,var(--color-black)10%,transparent)}}.hover\:bg-blue-500:hover{background-color:var(--color-blue-500)}.hover\:bg-gray-800:hover{background-color:var(--color-gray-800)}.hover\:bg-white\/20:hover{background-color:#fff3}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/20:hover{background-color:color-mix(in oklab,var(--color-white)20%,transparent)}}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}@media(prefers-color-scheme:dark){@media(hover:hover){.dark\:hover\:bg-white\/10:hover{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-white\/10:hover{background-color:color-mix(in oklab,var(--color-white)10%,transparent)}}}}}:root{--color-bg-primary:#fff;--color-bg-secondary:#f7f7f8;--color-bg-tertiary:#ececf1;--color-bg-hover:#e0e0e5;--color-text-primary:#0d0d0d;--color-text-secondary:#676767;--color-text-muted:#8e8ea0;--color-border:#e5e5e5;--color-accent:#10a37f;--color-accent-hover:#0d8a6f;--color-error:#ef4146;--color-error-bg:#fef2f2;--color-warning:#f59e0b;--color-warning-bg:#fffbeb;--color-success:#10a37f;--color-success-bg:#ecfdf5;--color-info:#6366f1;--color-info-bg:#eef2ff;--color-link:#2563eb;--color-suggestion:#8b5cf6;--color-suggestion-bg:#f5f3ff;--sidebar-width:280px;--sidebar-bg:#f9f9f9}.dark{--color-bg-primary:#212121;--color-bg-secondary:#2f2f2f;--color-bg-tertiary:#424242;--color-bg-hover:#525252;--color-text-primary:#ececec;--color-text-secondary:#b4b4b4;--color-text-muted:#8e8e8e;--color-border:#444;--color-accent:#10a37f;--color-accent-hover:#1a7f64;--color-error:#f87171;--color-error-bg:#3b1818;--color-warning:#fbbf24;--color-warning-bg:#3b2f05;--color-success:#10a37f;--color-success-bg:#052e22;--color-info:#818cf8;--color-info-bg:#1e1b4b;--color-link:#60a5fa;--color-suggestion:#a78bfa;--color-suggestion-bg:#2e1f4d;--sidebar-bg:#171717}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}body{background-color:var(--color-bg-primary);color:var(--color-text-primary);min-height:100vh;margin:0}#root{min-height:100vh}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--color-bg-secondary)}::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-text-muted)}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:1s linear infinite spin}.drop-zone{border:2px dashed var(--color-border);transition:all .2s}.drop-zone.active{border-color:var(--color-accent);background-color:var(--color-info-bg)}.progress-bar{background:linear-gradient(90deg,var(--color-accent)0%,var(--color-info)100%)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|