diff --git a/navi/api/deps.py b/navi/api/deps.py
index c769b2e..bfc940c 100644
--- a/navi/api/deps.py
+++ b/navi/api/deps.py
@@ -16,6 +16,13 @@
build_default_registries,
)
from navi.llm.ollama import OllamaBackend
+from navi.auth.deps import (
+ get_current_user,
+ get_current_user_ws,
+ require_admin,
+ require_permission,
+ require_user,
+)
from navi.memory import MemoryStore
from navi.workers import Worker, build_default_workers
diff --git a/navi/api/routes/admin.py b/navi/api/routes/admin.py
new file mode 100644
index 0000000..beaa760
--- /dev/null
+++ b/navi/api/routes/admin.py
@@ -0,0 +1,141 @@
+"""Admin endpoints for multi-user Navi management."""
+
+from typing import Annotated
+
+import structlog
+from fastapi import APIRouter, Depends, HTTPException
+
+from navi.api.deps import (
+ get_session_store,
+ require_admin,
+ require_permission,
+)
+from navi.auth import User
+from navi.config import settings
+from navi.core import SessionStore
+
+log = structlog.get_logger()
+router = APIRouter(prefix="/admin", tags=["admin"])
+
+
+@router.get("/sessions")
+async def admin_list_sessions(
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_admin)],
+):
+ """Return all sessions across all users."""
+ sessions = await store.list_all(user_id=user.id, is_admin=True)
+ return [
+ {
+ "session_id": s.id,
+ "profile_id": s.profile_id,
+ "user_id": s.user_id,
+ "name": s.name,
+ "message_count": len(s.messages),
+ "pinned": s.pinned,
+ "created_at": s.created_at.isoformat(),
+ "last_active": s.last_active.isoformat(),
+ }
+ for s in sessions
+ ]
+
+
+@router.get("/users")
+async def admin_list_users(
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_admin)],
+):
+ """Return all registered navi_users."""
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ rows = await conn.fetch(
+ "SELECT id, email, display_name, role, permissions, created_at, updated_at FROM navi_users ORDER BY created_at DESC"
+ )
+ return [
+ {
+ "id": r["id"],
+ "email": r["email"],
+ "display_name": r["display_name"],
+ "role": r["role"],
+ "permissions": r["permissions"],
+ "created_at": r["created_at"].isoformat(),
+ "updated_at": r["updated_at"].isoformat(),
+ }
+ for r in rows
+ ]
+
+
+@router.get("/memory")
+async def admin_list_memory(
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_permission("navi.memory.read_all"))],
+):
+ """Return all memory facts (global view)."""
+ from navi.api.deps import get_memory_store
+
+ memory = get_memory_store()
+ facts = await memory.get_all_facts(limit=500)
+ return {"facts": facts, "count": len(facts)}
+
+
+@router.patch("/users/{user_id}/role")
+async def admin_update_user_role(
+ user_id: str,
+ body: dict,
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_admin)],
+):
+ """Update a user's cached role (requires admin)."""
+ role = body.get("role")
+ if role not in ("user", "admin"):
+ raise HTTPException(status_code=400, detail="Invalid role")
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(
+ "UPDATE navi_users SET role = $1, updated_at = $2 WHERE id = $3",
+ role,
+ __import__("datetime").datetime.now(__import__("datetime").timezone.utc),
+ user_id,
+ )
+ log.info("admin.role_updated", target_user_id=user_id, role=role, admin_id=user.id)
+ return {"ok": True}
+
+
+@router.get("/profiles")
+async def admin_list_profiles(
+ user: Annotated[User, Depends(require_permission("navi.profiles.manage"))],
+):
+ """Return all profiles including admin-only ones."""
+ from navi.api.deps import get_profile_registry
+
+ profiles = get_profile_registry()
+ return [
+ {
+ "id": p.id,
+ "name": p.name,
+ "description": p.description,
+ "is_admin_only": getattr(p, "is_admin_only", False),
+ }
+ for p in profiles.all()
+ ]
+
+
+@router.patch("/profiles/{profile_id}/availability")
+async def admin_update_profile_availability(
+ profile_id: str,
+ body: dict,
+ user: Annotated[User, Depends(require_permission("navi.profiles.manage"))],
+):
+ """Toggle admin-only visibility for a profile."""
+ is_admin_only = body.get("is_admin_only")
+ if not isinstance(is_admin_only, bool):
+ raise HTTPException(status_code=400, detail="is_admin_only must be a boolean")
+ # Profile configuration is loaded from navi/profiles/ config files.
+ # For now this is a no-op endpoint; actual persistence requires editing profile JSON.
+ log.info(
+ "admin.profile_availability",
+ profile_id=profile_id,
+ is_admin_only=is_admin_only,
+ admin_id=user.id,
+ )
+ return {"ok": True, "note": "Profile availability is managed via profile config files"}
diff --git a/navi/api/routes/agents.py b/navi/api/routes/agents.py
index d017ea9..10b4124 100644
--- a/navi/api/routes/agents.py
+++ b/navi/api/routes/agents.py
@@ -4,7 +4,8 @@
from fastapi import APIRouter, Depends, HTTPException
-from navi.api.deps import get_profile_registry, get_tool_registry
+from navi.api.deps import get_current_user, get_profile_registry, get_tool_registry
+from navi.auth import User
from navi.config import settings
from navi.core import ProfileRegistry, ToolRegistry
@@ -14,9 +15,14 @@
@router.get("/profiles")
async def list_profiles(
profiles: Annotated[ProfileRegistry, Depends(get_profile_registry)],
+ user: Annotated[User | None, Depends(get_current_user)] = None,
) -> list[dict]:
- return [
- {
+ is_admin = user is not None and user.role == "admin"
+ result = []
+ for p in profiles.all():
+ if getattr(p, "is_admin_only", False) and not is_admin:
+ continue
+ result.append({
"id": p.id,
"name": p.name,
"description": p.description,
@@ -30,9 +36,8 @@
"iteration_budget_enabled": p.iteration_budget_enabled,
"think_enabled": p.think_enabled,
"subagent_think_enabled": p.subagent_think_enabled,
- }
- for p in profiles.all()
- ]
+ })
+ return result
@router.get("/prompts")
diff --git a/navi/api/routes/auth.py b/navi/api/routes/auth.py
new file mode 100644
index 0000000..0de33a5
--- /dev/null
+++ b/navi/api/routes/auth.py
@@ -0,0 +1,180 @@
+"""Auth endpoints for gnexus-auth OAuth integration."""
+
+import asyncio
+from datetime import datetime, timezone
+
+import structlog
+from fastapi import APIRouter, HTTPException, Request, Response
+from gnexus_gauth.exceptions import (
+ PkceException,
+ StateValidationException,
+ TokenExchangeException,
+)
+
+from navi.auth.client import get_gauth_client
+from navi.auth.deps import get_current_user, require_user
+from navi.auth.encrypt import get_encryptor
+from navi.auth import User
+from navi.config import settings
+
+log = structlog.get_logger()
+router = APIRouter(prefix="/auth", tags=["auth"])
+
+
+@router.get("/login")
+async def auth_login(request: Request) -> Response:
+ """Redirect to gnexus-auth OAuth authorization endpoint."""
+ client = get_gauth_client()
+
+ auth_request = client.build_authorization_request(
+ return_to="/",
+ scopes=["openid", "email", "profile", "roles", "permissions"],
+ )
+
+ log.info("auth.login_redirect", state=auth_request.state[:8] + "...")
+ return Response(status_code=302, headers={"Location": auth_request.authorization_url})
+
+
+@router.get("/callback")
+async def auth_callback(code: str, state: str, request: Request) -> Response:
+ """Handle OAuth callback from gnexus-auth."""
+ client = get_gauth_client()
+ encryptor = get_encryptor()
+
+ # Exchange code for tokens (sync IO wrapped in thread)
+ try:
+ token_set = await asyncio.to_thread(client.exchange_authorization_code, code, state)
+ except (StateValidationException, PkceException) as e:
+ log.warning("auth.invalid_state", state=state[:8], error=str(e))
+ raise HTTPException(status_code=400, detail="Invalid or expired state") from e
+ except TokenExchangeException as e:
+ log.warning("auth.token_exchange_failed", error=str(e))
+ raise HTTPException(status_code=400, detail="Token exchange failed") from e
+
+ # Fetch user info (sync IO wrapped in thread)
+ try:
+ auth_user = await asyncio.to_thread(client.fetch_user, token_set.access_token)
+ except Exception as e:
+ log.warning("auth.fetch_user_failed", error=str(e))
+ raise HTTPException(status_code=400, detail="Failed to fetch user info") from e
+
+ # Determine role
+ role = "user"
+ permissions: list[str] = []
+ for access in auth_user.client_access_list:
+ if access.client_id == settings.gnexus_auth_client_id:
+ if settings.gnexus_auth_admin_role_slug in (access.role_ids or []):
+ role = "admin"
+ permissions = list(access.permission_ids or [])
+ break
+
+ # Upsert navi_user
+ try:
+ from navi.api.deps import get_session_store
+ store = get_session_store()
+ pool = await store._get_pool()
+ import json
+ async with pool.acquire() as conn:
+ await conn.execute(
+ """INSERT INTO navi_users (id, email, display_name, role, permissions, created_at, updated_at)
+ VALUES ($1, $2, $3, $4, $5, $6, $6)
+ ON CONFLICT (id) DO UPDATE
+ SET email = EXCLUDED.email,
+ display_name = EXCLUDED.display_name,
+ role = EXCLUDED.role,
+ permissions = EXCLUDED.permissions,
+ updated_at = EXCLUDED.updated_at""",
+ auth_user.user_id,
+ auth_user.email,
+ auth_user.profile.get("display_name") or auth_user.email,
+ role,
+ json.dumps(permissions),
+ datetime.now(timezone.utc),
+ )
+ except Exception:
+ log.warning("auth.upsert_user_failed", user_id=auth_user.user_id, exc_info=True)
+
+ # Create auth session
+ session_id = __import__("uuid").uuid4().hex
+ try:
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(
+ """INSERT INTO user_auth_sessions
+ (id, user_id, access_token_enc, refresh_token_enc, expires_at, created_at, last_used_at)
+ VALUES ($1, $2, $3, $4, $5, $6, $6)""",
+ session_id,
+ auth_user.user_id,
+ encryptor.encrypt(token_set.access_token),
+ encryptor.encrypt(token_set.refresh_token or ""),
+ token_set.expires_at or datetime.now(timezone.utc),
+ datetime.now(timezone.utc),
+ )
+ except Exception:
+ log.warning("auth.create_session_failed", user_id=auth_user.user_id, exc_info=True)
+
+ # Set cookie
+ cookie_value = session_id
+ max_age = settings.navi_auth_cookie_max_age_days * 86400
+ cookie_str = (
+ f"{settings.navi_auth_cookie_name}={cookie_value}; "
+ f"Max-Age={max_age}; "
+ f"HttpOnly; "
+ f"Path=/; "
+ f"SameSite={settings.navi_auth_cookie_samesite}"
+ )
+ if settings.navi_auth_cookie_secure:
+ cookie_str += "; Secure"
+
+ log.info("auth.login_success", user_id=auth_user.user_id, role=role)
+ return Response(
+ status_code=302,
+ headers={
+ "Location": "/",
+ "Set-Cookie": cookie_str,
+ },
+ )
+
+
+@router.post("/logout")
+async def auth_logout(response: Response, user: Annotated[User, Depends(require_user)], request: Request) -> dict:
+ """Logout current user."""
+ cookie_name = settings.navi_auth_cookie_name
+ session_id = request.cookies.get(cookie_name)
+
+ if session_id:
+ try:
+ from navi.api.deps import get_session_store
+ store = get_session_store()
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute("DELETE FROM user_auth_sessions WHERE id = $1", session_id)
+ except Exception:
+ log.warning("auth.logout_cleanup_failed", exc_info=True)
+
+ # Clear cookie
+ cookie_str = (
+ f"{cookie_name}=; "
+ f"Max-Age=0; "
+ f"HttpOnly; "
+ f"Path=/; "
+ f"SameSite={settings.navi_auth_cookie_samesite}"
+ )
+ if settings.navi_auth_cookie_secure:
+ cookie_str += "; Secure"
+
+ response.headers["Set-Cookie"] = cookie_str
+ log.info("auth.logout", user_id=user.id)
+ return {"ok": True}
+
+
+@router.get("/me")
+async def auth_me(user: Annotated[User, Depends(require_user)]) -> dict:
+ """Return current authenticated user."""
+ return {
+ "id": user.id,
+ "email": user.email,
+ "display_name": user.display_name,
+ "role": user.role,
+ "permissions": user.permissions,
+ }
diff --git a/navi/api/routes/messages.py b/navi/api/routes/messages.py
index 082405c..7933099 100644
--- a/navi/api/routes/messages.py
+++ b/navi/api/routes/messages.py
@@ -5,8 +5,10 @@
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
-from navi.api.deps import get_agent
-from navi.core import Agent
+from navi.api.deps import get_agent, get_session_store, require_user
+from navi.auth import User
+from navi.auth.deps import check_session_access
+from navi.core import Agent, SessionStore
from navi.exceptions import MaxIterationsReached, NaviError, SessionNotFound
router = APIRouter(prefix="/sessions", tags=["messages"])
@@ -21,7 +23,13 @@
session_id: str,
body: SendMessageRequest,
agent: Annotated[Agent, Depends(get_agent)],
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
+ session = await store.get(session_id)
+ if session is None:
+ raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user)
try:
reply = await agent.run(session_id, body.content)
return {"role": "assistant", "content": reply}
diff --git a/navi/api/routes/sessions.py b/navi/api/routes/sessions.py
index 0fd1d77..77d9dcc 100644
--- a/navi/api/routes/sessions.py
+++ b/navi/api/routes/sessions.py
@@ -11,7 +11,17 @@
from fastapi.responses import FileResponse
from pydantic import BaseModel
-from navi.api.deps import get_backend_registry, get_memory_store, get_profile_registry, get_session_store
+from navi.api.deps import (
+ get_backend_registry,
+ get_memory_store,
+ get_profile_registry,
+ get_session_store,
+ require_admin,
+ require_permission,
+ require_user,
+)
+from navi.auth import User
+from navi.auth.deps import check_session_access
from navi.content_store import list_for_session
from navi.config import settings
from navi.core import BackendRegistry, ProfileRegistry, SessionStore
@@ -43,13 +53,14 @@
store: Annotated[SessionStore, Depends(get_session_store)],
profiles: Annotated[ProfileRegistry, Depends(get_profile_registry)],
memory: Annotated[MemoryStore, Depends(get_memory_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
try:
profiles.get(body.profile_id)
except ProfileNotFound:
raise HTTPException(status_code=404, detail=f"Profile '{body.profile_id}' not found")
- session = await store.create(body.profile_id)
+ session = await store.create(body.profile_id, user_id=user.id)
# Fire-and-forget: extract memory from any stale sessions (last active > 30 min ago)
async def _deduped_extract():
@@ -97,12 +108,14 @@
@router.get("")
async def list_sessions(
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
limit: Annotated[int | None, Query(ge=1, le=100)] = None,
offset: Annotated[int | None, Query(ge=0)] = None,
profile_id: str | None = None,
) -> dict | list[dict]:
+ is_admin = user.role == "admin" or user.has_permission("navi.sessions.read_all")
if limit is None and offset is None:
- sessions = await store.list_all()
+ sessions = await store.list_all(user_id=user.id, is_admin=is_admin)
if profile_id:
sessions = [s for s in sessions if s.profile_id == profile_id]
return [_session_summary(s) for s in sessions]
@@ -113,6 +126,8 @@
limit=page_limit + 1,
offset=page_offset,
profile_id=profile_id,
+ user_id=user.id,
+ is_admin=is_admin,
)
items = sessions[:page_limit]
return {
@@ -149,10 +164,12 @@
async def get_session(
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
session = await store.get(session_id)
if session is None:
raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user, permission="navi.sessions.read_all")
return {
"session_id": session.id,
"profile_id": session.profile_id,
@@ -170,7 +187,12 @@
session_id: str,
body: PinSessionRequest,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
+ session = await store.get(session_id)
+ if session is None:
+ raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user)
ok = await store.set_pinned(session_id, body.pinned)
if not ok:
raise HTTPException(status_code=404, detail="Session not found")
@@ -181,6 +203,7 @@
async def get_session_context(
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_admin)],
) -> dict:
"""Return the LLM context (what the model actually sees) for debugging."""
session = await store.get(session_id)
@@ -200,6 +223,7 @@
async def get_session_planning(
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_admin)],
) -> dict:
"""Return all planning phase debug logs for a session."""
session = await store.get(session_id)
@@ -212,11 +236,13 @@
async def get_session_content(
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
"""Return published inline content records for this session."""
session = await store.get(session_id)
if session is None:
raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user)
return {"session_id": session.id, "content": await list_for_session(session_id)}
@@ -225,10 +251,12 @@
session_id: str,
file: UploadFile,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
session = await store.get(session_id)
if session is None:
raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user)
name = safe_filename(file.filename or "upload")
if is_forbidden(name):
@@ -280,12 +308,14 @@
session_id: str,
filename: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
download: bool = False,
) -> FileResponse:
"""Download a file from the session's file directory."""
session = await store.get(session_id)
if session is None:
raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user, permission="navi.files.read_all")
# Resolve and verify the file is within the session directory (no path traversal)
base = session_dir(session_id).resolve()
@@ -317,10 +347,12 @@
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
backends: Annotated[BackendRegistry, Depends(get_backend_registry)],
+ user: Annotated[User, Depends(require_user)],
) -> dict:
session = await store.get(session_id)
if session is None:
raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user)
# Only generate if no name yet
if session.name:
@@ -346,7 +378,12 @@
async def delete_session(
session_id: str,
store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User, Depends(require_user)],
) -> None:
+ session = await store.get(session_id)
+ if session is None:
+ raise HTTPException(status_code=404, detail="Session not found")
+ check_session_access(session, user, permission="navi.sessions.delete_all")
deleted = await store.delete(session_id)
if not deleted:
raise HTTPException(status_code=404, detail="Session not found")
diff --git a/navi/api/routes/webhooks.py b/navi/api/routes/webhooks.py
new file mode 100644
index 0000000..65d06f0
--- /dev/null
+++ b/navi/api/routes/webhooks.py
@@ -0,0 +1,103 @@
+"""Webhook receiver for gnexus-auth events."""
+
+import structlog
+from fastapi import APIRouter, HTTPException, Request
+from gnexus_gauth.exceptions import WebhookPayloadException
+
+from navi.auth.client import get_gauth_client
+from navi.config import settings
+
+log = structlog.get_logger()
+router = APIRouter(prefix="/webhooks", tags=["webhooks"])
+
+
+@router.post("/gnexus-auth")
+async def gnexus_auth_webhook(request: Request) -> dict:
+ """Receive and handle webhooks from gnexus-auth.
+
+ Events handled:
+ - user.blocked / user.archived / user.deleted → invalidate user sessions
+ - auth.global_logout → invalidate all sessions
+ - session.revoked → invalidate matching session
+ - client.roles_changed / client.permissions_changed → update user role/permissions
+ """
+ raw_body = await request.body()
+ body_text = raw_body.decode("utf-8")
+
+ client = get_gauth_client()
+
+ # For now, log and acknowledge. Full HMAC verification can be added when webhook
+ # secret is configured in gnexus-auth admin panel.
+ try:
+ event = client.parse_webhook(body_text)
+ except WebhookPayloadException:
+ raise HTTPException(status_code=400, detail="Invalid JSON payload")
+
+ event_type = event.event_type
+ target = event.target_identifiers
+ log.info("webhook.received", event=event_type)
+
+ if event_type in ("user.blocked", "user.archived", "user.deleted"):
+ user_id = target.get("user_id")
+ if user_id:
+ await _invalidate_user_sessions(user_id)
+ log.info("webhook.user_invalidated", user_id=user_id, event=event_type)
+
+ elif event_type == "auth.global_logout":
+ await _invalidate_all_sessions()
+ log.info("webhook.all_sessions_invalidated")
+
+ elif event_type == "session.revoked":
+ # gnexus-auth session revoked — we don't have a direct mapping, so invalidate all
+ # for the user if user_id is present
+ user_id = target.get("user_id")
+ if user_id:
+ await _invalidate_user_sessions(user_id)
+ log.info("webhook.session_revoked", user_id=user_id)
+
+ elif event_type in ("client.roles_changed", "client.permissions_changed"):
+ # Update affected users' cached role/permissions
+ user_id = target.get("user_id")
+ if user_id:
+ await _update_user_permissions(user_id)
+ log.info("webhook.permissions_updated", user_id=user_id, event=event_type)
+
+ return {"ok": True}
+
+
+async def _invalidate_user_sessions(user_id: str) -> None:
+ try:
+ from navi.api.deps import get_session_store
+ store = get_session_store()
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute("DELETE FROM user_auth_sessions WHERE user_id = $1", user_id)
+ except Exception:
+ log.warning("webhook.invalidate_user_failed", user_id=user_id, exc_info=True)
+
+
+async def _invalidate_all_sessions() -> None:
+ try:
+ from navi.api.deps import get_session_store
+ store = get_session_store()
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute("DELETE FROM user_auth_sessions")
+ except Exception:
+ log.warning("webhook.invalidate_all_failed", exc_info=True)
+
+
+async def _update_user_permissions(user_id: str) -> None:
+ """Clear cached permissions so next request re-fetches from gnexus-auth."""
+ try:
+ from navi.api.deps import get_session_store
+ store = get_session_store()
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(
+ "UPDATE navi_users SET permissions = '[]', updated_at = $1 WHERE id = $2",
+ __import__("datetime").datetime.now(__import__("datetime").timezone.utc),
+ user_id,
+ )
+ except Exception:
+ log.warning("webhook.update_permissions_failed", user_id=user_id, exc_info=True)
diff --git a/navi/api/websocket.py b/navi/api/websocket.py
index f206338..b84da02 100644
--- a/navi/api/websocket.py
+++ b/navi/api/websocket.py
@@ -21,10 +21,14 @@
import json
import structlog
-from fastapi import APIRouter, WebSocket, WebSocketDisconnect
+from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
+from typing import Annotated
from navi.api.deps import get_session_store
-from navi.core import Agent
+from navi.auth.deps import get_current_user_ws
+from navi.auth import User
+from navi.auth.deps import check_session_access
+from navi.core import Agent, SessionStore
from navi.core.event_bus import get_event_bus
from navi.core.events import AgentEvent
from navi.exceptions import MaxIterationsReached, NaviError, SessionNotFound
@@ -167,8 +171,16 @@
# ── Endpoints ─────────────────────────────────────────────────────────────────
@router.post("/sessions/{session_id}/stop")
-async def stop_session(session_id: str) -> dict:
+async def stop_session(
+ session_id: str,
+ store: Annotated[SessionStore, Depends(get_session_store)],
+ user: Annotated[User | None, Depends(get_current_user_ws)] = None,
+) -> dict:
"""Signal the running agent for this session to stop cooperatively."""
+ if user is not None:
+ session = await store.get(session_id)
+ if session is not None:
+ check_session_access(session, user)
run = _runs.get(session_id)
if run is not None:
run.stop_event.set()
@@ -177,7 +189,11 @@
@router.websocket("/ws/sessions/{session_id}")
-async def websocket_session(session_id: str, websocket: WebSocket) -> None:
+async def websocket_session(
+ session_id: str,
+ websocket: WebSocket,
+ user: Annotated[User | None, Depends(get_current_user_ws)] = None,
+) -> None:
session_store = get_session_store()
session = await session_store.get(session_id)
@@ -185,6 +201,13 @@
await websocket.close(code=4004, reason="Session not found")
return
+ if user is not None:
+ try:
+ check_session_access(session, user)
+ except Exception:
+ await websocket.close(code=4003, reason="Access denied")
+ return
+
await websocket.accept()
log.info("ws.connected", session_id=session_id)
diff --git a/navi/auth/__init__.py b/navi/auth/__init__.py
new file mode 100644
index 0000000..adfc914
--- /dev/null
+++ b/navi/auth/__init__.py
@@ -0,0 +1,22 @@
+"""Auth models for Navi user identity."""
+
+from pydantic import BaseModel
+
+from ._ddl import _ensure_auth_tables
+
+
+class User(BaseModel):
+ """Authenticated Navi user, resolved from gnexus-auth."""
+
+ id: str
+ email: str
+ display_name: str | None = None
+ role: str = "user" # "user" | "admin"
+ permissions: list[str] = []
+
+ def has_permission(self, permission: str) -> bool:
+ """Check if user has a specific permission.
+
+ Admin role implies all permissions.
+ """
+ return self.role == "admin" or permission in self.permissions
diff --git a/navi/auth/_ddl.py b/navi/auth/_ddl.py
new file mode 100644
index 0000000..53f2ae9
--- /dev/null
+++ b/navi/auth/_ddl.py
@@ -0,0 +1,36 @@
+"""Auth DDL — table creation for navi_users and user_auth_sessions."""
+
+
+_DDL = """
+CREATE TABLE IF NOT EXISTS navi_users (
+ id TEXT PRIMARY KEY,
+ email TEXT NOT NULL,
+ display_name TEXT,
+ role TEXT NOT NULL DEFAULT 'user',
+ permissions TEXT NOT NULL DEFAULT '[]',
+ created_at TIMESTAMPTZ NOT NULL,
+ updated_at TIMESTAMPTZ NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS user_auth_sessions (
+ id TEXT PRIMARY KEY,
+ user_id TEXT NOT NULL REFERENCES navi_users(id) ON DELETE CASCADE,
+ access_token_enc TEXT NOT NULL,
+ refresh_token_enc TEXT NOT NULL,
+ expires_at TIMESTAMPTZ NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL,
+ last_used_at TIMESTAMPTZ NOT NULL
+);
+
+CREATE INDEX IF NOT EXISTS idx_user_auth_sessions_user_id ON user_auth_sessions (user_id);
+"""
+
+
+async def _ensure_auth_tables() -> None:
+ """Create auth tables if they don't exist."""
+ from navi.api.deps import get_session_store
+
+ store = get_session_store()
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(_DDL)
diff --git a/navi/auth/client.py b/navi/auth/client.py
new file mode 100644
index 0000000..2fdde56
--- /dev/null
+++ b/navi/auth/client.py
@@ -0,0 +1,38 @@
+"""GAuthClient singleton wired to navi config."""
+
+from gnexus_gauth.client import GAuthClient
+from gnexus_gauth.config import GAuthConfig
+from gnexus_gauth.oauth import HttpTokenEndpoint
+from gnexus_gauth.runtime import HttpRuntimeUserProvider
+from gnexus_gauth.support import InMemoryPkceStore, InMemoryStateStore
+from gnexus_gauth.webhook import HmacWebhookVerifier, JsonWebhookParser
+
+from navi.config import settings
+
+# Singleton instances, lazily created
+_gauth_client: GAuthClient | None = None
+_state_store: InMemoryStateStore | None = None
+_pkce_store: InMemoryPkceStore | None = None
+
+
+def get_gauth_client() -> GAuthClient:
+ global _gauth_client, _state_store, _pkce_store
+ if _gauth_client is None:
+ config = GAuthConfig(
+ base_url=settings.gnexus_auth_base_url,
+ client_id=settings.gnexus_auth_client_id,
+ client_secret=settings.gnexus_auth_client_secret,
+ redirect_uri=settings.gnexus_auth_redirect_uri,
+ )
+ _state_store = InMemoryStateStore()
+ _pkce_store = InMemoryPkceStore()
+ _gauth_client = GAuthClient(
+ config=config,
+ token_endpoint=HttpTokenEndpoint(config),
+ runtime_user_provider=HttpRuntimeUserProvider(config),
+ webhook_verifier=HmacWebhookVerifier(config),
+ webhook_parser=JsonWebhookParser(),
+ state_store=_state_store,
+ pkce_store=_pkce_store,
+ )
+ return _gauth_client
diff --git a/navi/auth/deps.py b/navi/auth/deps.py
new file mode 100644
index 0000000..742e38f
--- /dev/null
+++ b/navi/auth/deps.py
@@ -0,0 +1,229 @@
+"""FastAPI dependencies for auth resolution."""
+
+import asyncio
+from datetime import datetime, timezone
+from typing import Annotated
+
+import structlog
+from fastapi import Depends, HTTPException, Request
+
+from navi.config import settings
+
+from . import User
+from .client import get_gauth_client
+from .encrypt import get_encryptor
+
+log = structlog.get_logger()
+
+
+async def _resolve_user(conn) -> User | None:
+ """Shared logic to resolve user from a connection object (Request or WebSocket)."""
+ if conn is None:
+ return None
+
+ # Return cached user if already resolved this request
+ if hasattr(conn.state, "user") and conn.state.user is not None:
+ return conn.state.user
+
+ cookie_name = settings.navi_auth_cookie_name
+ session_id = conn.cookies.get(cookie_name)
+ if not session_id:
+ return None
+
+ # Look up the auth session in DB
+ try:
+ from navi.api.deps import get_session_store
+ except Exception:
+ # Avoid circular import during early bootstrap
+ return None
+
+ store = get_session_store()
+ row = await _get_auth_session(store, session_id)
+ if row is None:
+ return None
+
+ encryptor = get_encryptor()
+ access_token = encryptor.decrypt(row["access_token_enc"])
+ expires_at = row["expires_at"]
+
+ client = get_gauth_client()
+
+ # Refresh if expired
+ if datetime.now(timezone.utc) > expires_at:
+ try:
+ refresh_token = encryptor.decrypt(row["refresh_token_enc"])
+ token_set = await asyncio.to_thread(client.refresh_token, refresh_token)
+ access_token = token_set.access_token
+ # Update DB with new tokens
+ await _update_auth_session(
+ store,
+ session_id,
+ encryptor.encrypt(access_token),
+ encryptor.encrypt(token_set.refresh_token or refresh_token),
+ token_set.expires_at or datetime.now(timezone.utc),
+ )
+ log.info("auth.token_refreshed", user_id=row["user_id"])
+ except Exception:
+ log.warning("auth.refresh_failed", session_id=session_id[:8])
+ # Refresh failed — treat as unauthenticated
+ await _delete_auth_session(store, session_id)
+ return None
+
+ # Fetch user from gnexus-auth
+ try:
+ auth_user = await asyncio.to_thread(client.fetch_user, access_token)
+ except Exception:
+ log.warning("auth.fetch_user_failed", session_id=session_id[:8])
+ return None
+
+ # Determine role from client-level role_ids
+ role = "user"
+ permissions: list[str] = []
+ for access in auth_user.client_access_list:
+ if access.client_id == settings.gnexus_auth_client_id:
+ if settings.gnexus_auth_admin_role_slug in (access.role_ids or []):
+ role = "admin"
+ permissions = list(access.permission_ids or [])
+ break
+
+ # Upsert into navi_users
+ await _upsert_navi_user(store, auth_user.user_id, auth_user.email, auth_user.profile.get("display_name"), role, permissions)
+
+ user = User(
+ id=auth_user.user_id,
+ email=auth_user.email,
+ display_name=auth_user.profile.get("display_name") or auth_user.email,
+ role=role,
+ permissions=permissions,
+ )
+
+ # Update last_used_at
+ await _touch_auth_session(store, session_id)
+ conn.state.user = user
+ return user
+
+
+async def get_current_user(request: Request) -> User | None:
+ """Resolve the current user from the auth session cookie for REST requests."""
+ return await _resolve_user(request)
+
+
+async def get_current_user_ws(websocket) -> User | None:
+ """Resolve the current user from the auth session cookie for WebSocket connections."""
+ return await _resolve_user(websocket)
+
+
+# ── Helpers that talk to the session store ──────────────────────────────────
+
+async def _get_auth_session(store, session_id: str) -> dict | None:
+ """Fetch a row from user_auth_sessions."""
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ row = await conn.fetchrow(
+ "SELECT user_id, access_token_enc, refresh_token_enc, expires_at "
+ "FROM user_auth_sessions WHERE id = $1",
+ session_id,
+ )
+ if row is None:
+ return None
+ return {
+ "user_id": row["user_id"],
+ "access_token_enc": row["access_token_enc"],
+ "refresh_token_enc": row["refresh_token_enc"],
+ "expires_at": row["expires_at"],
+ }
+
+
+async def _update_auth_session(
+ store, session_id: str, access_token_enc: str, refresh_token_enc: str, expires_at: datetime
+) -> None:
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(
+ "UPDATE user_auth_sessions "
+ "SET access_token_enc = $1, refresh_token_enc = $2, expires_at = $3, last_used_at = $4 "
+ "WHERE id = $5",
+ access_token_enc, refresh_token_enc, expires_at, datetime.now(timezone.utc), session_id,
+ )
+
+
+async def _delete_auth_session(store, session_id: str) -> None:
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute("DELETE FROM user_auth_sessions WHERE id = $1", session_id)
+
+
+async def _touch_auth_session(store, session_id: str) -> None:
+ pool = await store._get_pool()
+ async with pool.acquire() as conn:
+ await conn.execute(
+ "UPDATE user_auth_sessions SET last_used_at = $1 WHERE id = $2",
+ datetime.now(timezone.utc), session_id,
+ )
+
+
+async def _upsert_navi_user(
+ store, user_id: str, email: str, display_name: str | None, role: str, permissions: list[str]
+) -> None:
+ pool = await store._get_pool()
+ import json
+ async with pool.acquire() as conn:
+ await conn.execute(
+ """INSERT INTO navi_users (id, email, display_name, role, permissions, created_at, updated_at)
+ VALUES ($1, $2, $3, $4, $5, $6, $6)
+ ON CONFLICT (id) DO UPDATE
+ SET email = EXCLUDED.email,
+ display_name = EXCLUDED.display_name,
+ role = EXCLUDED.role,
+ permissions = EXCLUDED.permissions,
+ updated_at = EXCLUDED.updated_at""",
+ user_id, email, display_name or email, role, json.dumps(permissions), datetime.now(timezone.utc),
+ )
+
+
+# ── FastAPI Depends helpers ─────────────────────────────────────────────────
+
+async def require_user(user: Annotated[User | None, Depends(get_current_user)]) -> User:
+ if user is None:
+ raise HTTPException(status_code=401, detail="Authentication required")
+ return user
+
+
+async def require_admin(user: Annotated[User | None, Depends(get_current_user)]) -> User:
+ if user is None:
+ raise HTTPException(status_code=401, detail="Authentication required")
+ if user.role != "admin":
+ raise HTTPException(status_code=403, detail="Admin access required")
+ return user
+
+
+def require_permission(permission: str):
+ async def _check(
+ user: Annotated[User | None, Depends(get_current_user)],
+ ) -> User:
+ if user is None:
+ raise HTTPException(status_code=401, detail="Authentication required")
+ if user.role != "admin" and permission not in user.permissions:
+ raise HTTPException(status_code=403, detail=f"Permission '{permission}' required")
+ return user
+ return _check
+
+
+def check_session_access(session, user: User, permission: str | None = None) -> None:
+ """Raise 403 if user does not own the session and lacks the required permission.
+
+ Legacy sessions (user_id=None) are accessible only to admins.
+ """
+ from fastapi import HTTPException
+
+ if session.user_id is None:
+ if user.role != "admin":
+ raise HTTPException(status_code=403, detail="Access denied")
+ return
+ if session.user_id == user.id:
+ return
+ if user.role == "admin":
+ return
+ if permission and user.has_permission(permission):
+ return
+ raise HTTPException(status_code=403, detail="Access denied")
diff --git a/navi/auth/encrypt.py b/navi/auth/encrypt.py
new file mode 100644
index 0000000..19f983b
--- /dev/null
+++ b/navi/auth/encrypt.py
@@ -0,0 +1,31 @@
+"""Fernet-based symmetric encryption for OAuth tokens stored in DB."""
+
+from cryptography.fernet import Fernet
+
+from navi.config import settings
+
+
+class TokenEncryptor:
+ """Encrypt/decrypt opaque tokens before writing to DB."""
+
+ def __init__(self, key: str) -> None:
+ if not key:
+ raise ValueError("NAVI_AUTH_ENCRYPTION_KEY is required for token encryption")
+ self._fernet = Fernet(key.encode())
+
+ def encrypt(self, plain: str) -> str:
+ return self._fernet.encrypt(plain.encode()).decode()
+
+ def decrypt(self, cipher: str) -> str:
+ return self._fernet.decrypt(cipher.encode()).decode()
+
+
+# Singleton instance, lazily created
+_encryptor: TokenEncryptor | None = None
+
+
+def get_encryptor() -> TokenEncryptor:
+ global _encryptor
+ if _encryptor is None:
+ _encryptor = TokenEncryptor(settings.navi_auth_encryption_key)
+ return _encryptor
diff --git a/navi/config.py b/navi/config.py
index 72f236e..c69bcc9 100644
--- a/navi/config.py
+++ b/navi/config.py
@@ -70,6 +70,21 @@
gmail_address: str = ""
gmail_app_password: str = ""
+ # gnexus-auth OAuth integration
+ gnexus_auth_base_url: str = "http://gnexus-auth.local"
+ gnexus_auth_client_id: str = ""
+ gnexus_auth_client_secret: str = ""
+ gnexus_auth_redirect_uri: str = "http://localhost:8000/auth/callback"
+ gnexus_auth_admin_role_slug: str = "navi_admin"
+ gnexus_auth_user_role_slug: str = "navi_user"
+
+ # Auth session cookie encryption (Fernet key, 32-byte base64)
+ navi_auth_encryption_key: str = ""
+ navi_auth_cookie_name: str = "navi_auth_session"
+ navi_auth_cookie_secure: bool = False
+ navi_auth_cookie_samesite: str = "lax"
+ navi_auth_cookie_max_age_days: int = 30
+
# LLM call timeouts
# complete() is non-streaming (planning, compression) — blocked until full response
llm_complete_timeout: int = 120
diff --git a/navi/core/agent.py b/navi/core/agent.py
index b995ab0..842880d 100644
--- a/navi/core/agent.py
+++ b/navi/core/agent.py
@@ -229,7 +229,7 @@
tool_schemas = [t.schema() for t in tools]
llm = self._get_backend(profile.llm_backend)
- mem = await self._ctx_builder._memory_msg()
+ mem = await self._ctx_builder._memory_msg(user_id=session.user_id)
# Expose session_id to tools (e.g. SSH connection pool) via ContextVar
from navi.tools.base import current_session_id as _sid_var
@@ -338,7 +338,7 @@
tool_schemas = [t.schema() for t in tools]
llm = self._get_backend(profile.llm_backend)
- mem = await self._ctx_builder._memory_msg()
+ mem = await self._ctx_builder._memory_msg(user_id=session.user_id)
# Build subagent system prompt — completely separate from the parent's system prompt.
# No persona, no orchestrator instructions, no profiles block.
@@ -598,7 +598,7 @@
tool_schemas = [t.schema() for t in tools]
llm = self._get_backend(profile.llm_backend)
- mem = await self._ctx_builder._memory_msg()
+ mem = await self._ctx_builder._memory_msg(user_id=session.user_id)
# Expose session_id and model to tools via ContextVar
from navi.tools.base import current_session_id as _sid_var, current_model as _model_var
diff --git a/navi/core/context_builder.py b/navi/core/context_builder.py
index 3fc0f40..88a9459 100644
--- a/navi/core/context_builder.py
+++ b/navi/core/context_builder.py
@@ -78,10 +78,10 @@
else:
self._system_prompt_cache.pop(profile_id, None)
- async def _memory_msg(self) -> "Message | None":
+ async def _memory_msg(self, user_id: str | None = None) -> "Message | None":
if self._memory is None:
return None
- summary = await self._memory.get_summary()
+ summary = await self._memory.get_summary(user_id=user_id)
if not summary:
return None
return Message(
diff --git a/navi/core/pg_session_store.py b/navi/core/pg_session_store.py
index 593db3e..8b89351 100644
--- a/navi/core/pg_session_store.py
+++ b/navi/core/pg_session_store.py
@@ -14,6 +14,7 @@
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL,
+ user_id TEXT REFERENCES navi_users(id) ON DELETE SET NULL,
messages TEXT NOT NULL DEFAULT '[]',
context TEXT NOT NULL DEFAULT '',
pinned BOOLEAN NOT NULL DEFAULT FALSE,
@@ -26,7 +27,8 @@
_MIGRATE = """
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS name TEXT;
-ALTER TABLE sessions ADD COLUMN IF NOT EXISTS planning_logs TEXT NOT NULL DEFAULT '[]'
+ALTER TABLE sessions ADD COLUMN IF NOT EXISTS planning_logs TEXT NOT NULL DEFAULT '[]';
+ALTER TABLE sessions ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES navi_users(id) ON DELETE SET NULL
"""
@@ -61,15 +63,15 @@
self._pool = pool
return self._pool
- async def create(self, profile_id: str) -> Session:
- session = Session(profile_id=profile_id)
+ async def create(self, profile_id: str, user_id: str | None = None) -> Session:
+ session = Session(profile_id=profile_id, user_id=user_id)
pool = await self._get_pool()
async with pool.acquire() as conn:
await conn.execute(
"INSERT INTO sessions "
- "(id, profile_id, messages, context, pinned, created_at, last_active, context_token_count) "
- "VALUES ($1, $2, '[]', '', FALSE, $3, $4, 0)",
- session.id, session.profile_id, session.created_at, session.last_active,
+ "(id, profile_id, user_id, messages, context, pinned, created_at, last_active, context_token_count) "
+ "VALUES ($1, $2, $3, '[]', '', FALSE, $4, $5, 0)",
+ session.id, session.profile_id, session.user_id, session.created_at, session.last_active,
)
return session
@@ -77,7 +79,7 @@
pool = await self._get_pool()
async with pool.acquire() as conn:
row = await conn.fetchrow(
- "SELECT id, profile_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
+ "SELECT id, profile_id, user_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
"FROM sessions WHERE id = $1",
session_id,
)
@@ -88,9 +90,9 @@
pool = await self._get_pool()
async with pool.acquire() as conn:
await conn.execute(
- "UPDATE sessions SET profile_id = $1, messages = $2, context = $3, "
- "last_active = $4, context_token_count = $5, planning_logs = $6 WHERE id = $7",
- session.profile_id, _serialize(session.messages), _serialize(session.context),
+ "UPDATE sessions SET profile_id = $1, user_id = $2, messages = $3, context = $4, "
+ "last_active = $5, context_token_count = $6, planning_logs = $7 WHERE id = $8",
+ session.profile_id, session.user_id, _serialize(session.messages), _serialize(session.context),
session.last_active, session.context_token_count,
json.dumps(session.planning_logs, ensure_ascii=False), session.id,
)
@@ -113,13 +115,20 @@
)
return result == "UPDATE 1"
- async def list_all(self) -> list[Session]:
+ async def list_all(self, user_id: str | None = None, is_admin: bool = False) -> list[Session]:
pool = await self._get_pool()
async with pool.acquire() as conn:
- rows = await conn.fetch(
- "SELECT id, profile_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
- "FROM sessions ORDER BY pinned DESC, last_active DESC"
- )
+ if not is_admin and user_id is not None:
+ rows = await conn.fetch(
+ "SELECT id, profile_id, user_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
+ "FROM sessions WHERE user_id = $1 OR user_id IS NULL ORDER BY pinned DESC, last_active DESC",
+ user_id,
+ )
+ else:
+ rows = await conn.fetch(
+ "SELECT id, profile_id, user_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
+ "FROM sessions ORDER BY pinned DESC, last_active DESC"
+ )
return [self._row_to_session(r) for r in rows]
async def list_page(
@@ -128,14 +137,32 @@
limit: int,
offset: int,
profile_id: str | None = None,
+ user_id: str | None = None,
+ is_admin: bool = False,
) -> list[Session]:
pool = await self._get_pool()
async with pool.acquire() as conn:
- where = "WHERE profile_id = $3" if profile_id else ""
- params = (limit, offset, profile_id) if profile_id else (limit, offset)
+ conditions = []
+ params: list = []
+ param_idx = 0
+
+ def add_param(value):
+ nonlocal param_idx
+ param_idx += 1
+ params.append(value)
+ return f"${param_idx}"
+
+ if not is_admin and user_id is not None:
+ conditions.append(f"(user_id = {add_param(user_id)} OR user_id IS NULL)")
+ if profile_id:
+ conditions.append(f"profile_id = {add_param(profile_id)}")
+
+ where = "WHERE " + " AND ".join(conditions) if conditions else ""
+ order_limit = f"ORDER BY pinned DESC, last_active DESC LIMIT {add_param(limit)} OFFSET {add_param(offset)}"
+
rows = await conn.fetch(
- "SELECT id, profile_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
- f"FROM sessions {where} ORDER BY pinned DESC, last_active DESC LIMIT $1 OFFSET $2",
+ "SELECT id, profile_id, user_id, messages, context, pinned, created_at, last_active, context_token_count, name, planning_logs "
+ f"FROM sessions {where} {order_limit}",
*params,
)
return [self._row_to_session(r) for r in rows]
@@ -155,6 +182,7 @@
return Session(
id=row["id"],
profile_id=row["profile_id"],
+ user_id=row["user_id"],
messages=messages,
context=context,
pinned=bool(row["pinned"]),
diff --git a/navi/core/session.py b/navi/core/session.py
index 18ddabd..686f256 100644
--- a/navi/core/session.py
+++ b/navi/core/session.py
@@ -12,6 +12,7 @@
class Session(BaseModel):
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
profile_id: str
+ user_id: str | None = None # owner; null for legacy single-user sessions
messages: list[Message] = Field(default_factory=list) # full display history (never compressed)
context: list[Message] = Field(default_factory=list) # LLM context (may be compressed)
context_token_count: int = 0 # accumulated total; reset to 0 after compression
@@ -24,7 +25,7 @@
class SessionStore(ABC):
@abstractmethod
- async def create(self, profile_id: str) -> Session: ...
+ async def create(self, profile_id: str, user_id: str | None = None) -> Session: ...
@abstractmethod
async def get(self, session_id: str) -> Session | None: ...
@@ -33,7 +34,7 @@
async def save(self, session: Session) -> None: ...
@abstractmethod
- async def list_all(self) -> list[Session]: ...
+ async def list_all(self, user_id: str | None = None, is_admin: bool = False) -> list[Session]: ...
@abstractmethod
async def list_page(
@@ -42,6 +43,8 @@
limit: int,
offset: int,
profile_id: str | None = None,
+ user_id: str | None = None,
+ is_admin: bool = False,
) -> list[Session]: ...
@abstractmethod
@@ -58,8 +61,8 @@
def __init__(self) -> None:
self._sessions: dict[str, Session] = {}
- async def create(self, profile_id: str) -> Session:
- session = Session(profile_id=profile_id)
+ async def create(self, profile_id: str, user_id: str | None = None) -> Session:
+ session = Session(profile_id=profile_id, user_id=user_id)
self._sessions[session.id] = session
return session
@@ -70,9 +73,12 @@
session.last_active = datetime.now(timezone.utc)
self._sessions[session.id] = session
- async def list_all(self) -> list[Session]:
+ async def list_all(self, user_id: str | None = None, is_admin: bool = False) -> list[Session]:
+ sessions = self._sessions.values()
+ if not is_admin and user_id is not None:
+ sessions = [s for s in sessions if s.user_id == user_id]
return sorted(
- self._sessions.values(),
+ sessions,
key=lambda s: (s.pinned, s.last_active),
reverse=True,
)
@@ -83,8 +89,10 @@
limit: int,
offset: int,
profile_id: str | None = None,
+ user_id: str | None = None,
+ is_admin: bool = False,
) -> list[Session]:
- sessions = await self.list_all()
+ sessions = await self.list_all(user_id=user_id, is_admin=is_admin)
if profile_id:
sessions = [s for s in sessions if s.profile_id == profile_id]
return sessions[offset:offset + limit]
diff --git a/navi/main.py b/navi/main.py
index 8921aa7..a7c6007 100644
--- a/navi/main.py
+++ b/navi/main.py
@@ -11,7 +11,8 @@
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
-from navi.api.routes import agents, health, messages, sessions
+from navi.api.routes import agents, auth, health, messages, sessions, webhooks
+from navi.api.routes.admin import router as admin_router
from navi.api.websocket import router as ws_router
from navi.config import settings
from debug.eval.api import router as eval_router
@@ -31,7 +32,7 @@
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
- allow_credentials=False,
+ allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@@ -40,10 +41,13 @@
_cleanup_task = None
app.include_router(health.router)
+app.include_router(auth.router)
app.include_router(agents.router)
app.include_router(sessions.router)
app.include_router(messages.router)
app.include_router(ws_router)
+app.include_router(webhooks.router)
+app.include_router(admin_router)
app.include_router(eval_router)
_base = Path(__file__).parent.parent
@@ -58,10 +62,12 @@
from navi.api.deps import get_registries, get_session_store
from navi.content_store import ensure_tables
from navi.session_files import cleanup_loop
- # Ensure content store tables exist (retry for race with Docker compose)
+ from navi.auth import _ensure_auth_tables
+ # Ensure content store and auth tables exist (retry for race with Docker compose)
for attempt in range(1, 6):
try:
await ensure_tables()
+ await _ensure_auth_tables()
break
except Exception as e:
log = structlog.get_logger()
diff --git a/navi/memory/_ddl.py b/navi/memory/_ddl.py
index 65b3461..c59a1ce 100644
--- a/navi/memory/_ddl.py
+++ b/navi/memory/_ddl.py
@@ -11,8 +11,15 @@
if pgvector_available else ""
)
stmts = [
+ # Migration: add user_id to existing tables (nullable for legacy)
+ "ALTER TABLE memory_facts ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES navi_users(id) ON DELETE CASCADE",
+ "ALTER TABLE memory_summary ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES navi_users(id) ON DELETE CASCADE",
+ # Migrate unique constraint from (category, key) to (user_id, category, key)
+ "DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'memory_facts_category_key_key') THEN ALTER TABLE memory_facts DROP CONSTRAINT memory_facts_category_key_key; END IF; END $$;",
+ "ALTER TABLE memory_facts ADD CONSTRAINT IF NOT EXISTS memory_facts_user_cat_key UNIQUE (user_id, category, key)",
"""CREATE TABLE IF NOT EXISTS memory_facts (
id TEXT PRIMARY KEY,
+ user_id TEXT REFERENCES navi_users(id) ON DELETE CASCADE,
category TEXT NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL,
@@ -25,7 +32,7 @@
expires_at TIMESTAMPTZ,
last_verified_at TIMESTAMPTZ,
source_context TEXT,
- UNIQUE(category, key)
+ UNIQUE(user_id, category, key)
)""" % embedding_col,
"CREATE INDEX IF NOT EXISTS idx_memory_facts_expires ON memory_facts (expires_at) WHERE expires_at IS NOT NULL",
"CREATE INDEX IF NOT EXISTS idx_memory_facts_source_cat ON memory_facts (source, category)",
@@ -41,8 +48,10 @@
END $$;""",
"""CREATE TABLE IF NOT EXISTS memory_summary (
id INTEGER PRIMARY KEY DEFAULT 1,
+ user_id TEXT REFERENCES navi_users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
- generated_at TIMESTAMPTZ NOT NULL
+ generated_at TIMESTAMPTZ NOT NULL,
+ UNIQUE(id, user_id)
)""",
"""CREATE TABLE IF NOT EXISTS session_memory_state (
session_id TEXT PRIMARY KEY,
diff --git a/navi/memory/_facts.py b/navi/memory/_facts.py
index 28aa69d..2677782 100644
--- a/navi/memory/_facts.py
+++ b/navi/memory/_facts.py
@@ -39,6 +39,7 @@
category: str,
key: str,
value: str,
+ user_id: str | None = None,
source_session_id: str | None = None,
source: str = "conversation",
confidence: int = 70,
@@ -53,10 +54,10 @@
if vec_str:
await conn.execute(
"""INSERT INTO memory_facts
- (id, category, key, value, created_at, updated_at, source_session_id,
+ (id, user_id, category, key, value, created_at, updated_at, source_session_id,
embedding, source, confidence, expires_at, source_context)
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8::vector, $9, $10, $11, $12)
- ON CONFLICT(category, key) DO UPDATE SET
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::vector, $10, $11, $12, $13)
+ ON CONFLICT(user_id, category, key) DO UPDATE SET
value = EXCLUDED.value,
updated_at = EXCLUDED.updated_at,
source_session_id = EXCLUDED.source_session_id,
@@ -65,16 +66,16 @@
confidence = EXCLUDED.confidence,
expires_at = EXCLUDED.expires_at,
source_context = EXCLUDED.source_context""",
- str(uuid.uuid4()), category, key, value, now, now,
+ str(uuid.uuid4()), user_id, category, key, value, now, now,
source_session_id, vec_str, source, confidence, expires_at, source_context,
)
else:
await conn.execute(
"""INSERT INTO memory_facts
- (id, category, key, value, created_at, updated_at, source_session_id,
+ (id, user_id, category, key, value, created_at, updated_at, source_session_id,
source, confidence, expires_at, source_context)
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
- ON CONFLICT(category, key) DO UPDATE SET
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
+ ON CONFLICT(user_id, category, key) DO UPDATE SET
value = EXCLUDED.value,
updated_at = EXCLUDED.updated_at,
source_session_id = EXCLUDED.source_session_id,
@@ -82,11 +83,14 @@
confidence = EXCLUDED.confidence,
expires_at = EXCLUDED.expires_at,
source_context = EXCLUDED.source_context""",
- str(uuid.uuid4()), category, key, value, now, now,
+ str(uuid.uuid4()), user_id, category, key, value, now, now,
source_session_id, source, confidence, expires_at, source_context,
)
- async def search_facts(self, query: str, limit: int = 15) -> list[dict]:
+ async def search_facts(self, query: str, user_id: str | None = None, limit: int = 15) -> list[dict]:
+ user_clause = "AND user_id IS NULL" if user_id is None else "AND user_id = $3"
+ user_param = () if user_id is None else (user_id,)
+
# 1. Try vector search if pgvector + embedding backend are available
if self._embedding_backend and await self._has_pgvector():
query_embedding = await self._generate_embedding(query)
@@ -101,9 +105,10 @@
embedding <=> $1::vector AS distance
FROM memory_facts
WHERE (expires_at IS NULL OR expires_at > now())
+ AND (user_id IS NOT DISTINCT FROM $3)
ORDER BY embedding <=> $1::vector
LIMIT $2""",
- vec_str, limit,
+ vec_str, limit, *user_param,
)
results = [
_row_to_dict(r)
@@ -124,10 +129,10 @@
# 2. Text fallback (original ILIKE logic)
terms = _normalize_query(query)
if not terms:
- return await self.get_all_facts(limit=limit)
+ return await self.get_all_facts(user_id=user_id, limit=limit)
- if await self.fact_count() <= _AUTO_DUMP_THRESHOLD:
- return await self.get_all_facts(limit=limit)
+ if await self.fact_count(user_id=user_id) <= _AUTO_DUMP_THRESHOLD:
+ return await self.get_all_facts(user_id=user_id, limit=limit)
base_params: list = []
term_conds: list[str] = []
@@ -139,6 +144,10 @@
)
base_params.extend([like, like, like])
+ user_filter = "user_id IS NULL" if user_id is None else f"user_id = ${len(base_params) + 1}"
+ if user_id is not None:
+ base_params.append(user_id)
+
limit_idx = len(base_params) + 1
and_where = " AND ".join(term_conds)
or_where = " OR ".join(term_conds)
@@ -148,7 +157,7 @@
rows = await conn.fetch(
f"SELECT id, category, key, value, updated_at, source, confidence, "
f"expires_at, source_context FROM memory_facts "
- f"WHERE {and_where} ORDER BY updated_at DESC LIMIT ${limit_idx}",
+ f"WHERE {user_filter} AND {and_where} ORDER BY updated_at DESC LIMIT ${limit_idx}",
*base_params, limit,
)
if rows:
@@ -160,32 +169,49 @@
rows = await conn.fetch(
f"SELECT id, category, key, value, updated_at, source, confidence, "
f"expires_at, source_context, ({score_expr}) AS score "
- f"FROM memory_facts WHERE {or_where} "
+ f"FROM memory_facts WHERE {user_filter} AND ({or_where}) "
f"ORDER BY score DESC, updated_at DESC LIMIT ${limit_idx}",
*base_params, limit,
)
return [_row_to_dict(r) for r in rows]
- async def delete_fact(self, key: str, category: str | None = None) -> int:
+ async def delete_fact(self, key: str, category: str | None = None, user_id: str | None = None) -> int:
pool = await self._get_pool()
async with pool.acquire() as conn:
if category:
- result = await conn.execute(
- "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1) AND LOWER(category)=LOWER($2)",
- key, category,
- )
+ if user_id is None:
+ result = await conn.execute(
+ "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1) AND LOWER(category)=LOWER($2) AND user_id IS NULL",
+ key, category,
+ )
+ else:
+ result = await conn.execute(
+ "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1) AND LOWER(category)=LOWER($2) AND user_id = $3",
+ key, category, user_id,
+ )
else:
- result = await conn.execute(
- "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1)", key
- )
+ if user_id is None:
+ result = await conn.execute(
+ "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1) AND user_id IS NULL", key
+ )
+ else:
+ result = await conn.execute(
+ "DELETE FROM memory_facts WHERE LOWER(key)=LOWER($1) AND user_id = $2", key, user_id
+ )
return int(result.split()[1])
- async def get_all_facts(self, limit: int | None = None) -> list[dict]:
+ async def get_all_facts(self, user_id: str | None = None, limit: int | None = None) -> list[dict]:
q = (
"SELECT id, category, key, value, updated_at, source, confidence, "
- "expires_at, source_context FROM memory_facts ORDER BY category, updated_at DESC"
+ "expires_at, source_context FROM memory_facts "
)
params: list = []
+ if user_id is None:
+ q += "WHERE user_id IS NULL "
+ else:
+ q += "WHERE user_id = $1 "
+ params.append(user_id)
+ q += "ORDER BY category, updated_at DESC"
if limit:
q += f" LIMIT ${len(params) + 1}"
params.append(limit)
@@ -194,10 +220,12 @@
rows = await conn.fetch(q, *params)
return [_row_to_dict(r) for r in rows]
- async def fact_count(self) -> int:
+ async def fact_count(self, user_id: str | None = None) -> int:
pool = await self._get_pool()
async with pool.acquire() as conn:
- return await conn.fetchval("SELECT COUNT(*) FROM memory_facts") or 0
+ if user_id is None:
+ return await conn.fetchval("SELECT COUNT(*) FROM memory_facts WHERE user_id IS NULL") or 0
+ return await conn.fetchval("SELECT COUNT(*) FROM memory_facts WHERE user_id = $1", user_id) or 0
def _row_to_dict(row: asyncpg.Record) -> dict:
diff --git a/navi/memory/_summary.py b/navi/memory/_summary.py
index c7b80a7..d6baec4 100644
--- a/navi/memory/_summary.py
+++ b/navi/memory/_summary.py
@@ -10,19 +10,21 @@
_get_pool() -> asyncpg.Pool
"""
- async def get_summary(self) -> str | None:
+ async def get_summary(self, user_id: str | None = None) -> str | None:
pool = await self._get_pool()
async with pool.acquire() as conn:
- return await conn.fetchval("SELECT content FROM memory_summary WHERE id=1")
+ if user_id is None:
+ return await conn.fetchval("SELECT content FROM memory_summary WHERE id=1 AND user_id IS NULL")
+ return await conn.fetchval("SELECT content FROM memory_summary WHERE id=1 AND user_id = $1", user_id)
- async def set_summary(self, content: str) -> None:
+ async def set_summary(self, content: str, user_id: str | None = None) -> None:
now = datetime.now(timezone.utc)
pool = await self._get_pool()
async with pool.acquire() as conn:
await conn.execute(
- """INSERT INTO memory_summary (id, content, generated_at) VALUES (1, $1, $2)
- ON CONFLICT(id) DO UPDATE SET
+ """INSERT INTO memory_summary (id, user_id, content, generated_at) VALUES (1, $1, $2, $3)
+ ON CONFLICT(id, user_id) DO UPDATE SET
content = EXCLUDED.content,
generated_at = EXCLUDED.generated_at""",
- content, now,
+ user_id, content, now,
)
diff --git a/navi/memory/extractor.py b/navi/memory/extractor.py
index 5069941..bebcb80 100644
--- a/navi/memory/extractor.py
+++ b/navi/memory/extractor.py
@@ -82,7 +82,7 @@
await memory_store.mark_session_extracted(session.id)
if facts_added > 0:
- await _regenerate_summary(llm, model, memory_store)
+ await _regenerate_summary(llm, model, memory_store, user_id=session.user_id)
_MAX_TOOL_RESULT_LEN = 500
@@ -90,6 +90,7 @@
async def _extract_facts(session, llm: LLMBackend, model: str, store: MemoryStore) -> int:
+ user_id = getattr(session, "user_id", None)
lines: list[str] = []
# Map tool_call_id -> tool_name so we can label tool results
@@ -175,6 +176,7 @@
category=category,
key=key,
value=value,
+ user_id=user_id,
source_session_id=session.id,
source=source,
confidence=confidence,
@@ -185,8 +187,8 @@
return count
-async def _regenerate_summary(llm: LLMBackend, model: str, store: MemoryStore) -> None:
- facts = await store.get_all_facts()
+async def _regenerate_summary(llm: LLMBackend, model: str, store: MemoryStore, user_id: str | None = None) -> None:
+ facts = await store.get_all_facts(user_id=user_id)
if not facts:
return
@@ -214,5 +216,5 @@
return
if summary:
- await store.set_summary(summary)
- log.info("memory.summary_updated", fact_count=len(facts))
+ await store.set_summary(summary, user_id=user_id)
+ log.info("memory.summary_updated", fact_count=len(facts), user_id=user_id)
diff --git a/navi/profiles/base.py b/navi/profiles/base.py
index b85528f..c6132b9 100644
--- a/navi/profiles/base.py
+++ b/navi/profiles/base.py
@@ -35,6 +35,9 @@
short_description: str = ""
full_description: dict = Field(default_factory=dict)
+ # Admin-only profiles are hidden from non-admin users in the profile list.
+ is_admin_only: bool = False
+
# ── Thinking mechanics ────────────────────────────────────────────────────
# Each flag can be set per-profile in config.json to tune the balance
# between reasoning depth and response latency.
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index 96423e2..03cf7b9 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -5,6 +5,7 @@
import pytest
from fastapi.testclient import TestClient
+from navi.auth import User
from navi.core.events import StreamEnd, TextDelta
from navi.core.registry import BackendRegistry
from navi.core.session import InMemorySessionStore, Session
@@ -58,6 +59,21 @@
monkeypatch.setattr(deps, "_registries", (tools, profiles, backends, None))
monkeypatch.setattr(deps, "_workers", [])
+ # Patch auth dependencies so tests don't need real OAuth.
+ # Use FastAPI's built-in dependency_overrides mechanism so the replacement
+ # is respected even though Depends() captured the original callable at import time.
+ fake_user = User(id="test-user", email="test@example.com", display_name="Test", role="admin", permissions=[])
+
+ from navi.main import app
+ from navi.api.deps import get_current_user, require_admin, require_permission, require_user
+ from navi.auth.deps import get_current_user_ws
+
+ app.dependency_overrides[get_current_user] = lambda: fake_user
+ app.dependency_overrides[get_current_user_ws] = lambda: fake_user
+ app.dependency_overrides[require_user] = lambda: fake_user
+ app.dependency_overrides[require_admin] = lambda: fake_user
+ app.dependency_overrides[require_permission] = lambda p: fake_user
+
# Patch get_agent in routes that import it directly (messages.py)
fake_agent = FakeAgent()
monkeypatch.setattr("navi.api.routes.messages.get_agent", lambda: fake_agent)
diff --git a/tests/unit/api/test_session_files.py b/tests/unit/api/test_session_files.py
index 2ede8ed..698beae 100644
--- a/tests/unit/api/test_session_files.py
+++ b/tests/unit/api/test_session_files.py
@@ -5,6 +5,7 @@
import navi.api.routes.sessions as sessions_mod
import navi.session_files as session_files_mod
+from navi.auth import User
from navi.core.session import InMemorySessionStore
@@ -52,11 +53,14 @@
return FakeUploadFile(name, data, content_type)
+_FAKE_USER = User(id="test-user", email="test@example.com", display_name="Test", role="admin", permissions=[])
+
+
async def test_upload_duplicate_filename_gets_numbered_name(store):
session_id = await _session_id(store)
- first = await sessions_mod.upload_file(session_id, _upload("report.txt", b"one"), store)
- second = await sessions_mod.upload_file(session_id, _upload("report.txt", b"two"), store)
+ first = await sessions_mod.upload_file(session_id, _upload("report.txt", b"one"), store, _FAKE_USER)
+ second = await sessions_mod.upload_file(session_id, _upload("report.txt", b"two"), store, _FAKE_USER)
assert first["name"] == "report.txt"
assert second["name"] == "report_1.txt"
@@ -66,7 +70,7 @@
session_id = await _session_id(store)
with pytest.raises(HTTPException) as exc:
- await sessions_mod.upload_file(session_id, _upload("run.sh", b"echo nope"), store)
+ await sessions_mod.upload_file(session_id, _upload("run.sh", b"echo nope"), store, _FAKE_USER)
assert exc.value.status_code == 400
assert "Executable files" in exc.value.detail
@@ -76,7 +80,7 @@
session_id = await _session_id(store)
with pytest.raises(HTTPException) as exc:
- await sessions_mod.download_file(session_id, "../secret.txt", store)
+ await sessions_mod.download_file(session_id, "../secret.txt", store, _FAKE_USER)
assert exc.value.status_code == 403
@@ -86,7 +90,7 @@
dest = session_files_mod.ensure_session_dir(session_id) / "page.html"
dest.write_text("
Hello
")
- response = await sessions_mod.download_file(session_id, "page.html", store)
+ response = await sessions_mod.download_file(session_id, "page.html", store, _FAKE_USER)
assert response.media_type == "text/html"
assert "inline" in response.headers["content-disposition"]
@@ -97,7 +101,7 @@
dest = session_files_mod.ensure_session_dir(session_id) / "page.html"
dest.write_text("Hello
")
- response = await sessions_mod.download_file(session_id, "page.html", store, download=True)
+ response = await sessions_mod.download_file(session_id, "page.html", store, _FAKE_USER, download=True)
assert response.media_type == "text/html"
assert "attachment" in response.headers["content-disposition"]
@@ -108,7 +112,7 @@
dest = session_files_mod.ensure_session_dir(session_id) / "bundle.zip"
dest.write_bytes(b"zip")
- response = await sessions_mod.download_file(session_id, "bundle.zip", store)
+ response = await sessions_mod.download_file(session_id, "bundle.zip", store, _FAKE_USER)
assert response.media_type == "application/zip"
assert "attachment" in response.headers["content-disposition"]
@@ -123,6 +127,6 @@
monkeypatch.setattr(sessions_mod, "list_for_session", fake_list_for_session)
- result = await sessions_mod.get_session_content(session_id, store)
+ result = await sessions_mod.get_session_content(session_id, store, _FAKE_USER)
assert result == {"session_id": session_id, "content": [{"filename": "logo.svg"}]}
diff --git a/tests/unit/memory/test_extractor.py b/tests/unit/memory/test_extractor.py
index f88b833..78caa73 100644
--- a/tests/unit/memory/test_extractor.py
+++ b/tests/unit/memory/test_extractor.py
@@ -8,9 +8,10 @@
class FakeSession:
- def __init__(self, messages, session_id="sess-1"):
+ def __init__(self, messages, session_id="sess-1", user_id=None):
self.id = session_id
self.messages = messages
+ self.user_id = user_id
class TestExtractFacts:
diff --git a/tests/unit/test_startup.py b/tests/unit/test_startup.py
index a1cd04f..88ddaf8 100644
--- a/tests/unit/test_startup.py
+++ b/tests/unit/test_startup.py
@@ -35,6 +35,11 @@
monkeypatch.setattr(session_files, "cleanup_loop", fake_cleanup_loop)
monkeypatch.setattr(deps, "get_session_store", lambda: object())
monkeypatch.setattr(main_mod.asyncio, "create_task", fake_create_task)
+ # Auth tables creation should not break startup test
+ import navi.auth as auth_mod
+ async def fake_ensure_auth_tables():
+ pass
+ monkeypatch.setattr(auth_mod, "_ensure_auth_tables", fake_ensure_auth_tables)
await main_mod._on_startup()
diff --git a/webclient/dist/assets/index-BAFK9TX3.css b/webclient/dist/assets/index-BAFK9TX3.css
new file mode 100644
index 0000000..9836255
--- /dev/null
+++ b/webclient/dist/assets/index-BAFK9TX3.css
@@ -0,0 +1 @@
+@charset "UTF-8";.vue-recycle-scroller__resize-observer[data-v-08cc04ab]{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;pointer-events:none;z-index:-1}.vue-recycle-scroller{position:relative}.vue-recycle-scroller.direction-vertical:not(.page-mode){overflow-y:auto}.vue-recycle-scroller.direction-horizontal:not(.page-mode){overflow-x:auto}.vue-recycle-scroller.grid-mode:not(.page-mode){overflow:auto}.vue-recycle-scroller.direction-horizontal{display:flex}.vue-recycle-scroller__slot{flex:auto 0 0}.vue-recycle-scroller__item-wrapper{flex:1;box-sizing:border-box;overflow:hidden;position:relative}.vue-recycle-scroller.ready .vue-recycle-scroller__item-view{position:absolute;top:0;left:0;will-change:transform}.vue-recycle-scroller.direction-vertical .vue-recycle-scroller__item-wrapper{width:100%}.vue-recycle-scroller.direction-horizontal .vue-recycle-scroller__item-wrapper{height:100%}.vue-recycle-scroller.ready.direction-vertical .vue-recycle-scroller__item-view{width:100%}.vue-recycle-scroller.ready.direction-horizontal .vue-recycle-scroller__item-view{height:100%}.session-list-wrap[data-v-01e3820b]{flex:1;overflow:hidden;display:flex;flex-direction:column}.session-scroller[data-v-01e3820b]{flex:1;overflow-y:auto}.empty-sessions[data-v-01e3820b]{display:flex;flex-direction:column;align-items:center;gap:8px;padding:32px 16px;color:var(--color-text-dark, #787c99);font-size:13px}.empty-sessions i[data-v-01e3820b]{font-size:32px;opacity:.4}.empty-sessions p[data-v-01e3820b]{margin:0}.sessions-loading[data-v-01e3820b]{display:flex;align-items:center;justify-content:center;gap:10px;padding:28px 16px;color:var(--color-text-dark, #787c99);font-size:12px}.sessions-loading-more[data-v-01e3820b]{padding:10px 16px 14px}.sessions-spinner[data-v-01e3820b]{width:16px;height:16px;border:2px solid var(--color-border, #3b4261);border-top-color:var(--color-accent, #7aa2f7);border-radius:50%;animation:sessions-spin-01e3820b .8s linear infinite}@keyframes sessions-spin-01e3820b{to{transform:rotate(360deg)}}.sidebar-close-btn[data-v-954feac6]{display:none}@media(max-width:1280px){.sidebar-close-btn[data-v-954feac6]{display:flex;margin-left:auto}}.sidebar-footer[data-v-954feac6]{padding:12px 16px;border-top:1px solid var(--color-border);display:flex;align-items:center;justify-content:space-between;gap:8px}.user-name[data-v-954feac6]{font-size:13px;color:var(--color-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.context-bar-pct[data-v-fe8d0787]{font-size:11px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--color-success);white-space:nowrap}.context-bar-pct.is-warn[data-v-fe8d0787]{color:var(--color-warning)}.context-bar-pct.is-crit[data-v-fe8d0787]{color:var(--color-error)}.btn-artifacts-toggle[data-v-ed66e8ab]{position:relative}.artifact-count[data-v-ed66e8ab]{position:absolute;top:-3px;right:-3px;min-width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;padding:0 4px;font-size:10px;line-height:1;background:var(--accent, #4ec9b0);color:#11111b}.content-card[data-v-929d4ed2]{margin:8px 0;background:var(--surface, #1e1e2e);border:1px solid var(--border, #2a2a3e);overflow:hidden}.content-card summary[data-v-929d4ed2]{display:flex;align-items:center;gap:8px;padding:10px 14px;cursor:pointer;-webkit-user-select:none;user-select:none;list-style:none}.content-card summary[data-v-929d4ed2]::-webkit-details-marker{display:none}.content-icon[data-v-929d4ed2]{font-size:1.2em;line-height:1}.content-title[data-v-929d4ed2]{flex:1;font-size:.9em;font-weight:500;color:var(--text, #cdd6f4);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.content-badge[data-v-929d4ed2]{font-size:.7em;text-transform:uppercase;padding:2px 8px;background:var(--accent-muted, #313244);color:var(--accent, #4ec9b0)}.content-actions[data-v-929d4ed2]{display:inline-flex;align-items:center;gap:4px}.content-actions a[data-v-929d4ed2],.content-actions button[data-v-929d4ed2]{width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--border, #2a2a3e);background:var(--surface-elevated, #242438);color:var(--text, #cdd6f4);text-decoration:none;cursor:pointer}.content-actions a[data-v-929d4ed2]:hover,.content-actions button[data-v-929d4ed2]:hover{color:var(--accent, #4ec9b0);border-color:var(--accent, #4ec9b0)}.content-chevron[data-v-929d4ed2]{transition:transform .2s;color:var(--text-muted, #6c7086)}.content-card[open] .content-chevron[data-v-929d4ed2]{transform:rotate(180deg)}.content-body[data-v-929d4ed2]{border-top:1px solid var(--border, #2a2a3e);overflow:auto}.content-iframe[data-v-929d4ed2]{width:100%;height:300px;border:none;display:block}@media(min-width:768px){.content-iframe[data-v-929d4ed2]{height:500px}}.content-image[data-v-929d4ed2]{width:100%;max-height:60vh;object-fit:contain;cursor:zoom-in;display:block;background:var(--surface, #1e1e2e)}.content-video[data-v-929d4ed2]{width:100%;max-height:60vh;display:block;background:var(--surface, #1e1e2e)}.content-source[data-v-929d4ed2]{max-height:500px;overflow:auto;background:#11111b}.content-source-code[data-v-929d4ed2],.content-source-error[data-v-929d4ed2]{margin:0;padding:14px;white-space:pre;font-family:IBM Plex Mono,monospace;font-size:12px;line-height:1.6;color:var(--text, #cdd6f4)}.content-source-error[data-v-929d4ed2]{color:var(--error, #f7768e)}.content-source-state[data-v-929d4ed2]{display:flex;align-items:center;gap:8px;padding:14px;color:var(--text-muted, #6c7086);font-size:12px}.content-unknown[data-v-929d4ed2]{padding:24px;text-align:center;color:var(--text-muted, #6c7086);display:flex;flex-direction:column;align-items:center;gap:10px}.unknown-icon[data-v-929d4ed2]{font-size:2em;line-height:1}.unknown-name[data-v-929d4ed2]{font-size:.95em;font-weight:500;color:var(--text, #cdd6f4);word-break:break-word;max-width:100%}.unknown-open[data-v-929d4ed2]{display:inline-block;margin-top:4px;padding:6px 14px;border-radius:0;background:var(--accent-muted, #313244);color:var(--accent, #4ec9b0);text-decoration:none;font-size:.85em;font-weight:500;transition:background .15s}.unknown-open[data-v-929d4ed2]:hover{background:var(--border, #2a2a3e)}.content-card.is-stl .content-badge[data-v-929d4ed2]{color:#f5c2e7}.content-card.is-html .content-badge[data-v-929d4ed2]{color:#89b4fa}.content-card.is-svg .content-badge[data-v-929d4ed2]{color:#a6e3a1}.content-card.is-pdf .content-badge[data-v-929d4ed2]{color:#fab387}.content-card.is-image .content-badge[data-v-929d4ed2]{color:#89dceb}.content-card.is-video .content-badge[data-v-929d4ed2]{color:#f38ba8}.stream-cursor[data-v-1fd4166a]{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:2px;vertical-align:text-bottom;animation:blink-1fd4166a 1s step-end infinite}@keyframes blink-1fd4166a{0%,to{opacity:1}50%{opacity:0}}.msg-rate-btn[data-v-1fd4166a]{opacity:.55;transition:opacity .15s,color .15s}.msg-rate-btn[data-v-1fd4166a]:hover{opacity:1}.msg-rate-btn.active[data-v-1fd4166a]{opacity:1;color:var(--accent, #4ec9b0)}.message-list-wrap[data-v-6967a257]{flex:1;min-height:0;position:relative;display:flex;flex-direction:column}.messages-group[data-v-6967a257]{display:flex;flex-direction:column;gap:32px}.scroll-to-bottom-btn[data-v-6967a257]{position:absolute;bottom:16px;right:16px;width:40px;height:40px;border-radius:50%;background:var(--color-secondary, #7aa2f7);color:var(--color-black, #1a1b2e);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px;box-shadow:0 2px 12px #0006;opacity:.9;transition:opacity .15s ease,transform .15s ease;z-index:10}.scroll-to-bottom-btn[data-v-6967a257]:hover{opacity:1;transform:translateY(-2px)}.scroll-btn-enter-active[data-v-6967a257],.scroll-btn-leave-active[data-v-6967a257]{transition:opacity .2s ease,transform .2s ease}.scroll-btn-enter-from[data-v-6967a257],.scroll-btn-leave-to[data-v-6967a257]{opacity:0;transform:translateY(8px)}.file-preview-image[data-v-0239fe0c]{position:relative}.file-preview-image .file-preview-remove[data-v-0239fe0c]{position:absolute;top:-4px;right:-4px;background:var(--surface-panel, #1f2335);border:1px solid var(--border-color-muted);width:18px;height:18px;display:flex;align-items:center;justify-content:center;font-size:10px;cursor:pointer;color:var(--color-text-dark)}.file-preview-image .file-preview-remove[data-v-0239fe0c]:hover{color:var(--color-error)}.reconnect-notice[data-v-8e422257]{display:flex;align-items:center;gap:6px;padding:4px 8px;font-size:12px;color:var(--color-warning, #e0af68);margin-bottom:4px}.reconnect-banner[data-v-9312ef2d]{display:flex;align-items:center;gap:8px;padding:6px 16px;background:#e0af681a;border-bottom:1px solid rgba(224,175,104,.3);font-size:13px;color:var(--color-warning, #e0af68)}.welcome-sidebar-btn[data-v-fe297861]{display:none;position:absolute;top:12px;left:12px}@media(max-width:1280px){.welcome-sidebar-btn[data-v-fe297861]{display:flex}}.confirm-panel[data-v-49a56e4f]{max-width:420px;min-height:unset}.lightbox-panel[data-v-9d2a8160]{max-width:90vw;min-height:unset;width:fit-content;cursor:default}.lightbox-body[data-v-9d2a8160]{display:flex;align-items:center;justify-content:center;padding:0;max-height:calc(90vh - 60px);overflow:hidden}.lightbox-img[data-v-9d2a8160]{display:block;max-width:100%;max-height:calc(90vh - 60px);object-fit:contain}.selection-toolbar[data-v-615fec6a]{position:fixed;transform:translate(-50%);z-index:900;pointer-events:all;background:#e0af68;color:#000}.artifacts-panel[data-v-f99bc53c]{width:var(--artifacts-width, min(600px, 42vw));min-width:var(--artifacts-width, min(600px, 42vw));max-width:var(--artifacts-width, min(600px, 42vw));display:flex;flex-direction:column;background:var(--surface, #1e1e2e);border-left:1px solid var(--border, #2a2a3e);min-height:0;margin-right:calc(-1 * var(--artifacts-width, min(600px, 42vw)));opacity:0;pointer-events:none;transform:translate(100%);position:relative;transition:margin-right .22s ease,opacity .22s ease,transform .22s ease}.artifacts-panel.is-open[data-v-f99bc53c]{margin-right:0;opacity:1;pointer-events:auto;transform:translate(0)}.artifacts-panel.is-resizing[data-v-f99bc53c]{transition:none}.artifacts-resize-handle[data-v-f99bc53c]{position:absolute;top:0;left:-4px;bottom:0;width:8px;z-index:2;cursor:col-resize;touch-action:none}.artifacts-resize-handle[data-v-f99bc53c]:after{content:"";position:absolute;top:0;left:3px;width:1px;height:100%;background:transparent;transition:background .15s ease}.artifacts-resize-handle[data-v-f99bc53c]:hover:after,.artifacts-panel.is-resizing .artifacts-resize-handle[data-v-f99bc53c]:after{background:var(--accent, #4ec9b0)}.artifacts-header[data-v-f99bc53c]{height:64px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:0 14px;border-bottom:1px solid var(--border, #2a2a3e)}.artifacts-title[data-v-f99bc53c]{font-size:14px;font-weight:600;color:var(--text, #cdd6f4)}.artifacts-count[data-v-f99bc53c]{margin-top:2px;font-size:12px;color:var(--text-muted, #6c7086)}.artifacts-empty[data-v-f99bc53c]{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--text-muted, #6c7086);font-size:13px}.artifacts-empty i[data-v-f99bc53c]{font-size:28px}.artifacts-list[data-v-f99bc53c]{max-height:232px;overflow-y:auto;border-bottom:1px solid var(--border, #2a2a3e)}.artifact-item[data-v-f99bc53c]{width:100%;min-height:58px;display:flex;align-items:center;gap:10px;padding:10px 14px;border:0;border-left:3px solid transparent;background:transparent;color:var(--text, #cdd6f4);text-align:left;cursor:pointer}.artifact-item[data-v-f99bc53c]:hover{background:#ffffff08}.artifact-item.is-active[data-v-f99bc53c]{border-left-color:var(--accent, #4ec9b0);background:#4ec9b014}.artifact-icon[data-v-f99bc53c]{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;color:var(--accent, #4ec9b0);background:var(--accent-muted, #313244)}.artifact-info[data-v-f99bc53c]{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}.artifact-title[data-v-f99bc53c],.artifact-detail-title[data-v-f99bc53c],.artifact-detail-filename[data-v-f99bc53c]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.artifact-title[data-v-f99bc53c]{font-size:13px;font-weight:500}.artifact-meta[data-v-f99bc53c]{font-size:11px;color:var(--text-muted, #6c7086)}.artifact-detail[data-v-f99bc53c]{flex:1;min-height:0;display:flex;flex-direction:column}.artifact-detail-header[data-v-f99bc53c]{padding:12px 14px 8px}.artifact-detail-title[data-v-f99bc53c]{font-size:14px;font-weight:600;color:var(--text, #cdd6f4)}.artifact-detail-filename[data-v-f99bc53c]{margin-top:3px;font-size:12px;color:var(--text-muted, #6c7086)}.artifact-actions[data-v-f99bc53c]{display:grid;grid-template-columns:repeat(auto-fit,minmax(42px,1fr));gap:6px;padding:0 14px 12px}.artifact-action[data-v-f99bc53c]{height:32px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--border, #2a2a3e);background:var(--surface-elevated, #242438);color:var(--text, #cdd6f4);text-decoration:none;cursor:pointer}.artifact-action[data-v-f99bc53c]:hover{border-color:var(--accent, #4ec9b0);color:var(--accent, #4ec9b0)}.artifact-preview[data-v-f99bc53c]{flex:1;min-height:0;border-top:1px solid var(--border, #2a2a3e);background:#11111b}.artifact-frame[data-v-f99bc53c],.artifact-image[data-v-f99bc53c],.artifact-video[data-v-f99bc53c]{width:100%;height:100%;border:0;display:block}.artifact-image[data-v-f99bc53c],.artifact-video[data-v-f99bc53c]{object-fit:contain}.artifact-source[data-v-f99bc53c]{height:100%;overflow:auto;background:#11111b}.artifact-source-code[data-v-f99bc53c],.artifact-source-error[data-v-f99bc53c]{margin:0;padding:14px;white-space:pre;font-family:IBM Plex Mono,monospace;font-size:12px;line-height:1.6;color:var(--text, #cdd6f4)}.artifact-source-error[data-v-f99bc53c]{color:var(--error, #f7768e)}.artifact-source-state[data-v-f99bc53c]{display:flex;align-items:center;gap:8px;padding:14px;color:var(--text-muted, #6c7086);font-size:12px}.artifact-no-preview[data-v-f99bc53c]{height:100%;min-height:220px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--text-muted, #6c7086);font-size:13px}.artifact-no-preview i[data-v-f99bc53c]{font-size:28px}@media(max-width:980px){.artifacts-panel[data-v-f99bc53c]{position:fixed;top:0;right:0;bottom:0;z-index:120;margin-right:0;transform:translate(100%);width:100vw;min-width:100vw;max-width:100vw}.artifacts-resize-handle[data-v-f99bc53c]{display:none}.artifacts-panel.is-open[data-v-f99bc53c]{transform:translate(0)}}@media(min-width:981px){.artifacts-close[data-v-f99bc53c]{display:none}}@media(prefers-reduced-motion:reduce){.artifacts-panel[data-v-f99bc53c]{transition:none}}.app-shell[data-v-2fc30202]{display:flex;flex:1 1 0;min-height:0;min-width:0;overflow:hidden}.sidebar-backdrop[data-v-2fc30202]{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;z-index:99}@media(max-width:1280px){.sidebar-backdrop[data-v-2fc30202]{display:block}}.artifacts-backdrop[data-v-2fc30202]{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000073;z-index:119}@media(max-width:980px){.artifacts-backdrop[data-v-2fc30202]{display:block}}.backdrop-fade-enter-active[data-v-2fc30202],.backdrop-fade-leave-active[data-v-2fc30202]{transition:opacity .18s ease}.backdrop-fade-enter-from[data-v-2fc30202],.backdrop-fade-leave-to[data-v-2fc30202]{opacity:0}@font-face{font-family:IBM Plex Mono;src:url(/assets/fonts/IBM_Plex_Mono/IBMPlexMono-Regular.ttf) format("truetype");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:IBM Plex Mono;src:url(/assets/fonts/IBM_Plex_Mono/IBMPlexMono-Medium.ttf) format("truetype");font-weight:500;font-style:normal;font-display:swap}@font-face{font-family:IBM Plex Mono;src:url(/assets/fonts/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf) format("truetype");font-weight:600;font-style:normal;font-display:swap}@font-face{font-family:IBM Plex Mono;src:url(/assets/fonts/IBM_Plex_Mono/IBMPlexMono-Bold.ttf) format("truetype");font-weight:700;font-style:normal;font-display:swap}@font-face{font-family:IBM Plex Mono;src:url(/assets/fonts/IBM_Plex_Mono/IBMPlexMono-Italic.ttf) format("truetype");font-weight:400;font-style:italic;font-display:swap}.container{padding:18px}.section{margin-bottom:48px}.section-title,.block{margin-bottom:34px}.block-title{margin-bottom:22px}p,.text{margin-bottom:15px}.hint{margin-top:8px}.list{padding-left:22px;margin-bottom:15px}.list-item{margin-bottom:8px}.list-nested{margin-top:8px}.table{margin-bottom:22px}.table-caption{margin-bottom:8px}.form-group{margin-bottom:15px}.label{margin-bottom:5px;display:block}.input,.textarea,.select{margin-top:5px}.toast{padding:15px}.toast-stack{gap:8px}@keyframes terminal_scan_x{0%{transform:translate(-120%)}to{transform:translate(220%)}}@keyframes terminal_scan_y{0%{transform:translateY(-120%)}to{transform:translateY(220%)}}@keyframes terminal_pulse{0%,to{box-shadow:0 0 #c0caf500}50%{box-shadow:0 0 0 4px #c0caf52e}}@keyframes panel_boot{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes overlay_reveal{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}@keyframes tooltip_reveal{0%{opacity:0;transform:translate(-50%) translateY(5px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}html{font-size:100%}body{font-family:IBM Plex Mono,monospace;font-size:15px;font-weight:400;line-height:1.6;letter-spacing:0;color:#c0caf5}h1,h2,h3,h4,h5,h6{font-family:IBM Plex Mono,monospace;font-weight:600;line-height:1.25;margin:0}h1.contrast,h2.contrast,h3.contrast,h4.contrast,h5.contrast,h6.contrast{background:#c0caf5;color:#16161e;display:inline;padding:0 8px}h1{font-size:34px;letter-spacing:0}h2{font-size:26px}h3{font-size:22px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px;font-weight:500}.text,p{font-size:15px;line-height:1.6}.text-sm{font-size:13px;line-height:1.4}.text-lg{font-size:16px;line-height:1.6}.text-lead{max-width:760px;color:#c0caf5;font-size:16px;font-weight:500;line-height:1.6}.text-muted{font-size:13px;color:#787c99}.text-strong,strong{font-weight:600}.text-bold{font-weight:700}.text-italic,em{font-style:italic}.text-success{color:#9ece6a}.text-warning{color:#e0af68}.text-danger,.text-error{color:#f7768e}.text-info{color:#bb9af7}.eyebrow{display:inline-flex;width:max-content;max-width:100%;padding:5px 8px;color:#16161e;background:#7aa2f7;font-size:12px;font-weight:700;line-height:1;text-transform:uppercase}.caption{color:#787c99;font-size:12px;line-height:1.4}code,pre,.code{font-family:IBM Plex Mono,monospace;font-size:15px;line-height:1.4;background-color:#1f2335}.text-primary{color:#c0caf5}.text-secondary{color:#a9b1d6}pre{font-size:15px;line-height:1.6;white-space:pre-wrap}pre code,.code{tab-size:2;-moz-tab-size:2}.code{display:inline-flex;padding:0 5px;color:#7aa2f7;border:2px solid rgba(122,162,247,.24)}.kbd{display:inline-flex;align-items:center;min-height:24px;padding:0 8px;border:2px solid rgba(192,202,245,.24);border-bottom-color:#7aa2f7;color:#c0caf5;background:#c0caf50b;font-family:IBM Plex Mono,monospace;font-size:12px;font-weight:700;line-height:1;text-transform:uppercase}.quote{max-width:760px;margin:0;padding:15px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;color:#a9b1d6;background:#c0caf50b;font-size:15px;line-height:1.6}.quote cite{display:block;margin-top:12px;color:#7aa2f7;font-size:13px;font-style:normal;text-transform:uppercase}a{font-weight:500;text-decoration:none;color:#7aa2f7}@media(hover:hover)and (pointer:fine){a:hover{color:#e0af68}}@media(hover:none)and (pointer:coarse){a:active{color:#e0af68}}.link{font-size:inherit;font-weight:500}.label{font-size:13px;font-weight:500;line-height:1.4}.hint,.meta{font-size:12px;line-height:1.4}.table{font-size:13px;line-height:1.4}.table th{font-weight:600}.table td{font-weight:400}.list{font-size:15px;line-height:1.6}.list-item{font-size:inherit}.modal-title{font-size:20px;font-weight:600}.modal-body{font-size:15px}.toast-title{font-size:14px;font-weight:600}.toast-text{font-size:13px;line-height:1.4}.palette{display:flex;flex-direction:row;gap:8px}.palette .color .color-box{width:92px;height:68px}body .bg-primary{background:#c0caf5}body .bg-secondary{background:#7aa2f7}body .bg-success{background:#9ece6a}body .bg-accent{background:#ff9e64}body .bg-info{background:#bb9af7}body .bg-warning{background:#e0af68}body .bg-error{background:#f7768e}body .text-color-primary{color:#c0caf5}body .text-color-secondary{color:#7aa2f7}body .text-color-success{color:#9ece6a}body .text-color-accent{color:#ff9e64}body .text-color-info{color:#bb9af7}body .text-color-warning{color:#e0af68}body .text-color-error{color:#f7768e}.loader{width:32px;aspect-ratio:1;--c:no-repeat linear-gradient(#FF3C00 0 0);background:var(--c) 0 0,var(--c) 0 100%,var(--c) 50% 0,var(--c) 50% 100%,var(--c) 100% 0,var(--c) 100% 100%;animation:l12 1s infinite}@keyframes l12{0%,to{background-size:20% 50%}16.67%{background-size:20% 30%,20% 30%,20% 50%,20% 50%,20% 50%,20% 50%}33.33%{background-size:20% 30%,20% 30%,20% 30%,20% 30%,20% 50%,20% 50%}50%{background-size:20% 30%,20% 30%,20% 30%,20% 30%,20% 30%,20% 30%}66.67%{background-size:20% 50%,20% 50%,20% 30%,20% 30%,20% 30%,20% 30%}83.33%{background-size:20% 50%,20% 50%,20% 50%,20% 50%,20% 30%,20% 30%}}.circle-loader{display:flex;flex-direction:row;align-items:center;gap:8px}.circle-loader .ph,.circle-loader .ph-bold{font-size:26px;transform-origin:50% 50%;animation:icon_spin 1.2s linear infinite}.progress{display:flex;flex-direction:column;gap:8px;width:100%;max-width:640px}.progress .progress-header{display:flex;align-items:center;justify-content:space-between;gap:12px;color:#a9b1d6;font-size:13px;font-weight:600;text-transform:uppercase}.progress .progress-value{color:#c0caf5;font-family:IBM Plex Mono,monospace}.progress .progress-track{position:relative;width:100%;height:18px;overflow:hidden;border:2px solid rgba(192,202,245,.24);background:#c0caf50b}.progress .progress-bar{display:block;position:relative;overflow:hidden;width:var(--progress-value, 0%);height:100%;background:#7aa2f7;transition:width .28s ease}.progress.progress-success .progress-bar{background:#9ece6a}.progress.progress-warning .progress-bar{background:#e0af68}.progress.progress-danger .progress-bar,.progress.progress-error .progress-bar{background:#f7768e}.progress.progress-striped .progress-bar{background-image:repeating-linear-gradient(90deg,transparent 0,transparent 14px,rgba(22,22,30,.2) 14px,rgba(22,22,30,.2) 16px)}.progress.progress-animated .progress-bar:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;width:48%;background:linear-gradient(90deg,transparent,rgba(192,202,245,.28),transparent);transform:translate(-120%);animation:progress_scan 1.4s ease infinite}.usage-meter{display:grid;gap:12px;width:100%;max-width:420px;padding:15px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.usage-meter .usage-meter-title{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0;font-size:16px;font-weight:700;line-height:1;text-transform:uppercase}.usage-meter .usage-meter-value{color:#7aa2f7;font-family:IBM Plex Mono,monospace;font-size:13px}.usage-meter .usage-meter-meta{margin:0;color:#a9b1d6;font-size:13px;line-height:1.4}.progress-stages{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;width:100%;max-width:720px}.progress-stages .progress-stage{min-height:42px;padding:8px 12px;border:2px solid rgba(192,202,245,.24);color:#787c99;background:#c0caf50b;font-size:13px;font-weight:600;line-height:1.4;text-transform:uppercase}.progress-stages .progress-stage-complete{color:#16161e;background:#9ece6a;border-color:#9ece6a}.progress-stages .progress-stage-current{color:#16161e;background:#e0af68;border-color:#e0af68}@media(max-width:767px){.progress-stages{grid-template-columns:1fr 1fr}}@media(max-width:479px){.progress-stages{grid-template-columns:1fr}}@keyframes progress_scan{0%{transform:translate(-120%)}to{transform:translate(220%)}}@keyframes icon_spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.btn{display:inline-flex;align-items:center;justify-content:center;min-height:46px;font-family:IBM Plex Mono,monospace;font-size:15px;font-weight:600;line-height:1;letter-spacing:.04em;padding:12px 22px;border-radius:0;border-width:2px;border-left-width:6px;border-style:solid;border-color:#c0caf5;text-transform:uppercase;background-color:transparent;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:background-color,border-color,color,opacity}.btn:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}.btn.with-icon{border-left-width:46px;position:relative}.btn.with-icon .ph,.btn.with-icon .ph-bold{position:absolute;color:#16161e;left:-46px;top:1px;font-size:26px;height:100%;display:inline-flex;align-items:center;width:46px;justify-content:center;transition-duration:.2s;transition-property:color,left}@media(hover:hover)and (pointer:fine){.btn:hover.with-icon:not(.loading-state):not(.btn-small) .ph,.btn:hover.with-icon:not(.loading-state):not(.btn-small) .ph-bold{left:-28px}}@media(hover:none)and (pointer:coarse){.btn:active.with-icon:not(.loading-state):not(.btn-small) .ph,.btn:active.with-icon:not(.loading-state):not(.btn-small) .ph-bold{left:-28px}}.btn.btn-primary{color:#c0caf5;border-color:#c0caf5}@media(hover:hover)and (pointer:fine){.btn.btn-primary:hover{background-color:#c0caf5;color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-primary:active{background-color:#c0caf5;color:#16161e}}.btn.btn-secondary{color:#7aa2f7;border-color:#7aa2f7}@media(hover:hover)and (pointer:fine){.btn.btn-secondary:hover{background-color:#7aa2f7;color:#16161e}.btn.btn-secondary:hover.with-icon .ph,.btn.btn-secondary:hover.with-icon .ph-bold{color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-secondary:active{background-color:#7aa2f7;color:#16161e}.btn.btn-secondary:active.with-icon .ph,.btn.btn-secondary:active.with-icon .ph-bold{color:#16161e}}.btn.btn-accent{color:#ff9e64;border-color:#ff9e64}@media(hover:hover)and (pointer:fine){.btn.btn-accent:hover{background-color:#ff9e64;color:#16161e}.btn.btn-accent:hover.with-icon .ph,.btn.btn-accent:hover.with-icon .ph-bold{color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-accent:active{background-color:#ff9e64;color:#16161e}.btn.btn-accent:active.with-icon .ph,.btn.btn-accent:active.with-icon .ph-bold{color:#16161e}}.btn.btn-danger{color:#f7768e;border-color:#f7768e}@media(hover:hover)and (pointer:fine){.btn.btn-danger:hover{background-color:#f7768e;color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-danger:active{background-color:#f7768e;color:#16161e}}.btn.btn-warning{color:#e0af68;border-color:#e0af68}@media(hover:hover)and (pointer:fine){.btn.btn-warning:hover{background-color:#e0af68;color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-warning:active{background-color:#e0af68;color:#16161e}}.btn.btn-success{color:#9ece6a;border-color:#9ece6a}@media(hover:hover)and (pointer:fine){.btn.btn-success:hover{background-color:#9ece6a;color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-success:active{background-color:#9ece6a;color:#16161e}}.btn.btn-info{color:#bb9af7;border-color:#bb9af7}@media(hover:hover)and (pointer:fine){.btn.btn-info:hover{background-color:#bb9af7;color:#16161e}.btn.btn-info:hover.with-icon .ph,.btn.btn-info:hover.with-icon .ph-bold{color:#16161e}}@media(hover:none)and (pointer:coarse){.btn.btn-info:active{background-color:#bb9af7;color:#16161e}.btn.btn-info:active.with-icon .ph,.btn.btn-info:active.with-icon .ph-bold{color:#16161e}}.btn[disabled]:not(.loading-state){color:#787c99;border-color:#c0caf53d;background-color:#1f2335;cursor:not-allowed;opacity:.72}.btn[disabled]:not(.loading-state).with-icon .ph,.btn[disabled]:not(.loading-state).with-icon .ph-bold{color:#787c99}@media(hover:hover)and (pointer:fine){.btn[disabled]:not(.loading-state):hover{background-color:#1f2335;color:#787c99}.btn[disabled]:not(.loading-state):hover.with-icon .ph,.btn[disabled]:not(.loading-state):hover.with-icon .ph-bold{color:#787c99}}@media(hover:none)and (pointer:coarse){.btn[disabled]:not(.loading-state):active{background-color:#1f2335;color:#787c99}.btn[disabled]:not(.loading-state):active.with-icon .ph,.btn[disabled]:not(.loading-state):active.with-icon .ph-bold{color:#787c99}}.btn[disabled]:not(.loading-state).with-icon:not(.btn-small) .ph,.btn[disabled]:not(.loading-state).with-icon:not(.btn-small) .ph-bold{left:-28px}.btn.btn-small{font-size:13px;font-weight:500;min-height:38px;padding:8px}.btn.btn-small.with-icon{border-left-width:32px}.btn.btn-small.with-icon .ph,.btn.btn-small.with-icon .ph-bold{top:0;left:-40px;font-size:22px}.btn.btn-small.with-icon.loading-state .ph,.btn.btn-small.with-icon.loading-state .ph-bold{font-size:26px}.btn.btn-large{font-size:16px;font-weight:700;min-height:54px;padding:15px 48px}.btn.loading-state{color:#16161e!important;border-color:#c0caf5!important;background-color:#c0caf5!important}.btn.loading-state .ph,.btn.loading-state .ph-bold{font-size:26px;transform-origin:50% 50%;animation:icon_spin 1.2s linear infinite}.btn-icon{display:flex;justify-content:center;align-items:center;width:38px;height:38px;background:transparent;color:#c0caf5;font-size:22px;border:2px solid transparent;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background,border-color}.btn-icon:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}.btn-icon .ph{transform:rotate(0);transition-duration:.2s;transition-property:transform}@media(hover:hover)and (pointer:fine){.btn-icon:not(.without-hover):hover{color:#e0af68;border-color:#e0af68}.btn-icon:not(.without-hover):hover .ph{transform:rotate(90deg)}}@media(hover:none)and (pointer:coarse){.btn-icon:not(.without-hover):active{color:#e0af68;border-color:#e0af68}.btn-icon:not(.without-hover):active .ph{transform:rotate(90deg)}}.form-group{width:100%;max-width:600px}.form-group .label{display:flex;flex-direction:column;font-size:15px;width:100%;position:relative}.form-group .label>.ph{position:absolute;color:#c0caf5;left:0;bottom:1px;font-size:26px;height:54px;display:inline-flex;align-items:center;width:46px;justify-content:center;transition-duration:.2s;transition-property:color,left}.form-group .label .input{min-height:54px;font-family:IBM Plex Mono,monospace;font-size:15px;font-weight:500;line-height:1;letter-spacing:.04em;padding:12px 22px;margin-top:8px;border-radius:0;border-width:2px;border-bottom-width:6px;border-style:solid;border-color:#c0caf5;color:#c0caf5;background-color:#c0caf50b;transition-duration:.2s;transition-timing-function:ease;transition-property:background-color,border-color,color}@media(hover:hover)and (pointer:fine){.form-group .label .input:hover{border-bottom-color:#787c99}}@media(hover:none)and (pointer:coarse){.form-group .label .input:active{border-bottom-color:#787c99}}.form-group .label .input:focus{outline:2px solid #E0AF68;outline-offset:3px;border-color:#7aa2f7;background-color:transparent}.form-group .label .input:disabled{color:#787c99;border-color:#c0caf53d;background:#1f2335;cursor:not-allowed;opacity:.72}.form-group .label .input[readonly]{color:#a9b1d6;border-color:#c0caf53d;background:#c0caf508}.form-group .label .input::placeholder{color:#787c99}.form-group .label .input::-webkit-search-cancel-button,.form-group .label .input::-webkit-search-decoration,.form-group .label .input::-webkit-search-results-button,.form-group .label .input::-webkit-search-results-decoration{display:none;-webkit-appearance:none}.form-group .label textarea.input{height:108px;line-height:1.25;resize:none}.form-group .label .ph+.input,.form-group .label .ph+.select-wrap .select{padding-left:46px}.form-group .label .select-wrap{margin-top:8px}.form-group .label .select{width:100%;height:54px;margin-top:0;appearance:none;-webkit-appearance:none;-moz-appearance:none}.form-group .label .select:focus{outline:none}.form-group .label .select option{color:#c0caf5;background:#1f2335}.form-group .label .select-wrap:after{content:"";position:absolute;right:22px;bottom:18px;transform:translateY(-50%);width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:10px solid #C0CAF5;pointer-events:none}.form-group .label.error .input:not(:focus){border-color:#f7768e}.form-group .label.error+.input-info{color:#e0af68}.form-group .label.success .input:not(:focus){border-color:#9ece6a}.form-group .label.success+.input-info{color:#9ece6a}.form-group .label.warning .input:not(:focus){border-color:#e0af68}.form-group .label.warning+.input-info{color:#e0af68}.form-group .input-info{font-size:14px;margin-top:8px}.form-group .input-info .ph{position:relative;top:1px}.form-group .input-info.error{color:#e0af68}.form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:15px;width:100%;max-width:760px}.fieldset{width:100%;max-width:760px;margin:0;padding:18px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.legend{padding:5px 8px;color:#16161e;background:#c0caf5;font-size:13px;font-weight:700;line-height:1;text-transform:uppercase}.file-upload{display:inline-flex;align-items:center;gap:8px;min-height:46px;padding:8px 12px;border:2px solid #7AA2F7;border-left-width:6px;color:#7aa2f7;background:#c0caf50b;font-size:13px;font-weight:700;text-transform:uppercase;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background,border-color}.file-upload input[type=file]{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@media(hover:hover)and (pointer:fine){.file-upload:hover{color:#16161e;background:#7aa2f7}}@media(hover:none)and (pointer:coarse){.file-upload:active{color:#16161e;background:#7aa2f7}}.file-upload:focus-within{outline:2px solid #E0AF68;outline-offset:3px}.range{width:100%;max-width:600px;accent-color:#7AA2F7}.range input[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:46px;margin:0;background:transparent;cursor:pointer}.range input[type=range]::-webkit-slider-runnable-track{height:6px;background:#c0caf516;border:2px solid rgba(192,202,245,.24)}.range input[type=range]::-webkit-slider-thumb{width:18px;height:38px;margin-top:-19px;border:2px solid #7AA2F7;background:#7aa2f7;-webkit-appearance:none}.range input[type=range]::-moz-range-track{height:6px;background:#c0caf516;border:2px solid rgba(192,202,245,.24)}.range input[type=range]::-moz-range-thumb{width:18px;height:38px;border:2px solid #7AA2F7;border-radius:0;background:#7aa2f7}@media(max-width:767px){.form-grid{grid-template-columns:1fr}}.radio{display:inline-flex;flex-direction:row;gap:8px;align-items:center}.radio input[type=radio]{display:none}.radio .radio-control{display:inline-block;border-radius:100%;border:2px solid #C0CAF5;width:18px;height:18px;background:transparent;transition-duration:.2s;transition-property:background,border-color}@media(hover:hover)and (pointer:fine){.radio:hover .radio-control{background:#414868}}@media(hover:none)and (pointer:coarse){.radio:active .radio-control{background:#414868}}.radio input[type=radio]:checked+.radio-control{background:#c0caf5}.radio input[type=radio]:disabled+.radio-control{background:#414868;border-color:#414868}.radio input[type=radio]:focus-visible+.radio-control{outline:2px solid #E0AF68;outline-offset:3px}.radio .radio-label{font-size:15px}.checkbox{display:inline-flex;flex-direction:row;gap:8px;align-items:center}.checkbox input[type=checkbox]{display:none}.checkbox .checkbox-control{height:16px;width:32px;border:2px solid #C0CAF5;position:relative;background:transparent;transition-duration:.2s;transition-property:border-color,background;display:block}.checkbox .checkbox-control:before{content:"";display:block;height:20px;width:20px;background:#c0caf5;position:absolute;left:-5px;top:-5px;transition-duration:.2s;transition-property:left,background}@media(hover:hover)and (pointer:fine){.checkbox:hover .checkbox-control{background:#414868}}@media(hover:none)and (pointer:coarse){.checkbox:active .checkbox-control{background:#414868}}.checkbox input[type=checkbox]:checked:not(:disabled)+.checkbox-control{background:#7aa2f7;border-color:#7aa2f7}.checkbox input[type=checkbox]:checked+.checkbox-control:before{left:17px}.checkbox input[type=checkbox]:disabled+.checkbox-control{border-color:#414868}.checkbox input[type=checkbox]:focus-visible+.checkbox-control{outline:2px solid #E0AF68;outline-offset:3px}.checkbox input[type=checkbox]:disabled+.checkbox-control:before{background:#414868}.input-group{display:flex;align-items:stretch;width:100%;max-width:600px;min-height:54px;border:2px solid #C0CAF5;border-bottom-width:6px;background:#c0caf50b;transition-duration:.2s;transition-timing-function:ease;transition-property:border-color,background}.input-group:focus-within{outline:2px solid #E0AF68;outline-offset:3px;border-color:#7aa2f7;background:transparent}.input-group .input-group-addon,.input-group .input-group-action{display:inline-flex;align-items:center;justify-content:center;min-width:54px;padding:0 12px;color:#a9b1d6;background:#c0caf50b;border:0;font-family:IBM Plex Mono,monospace;font-size:13px;font-weight:600;text-transform:uppercase}.input-group .input-group-action{color:#c0caf5;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background}@media(hover:hover)and (pointer:fine){.input-group .input-group-action:hover{color:#16161e;background:#e0af68}}@media(hover:none)and (pointer:coarse){.input-group .input-group-action:active{color:#16161e;background:#e0af68}}.input-group .input-group-input{flex:1 1 auto;min-width:0;border:0;padding:12px 15px;color:#c0caf5;background:transparent;font-family:IBM Plex Mono,monospace;font-size:15px;font-weight:500;letter-spacing:.04em}.input-group .input-group-input:focus{outline:none}.input-group .input-group-input::placeholder{color:#787c99}.input-group .input-group-input::-webkit-search-cancel-button,.input-group .input-group-input::-webkit-search-decoration,.input-group .input-group-input::-webkit-search-results-button,.input-group .input-group-input::-webkit-search-results-decoration{display:none;-webkit-appearance:none}.input-group .ph,.input-group .ph-bold{font-size:22px}.input-group.input-group-compact{min-height:46px}.input-group.input-group-compact .input-group-addon,.input-group.input-group-compact .input-group-action{min-width:46px}.input-group.input-group-compact .input-group-input{padding:8px 12px;font-size:13px}.search-field{max-width:420px}.list{display:flex;flex-direction:column;gap:5px;list-style-type:none;padding-left:0}.list .list-item{display:flex;flex-direction:row;align-items:center;gap:8px;margin-left:0}.list.list-ordered{list-style-type:decimal;display:list-item;margin-left:30px}.list.list-ordered .list-item{display:list-item}.list.list-definition{width:100%;max-width:620px;gap:0;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.list.list-definition .list-row{display:grid;grid-template-columns:minmax(120px,.32fr) minmax(0,1fr);gap:15px;align-items:start;padding:12px 15px;border-bottom:2px solid rgba(192,202,245,.08);transition-duration:.2s;transition-timing-function:ease;transition-property:background,border-color}.list.list-definition .list-row .list-term{display:inline-flex;width:max-content;max-width:100%;margin:0;padding:5px 8px;color:#16161e;background:#c0caf5;font-size:13px;font-weight:700;line-height:1;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:background,transform}.list.list-definition .list-row .list-desc{margin:0;color:#a9b1d6;font-size:13px;line-height:1.6;transition-duration:.2s;transition-timing-function:ease;transition-property:color,transform}.list.list-definition .list-row:last-child{border-bottom:0}@media(hover:hover)and (pointer:fine){.list.list-definition .list-row:hover{background:#c0caf516}.list.list-definition .list-row:hover .list-term{background:#7aa2f7;transform:translate(5px)}.list.list-definition .list-row:hover .list-desc{color:#c0caf5;transform:translate(5px)}}@media(hover:none)and (pointer:coarse){.list.list-definition .list-row:active{background:#c0caf516}.list.list-definition .list-row:active .list-term{background:#7aa2f7;transform:translate(5px)}.list.list-definition .list-row:active .list-desc{color:#c0caf5;transform:translate(5px)}}.list.list-nav{max-width:420px;width:100%;gap:0}.list.list-nav .list-item{display:flex;flex-direction:column;align-items:flex-start;height:50px;margin:0}.list.list-nav .list-item .list-action{display:flex;justify-content:space-between;align-items:center;width:100%;height:100%;padding:8px 12px;border:2px solid transparent;font-size:15px;background:#1f2335;color:inherit;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:background,border-color,color}.list.list-nav .list-item .list-action:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){.list.list-nav .list-item .list-action:hover{background:#7aa2f7;color:#16161e}}@media(hover:none)and (pointer:coarse){.list.list-nav .list-item .list-action:active{background:#7aa2f7;color:#16161e}}.list.list-nav .list-item .list-action .list-label{display:flex;flex-direction:row;gap:8px;align-items:center;letter-spacing:0;font-weight:400}.list.list-nav .list-item .list-action .list-meta{padding:8px;background:#9ece6a;color:#16161e;display:flex}.list.list-nav .list-item.list-item-active .list-action{background:#7aa2f7;color:#16161e;border-color:#7aa2f7}.list.list-actions{width:100%;max-width:420px;gap:22px}.list.list-actions .list-item{justify-content:space-between;align-items:flex-start;padding:12px 0;border-bottom:2px solid rgba(192,202,245,.08)}.list.list-actions .list-item .list-content{display:flex;flex-direction:column;gap:8px}.list.list-actions .list-item .list-content .list-title{font-size:16px;line-height:1}.list.list-actions .list-item .list-content .list-subtitle{color:#787c99}@media(hover:hover)and (pointer:fine){.list.list-actions .list-item:hover .list-title{color:#7aa2f7}}@media(hover:none)and (pointer:coarse){.list.list-actions .list-item:active .list-title{color:#7aa2f7}}@media(max-width:479px){.list.list-definition .list-row{grid-template-columns:1fr;gap:8px}}.badge{position:relative;overflow:hidden;background:#c0caf5;color:#16161e;padding:5px 8px;font-size:13px;font-weight:600;line-height:1;letter-spacing:.04em;text-transform:uppercase;display:inline-flex;align-items:center;min-height:24px;transition-duration:.2s;transition-timing-function:ease;transition-property:filter,transform,border-color,color,background}.badge:after{content:"";position:absolute;inset:0 auto 0 0;width:40%;background:linear-gradient(90deg,transparent,rgba(22,22,30,.16),transparent);opacity:0;pointer-events:none;transform:translate(-120%)}@media(hover:hover)and (pointer:fine){.badge:hover{filter:saturate(1.12);transform:translateY(-1px)}.badge:hover:after{opacity:1;animation:terminal_scan_x .7s ease}}@media(hover:none)and (pointer:coarse){.badge:active{filter:saturate(1.12);transform:translateY(-1px)}.badge:active:after{opacity:1;animation:terminal_scan_x .7s ease}}.badge.badge-success{background:#9ece6a}.badge.badge-warning{background:#e0af68}.badge.badge-error,.badge.badge-danger{background:#f7768e}.badge.badge-info{background:#bb9af7;color:#16161e}.badge.badge-secondary{background:#7aa2f7;color:#16161e}.badge.badge-primary-outline{color:#c0caf5;border:2px solid #C0CAF5;background:transparent;padding:3px 8px}.chip-group{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.chip{display:inline-flex;align-items:center;gap:8px;min-height:30px;padding:5px 12px;border:2px solid rgba(192,202,245,.24);color:#a9b1d6;background:#c0caf50b;font-family:IBM Plex Mono,monospace;font-size:12px;font-weight:600;line-height:1;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background,border-color,opacity}.chip .ph,.chip .ph-bold{font-size:18px}.chip:before{content:"";display:inline-block;width:7px;height:7px;flex:0 0 auto;background:#787c99;transition-duration:.2s;transition-timing-function:ease;transition-property:background,box-shadow,transform}.chip:has(.ph):before,.chip:has(.ph-bold):before{display:none}.chip .chip-remove{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:-5px;border:0;color:inherit;background:transparent;font:inherit;cursor:pointer}.chip .chip-remove:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}.chip.chip-primary{color:#c0caf5;background:#c0caf514;border-color:#c0caf5}.chip.chip-primary:before{background:#c0caf5}.chip.chip-secondary{color:#7aa2f7;background:#7aa2f714;border-color:#7aa2f7}.chip.chip-secondary:before{background:#7aa2f7}.chip.chip-success{color:#9ece6a;background:#9ece6a14;border-color:#9ece6a}.chip.chip-success:before{background:#9ece6a}.chip.chip-warning{color:#e0af68;background:#e0af6814;border-color:#e0af68}.chip.chip-warning:before{background:#e0af68}.chip.chip-danger,.chip.chip-error{color:#f7768e;background:#f7768e14;border-color:#f7768e}.chip.chip-danger:before,.chip.chip-error:before{background:#f7768e}.chip.chip-selected,.chip[aria-pressed=true],.chip[aria-selected=true]{color:#16161e;background:#c0caf5;border-color:#c0caf5}.chip.chip-selected:before,.chip[aria-pressed=true]:before,.chip[aria-selected=true]:before{background:#16161e}.chip.chip-selected.chip-secondary,.chip.chip-secondary[aria-pressed=true],.chip.chip-secondary[aria-selected=true]{background:#7aa2f7;border-color:#7aa2f7}.chip.chip-disabled,.chip:disabled{color:#787c99;background:#1f2335;border-color:#c0caf53d;cursor:not-allowed;opacity:.7}.chip.chip-disabled:before,.chip:disabled:before{background:#414868}button.chip,a.chip{cursor:pointer}button.chip:focus-visible,a.chip:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){button.chip:hover,a.chip:hover{color:#c0caf5;background:#c0caf516;border-color:#7aa2f7}button.chip:hover:before,a.chip:hover:before{background:#7aa2f7;animation:terminal_pulse .7s ease;transform:scale(1.12)}}@media(hover:none)and (pointer:coarse){button.chip:active,a.chip:active{color:#c0caf5;background:#c0caf516;border-color:#7aa2f7}button.chip:active:before,a.chip:active:before{background:#7aa2f7;animation:terminal_pulse .7s ease;transform:scale(1.12)}}.avatar{position:relative;display:inline-flex;align-items:center;justify-content:center;width:46px;height:46px;flex:0 0 auto;overflow:hidden;border:2px solid rgba(192,202,245,.24);color:#16161e;background:#c0caf5;font-family:IBM Plex Mono,monospace;font-size:13px;font-weight:700;line-height:1;text-transform:uppercase}.avatar img{width:100%;height:100%;object-fit:cover}.avatar .ph,.avatar .ph-bold{font-size:22px}.avatar .avatar-status{position:absolute;right:-2px;bottom:-2px;width:13px;height:13px;border:2px solid #16161E;background:#787c99;transition-duration:.2s;transition-timing-function:ease;transition-property:background,box-shadow}.avatar.avatar-sm{width:38px;height:38px;font-size:12px}.avatar.avatar-sm .ph,.avatar.avatar-sm .ph-bold{font-size:18px}.avatar.avatar-lg{width:54px;height:54px;font-size:14px}.avatar.avatar-lg .ph,.avatar.avatar-lg .ph-bold{font-size:26px}.avatar.avatar-secondary{background:#7aa2f7}.avatar.avatar-success{background:#9ece6a}.avatar.avatar-warning{background:#e0af68}.avatar.avatar-danger,.avatar.avatar-error{background:#f7768e}.avatar.avatar-outline{color:#c0caf5;background:#c0caf50b;border-color:#c0caf5}.avatar.is-online .avatar-status{background:#9ece6a;animation:terminal_pulse 1.8s ease infinite}.avatar.is-busy .avatar-status{background:#e0af68}.avatar.is-offline .avatar-status{background:#787c99}.identity{display:inline-flex;align-items:center;gap:12px;min-width:0}.identity-content{display:flex;flex-direction:column;gap:5px;min-width:0}.identity-title{color:#c0caf5;font-size:15px;font-weight:600;line-height:1}.identity-meta{color:#787c99;font-size:13px;line-height:1.4}.avatar-stack{display:inline-flex;align-items:center}.avatar-stack .avatar{margin-right:-8px;border-color:#16161e}.avatar-stack .avatar-stack-count{display:inline-flex;align-items:center;justify-content:center;min-width:46px;height:46px;padding:0 8px;border:2px solid #16161E;color:#16161e;background:#e0af68;font-size:13px;font-weight:700}.table{width:100%;text-align:left;border:2px solid rgba(192,202,245,.24);border-collapse:collapse;background:#c0caf50b}.table .table-caption{text-align:left;font-size:16px;background:#c0caf5;width:max-content;color:#16161e;padding:5px 12px;margin-bottom:0;font-weight:700;text-transform:uppercase}.table.table-empty{width:100%}.table.table-empty .is-empty{width:100%;padding:15px;font-size:13px;color:#787c99;text-align:left}.table .table-row th,.table .table-row td{padding:12px 18px;font-size:13px;vertical-align:middle;border-bottom:2px solid rgba(192,202,245,.08)}.table .table-row th{color:#c0caf5;background:#c0caf50a;text-transform:uppercase;letter-spacing:.04em}.table .table-head{border-bottom:2px solid #C0CAF5}.table .table-body .table-row{transition-duration:.2s;transition-timing-function:ease;transition-property:background,color}.table .table-body .table-row td{transition-duration:.2s;transition-timing-function:ease;transition-property:color,background}@media(hover:hover)and (pointer:fine){.table .table-body .table-row:hover{background:#7aa2f714}.table .table-body .table-row:hover td:first-child{color:#7aa2f7}}@media(hover:none)and (pointer:coarse){.table .table-body .table-row:active{background:#7aa2f714}.table .table-body .table-row:active td:first-child{color:#7aa2f7}}.table .table-foot th,.table .table-foot td{padding-top:15px}.table.table-compact .table-caption{font-size:14px}.table.table-compact .table-row th,.table.table-compact .table-row td{padding:8px 12px;font-size:12px}.table.table-compact .table-cell-mono{color:#a9b1d6;font-family:IBM Plex Mono,monospace;letter-spacing:0}.table.table-compact .table-cell-actions{width:1%;white-space:nowrap}.table-wrapper{width:100%;overflow-x:auto}.toolbar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;width:100%;padding:12px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.toolbar .toolbar-group{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}.toolbar .toolbar-title{margin:0;font-size:16px;font-weight:700;line-height:1;text-transform:uppercase}.toolbar .toolbar-meta{color:#787c99;font-size:13px}.pagination{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.pagination .pagination-item{display:inline-flex;align-items:center;justify-content:center;min-width:38px;height:38px;padding:0 12px;border:2px solid rgba(192,202,245,.24);color:#a9b1d6;background:#c0caf50b;font-family:IBM Plex Mono,monospace;font-size:13px;font-weight:600;line-height:1;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background,border-color,opacity}.pagination .pagination-item:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){.pagination .pagination-item:hover{color:#16161e;background:#7aa2f7;border-color:#7aa2f7}}@media(hover:none)and (pointer:coarse){.pagination .pagination-item:active{color:#16161e;background:#7aa2f7;border-color:#7aa2f7}}.pagination .pagination-item.pagination-item-active,.pagination .pagination-item[aria-current=page]{color:#16161e;background:#c0caf5;border-color:#c0caf5}.pagination .pagination-item:disabled,.pagination .pagination-item.pagination-item-disabled{color:#787c99;background:#1f2335;border-color:#c0caf53d;cursor:not-allowed;opacity:.72}.pagination .pagination-ellipsis{color:#787c99;padding:0 5px}.empty-state{max-width:560px;padding:22px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.empty-state .empty-state-icon{display:inline-flex;align-items:center;justify-content:center;width:54px;height:54px;margin-bottom:15px;color:#16161e;background:#c0caf5;font-size:26px}.empty-state .empty-state-title{margin:0 0 8px;font-size:20px;font-weight:700;text-transform:uppercase}.empty-state .empty-state-text{max-width:440px;margin:0 0 18px;color:#a9b1d6;line-height:1.6}.empty-state .empty-state-actions{display:flex;flex-wrap:wrap;gap:8px}.empty-state.empty-state-error{border-color:#f7768e}.empty-state.empty-state-error .empty-state-icon{background:#f7768e}.skeleton{display:block;position:relative;overflow:hidden;background:#c0caf516}.skeleton:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,rgba(192,202,245,.12),transparent);animation:skeleton_shimmer 1.6s infinite}.skeleton.skeleton-line{width:100%;height:14px}.skeleton.skeleton-title{width:60%;height:22px}.skeleton.skeleton-block{width:100%;height:120px}.skeleton.skeleton-square{width:54px;height:54px}.skeleton-stack{display:flex;flex-direction:column;gap:12px;max-width:520px;padding:15px;border:2px solid rgba(192,202,245,.24);background:#c0caf50b}@keyframes skeleton_shimmer{to{transform:translate(100%)}}.page-header{position:relative;display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:18px;width:100%;padding:18px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b;overflow:hidden;animation:panel_boot .28s ease both}.page-header:after{content:"";position:absolute;top:0;left:0;width:34%;height:2px;background:linear-gradient(90deg,transparent,#7AA2F7,transparent);opacity:.72;pointer-events:none;transform:translate(-120%)}@media(hover:hover)and (pointer:fine){.page-header:hover:after{animation:terminal_scan_x .9s ease}}@media(hover:none)and (pointer:coarse){.page-header:active:after{animation:terminal_scan_x .9s ease}}.page-header .page-header-content{display:flex;flex-direction:column;gap:8px;min-width:min(100%,320px)}.page-header .page-header-kicker{color:#7aa2f7;font-size:13px;font-weight:700;line-height:1;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:color}.page-header .page-header-title{margin:0;color:#c0caf5;font-size:26px;font-weight:700;line-height:1.15}.page-header .page-header-subtitle{max-width:720px;margin:0;color:#a9b1d6;font-size:15px;line-height:1.6}.page-header .page-header-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px;color:#787c99;font-size:13px}.page-header .page-header-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px}.page-header.page-header-compact{align-items:center;padding:15px}.page-header.page-header-compact .page-header-title{font-size:20px}.page-header.page-header-accent{border-color:#7aa2f7;background:#7aa2f70e}.description-list{display:grid;width:100%;max-width:760px;margin:0;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.description-list .description-list-row{display:grid;grid-template-columns:minmax(140px,.36fr) minmax(0,1fr);gap:15px;padding:12px 15px;border-bottom:2px solid rgba(192,202,245,.08);transition-duration:.2s;transition-timing-function:ease;transition-property:background}.description-list .description-list-row:last-child{border-bottom:0}@media(hover:hover)and (pointer:fine){.description-list .description-list-row:hover{background:#c0caf516}.description-list .description-list-row:hover .description-list-term{color:#7aa2f7}.description-list .description-list-row:hover .description-list-value{transform:translate(5px)}}@media(hover:none)and (pointer:coarse){.description-list .description-list-row:active{background:#c0caf516}.description-list .description-list-row:active .description-list-term{color:#7aa2f7}.description-list .description-list-row:active .description-list-value{transform:translate(5px)}}.description-list .description-list-term{margin:0;color:#787c99;font-size:13px;font-weight:600;line-height:1.4;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:color}.description-list .description-list-value{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;margin:0;color:#c0caf5;font-size:15px;line-height:1.4;transition-duration:.2s;transition-timing-function:ease;transition-property:transform}.description-list .description-list-value-muted{color:#a9b1d6}.description-list.description-list-compact{max-width:520px}.description-list.description-list-compact .description-list-row{grid-template-columns:minmax(112px,.42fr) minmax(0,1fr);gap:12px;padding:8px 12px}.description-list.description-list-compact .description-list-term,.description-list.description-list-compact .description-list-value{font-size:13px}@media(max-width:479px){.description-list .description-list-row{grid-template-columns:1fr;gap:5px}}.steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;width:100%;max-width:900px;margin:0;padding:0;list-style:none}.steps .step{position:relative;display:flex;flex-direction:column;gap:8px;min-height:120px;padding:15px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.steps .step-marker{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;color:#c0caf5;border:2px solid rgba(192,202,245,.24);font-size:13px;font-weight:700;line-height:1}.steps .step-title{margin:0;font-size:14px;font-weight:700;line-height:1.25;text-transform:uppercase}.steps .step-text{margin:0;color:#a9b1d6;font-size:13px;line-height:1.4}.steps .step-complete{border-color:#9ece6a}.steps .step-complete .step-marker{color:#16161e;background:#9ece6a;border-color:#9ece6a}.steps .step-current{border-color:#7aa2f7}.steps .step-current .step-marker{color:#16161e;background:#7aa2f7;border-color:#7aa2f7}.steps .step-disabled{opacity:.62}.steps.steps-vertical{grid-template-columns:1fr;max-width:520px;gap:0}.steps.steps-vertical .step{min-height:auto;border-bottom-width:0}.steps.steps-vertical .step:last-child{border-bottom-width:2px}@media(max-width:1023px){.steps{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:479px){.steps{grid-template-columns:1fr}}.timeline{display:grid;gap:0;width:100%;max-width:760px;margin:0;padding:0;list-style:none}.timeline .timeline-item{position:relative;display:grid;grid-template-columns:46px minmax(0,1fr);gap:12px;min-height:88px}.timeline .timeline-item:before{content:"";position:absolute;top:46px;bottom:0;left:22px;width:2px;background:#c0caf53d}.timeline .timeline-item:last-child:before{display:none}.timeline .timeline-marker{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:46px;height:46px;border:2px solid rgba(192,202,245,.24);color:#a9b1d6;background:#16161e;font-size:18px;transition-duration:.2s;transition-timing-function:ease;transition-property:border-color,background,color,box-shadow,transform}.timeline .timeline-content{min-width:0;padding:0 0 18px}.timeline .timeline-card{padding:15px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b;transition-duration:.2s;transition-timing-function:ease;transition-property:border-color,background,transform}.timeline .timeline-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.timeline .timeline-title{margin:0;font-size:14px;font-weight:700;line-height:1.25;text-transform:uppercase}.timeline .timeline-time{color:#787c99;font-size:12px;font-family:IBM Plex Mono,monospace;line-height:1.4}.timeline .timeline-text{margin:0;color:#a9b1d6;font-size:13px;line-height:1.4}.timeline .timeline-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.timeline .timeline-item-success .timeline-marker,.timeline .timeline-item-success .timeline-card{border-color:#9ece6a}.timeline .timeline-item-success .timeline-marker{color:#16161e;background:#9ece6a}.timeline .timeline-item-warning .timeline-marker,.timeline .timeline-item-warning .timeline-card{border-color:#e0af68}.timeline .timeline-item-warning .timeline-marker{color:#16161e;background:#e0af68}.timeline .timeline-item-danger .timeline-marker,.timeline .timeline-item-danger .timeline-card,.timeline .timeline-item-error .timeline-marker,.timeline .timeline-item-error .timeline-card{border-color:#f7768e}.timeline .timeline-item-danger .timeline-marker,.timeline .timeline-item-error .timeline-marker{color:#16161e;background:#f7768e}@media(hover:hover)and (pointer:fine){.timeline .timeline-item:hover .timeline-marker{box-shadow:0 0 0 4px #7aa2f724;transform:scale(1.04)}.timeline .timeline-item:hover .timeline-card{background:#c0caf516;transform:translate(5px)}}@media(hover:none)and (pointer:coarse){.timeline .timeline-item:active .timeline-marker{box-shadow:0 0 0 4px #7aa2f724;transform:scale(1.04)}.timeline .timeline-item:active .timeline-card{background:#c0caf516;transform:translate(5px)}}.activity-log{display:grid;width:100%;max-width:720px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.activity-log .activity-log-row{display:grid;grid-template-columns:minmax(120px,.24fr) minmax(0,1fr) auto;gap:12px;align-items:center;padding:12px 15px;border-bottom:2px solid rgba(192,202,245,.08);transition-duration:.2s;transition-timing-function:ease;transition-property:background}.activity-log .activity-log-row:last-child{border-bottom:0}@media(hover:hover)and (pointer:fine){.activity-log .activity-log-row:hover{background:#c0caf516}}@media(hover:none)and (pointer:coarse){.activity-log .activity-log-row:active{background:#c0caf516}}.activity-log .activity-log-time{color:#787c99;font-family:IBM Plex Mono,monospace;font-size:12px}.activity-log .activity-log-title{color:#c0caf5;font-size:13px;font-weight:600;line-height:1.4}@media(max-width:479px){.activity-log .activity-log-row{grid-template-columns:1fr;gap:8px}}.accordion{display:grid;width:100%;max-width:760px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.accordion-item{border-bottom:2px solid rgba(192,202,245,.08);overflow:hidden}.accordion-item:last-child{border-bottom:0}.accordion-item[open] .accordion-summary{color:#16161e;background:#c0caf5}.accordion-item[open] .accordion-icon{transform:rotate(180deg)}.accordion-summary{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:46px;padding:12px 15px;color:#c0caf5;cursor:pointer;font-size:13px;font-weight:700;line-height:1;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background}.accordion-summary::-webkit-details-marker{display:none}.accordion-summary::marker{content:""}.accordion-summary:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){.accordion-summary:hover{color:#16161e;background:#7aa2f7}}@media(hover:none)and (pointer:coarse){.accordion-summary:active{color:#16161e;background:#7aa2f7}}.accordion-summary-content{display:flex;align-items:center;gap:8px;min-width:0}.accordion-icon{flex:0 0 auto;font-size:18px;transition-duration:.2s;transition-property:transform}.accordion-panel{overflow:hidden;padding:15px;color:#a9b1d6;font-size:13px;line-height:1.6;transition-duration:.28s;transition-timing-function:ease;transition-property:height,opacity,transform}.accordion-panel p{margin-top:0}.accordion-panel p:last-child{margin-bottom:0}.disclosure{max-width:520px;border:2px solid rgba(192,202,245,.24);background:#c0caf50b}.disclosure .accordion-summary{min-height:38px;padding:8px 12px}.disclosure .accordion-panel{padding:12px}.drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;display:flex;justify-content:flex-end;pointer-events:none}.drawer .drawer-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1010;background:#16161e;opacity:0;transition-duration:.28s;transition-timing-function:ease;transition-property:opacity;pointer-events:auto}.drawer .drawer-panel{position:relative;z-index:1020;width:min(460px,100vw - 18px);min-height:100vh;display:flex;flex-direction:column;gap:15px;background:#16161e;border-left:2px solid #C0CAF5;box-shadow:-18px 0 42px #16161e61;opacity:0;transform:translate(100%);transition-duration:.28s;transition-timing-function:ease;transition-property:opacity,transform;pointer-events:auto}.drawer .drawer-header{display:flex;align-items:center;justify-content:space-between;padding-right:15px;border-bottom:2px solid rgba(192,202,245,.24)}.drawer .drawer-title{margin:0;padding:12px 15px;background:#c0caf5;color:#16161e;text-transform:uppercase;letter-spacing:.04em}.drawer .drawer-body{flex:1;overflow-y:auto;padding:18px}.drawer .drawer-footer{padding:18px;border-top:2px solid rgba(192,202,245,.24)}.drawer .drawer-footer .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:12px;width:100%}.drawer.drawer-left{justify-content:flex-start}.drawer.drawer-left .drawer-panel{border-left:0;border-right:2px solid #C0CAF5;box-shadow:18px 0 42px #16161e61;transform:translate(-100%)}.drawer.a-show .drawer-backdrop{opacity:.82}.drawer.a-show .drawer-panel{opacity:1;transform:translate(0)}.drawer.a-hide .drawer-backdrop{opacity:0}.drawer.a-hide .drawer-panel{opacity:0;transform:translate(100%)}.drawer.a-hide.drawer-left .drawer-panel{transform:translate(-100%)}.drawer-preview{display:grid;grid-template-columns:minmax(0,1fr) minmax(180px,280px);gap:18px;align-items:stretch;padding:18px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;background:#c0caf50b}.drawer-preview .drawer-preview-content{display:flex;flex-direction:column;gap:12px}.drawer-preview .drawer-preview-panel{display:flex;flex-direction:column;gap:12px;padding:15px;border:2px solid #7AA2F7;background:#1f2335}.drawer-preview .drawer-preview-title{margin:0;color:#7aa2f7;font-size:14px;text-transform:uppercase}.drawer-preview .drawer-preview-text{margin:0;color:#a9b1d6;font-size:13px;line-height:1.6}@media(max-width:720px){.drawer-preview{grid-template-columns:1fr}}.toast{position:fixed;z-index:1100;bottom:-100px;right:15px;max-width:420px;background:#1f2335;border:2px solid #C0CAF5;border-left-width:6px;padding:0;opacity:0;transition-duration:.28s;transition-timing-function:ease;transition-property:opacity,top,bottom}.toast.a-show{bottom:15px;opacity:1}.toast.a-hide{bottom:115px;opacity:0}.toast .toast-content{display:flex;flex-direction:column;gap:0}.toast .toast-content .toast-title{min-height:38px;font-size:16px;display:flex;flex-direction:row;gap:8px;align-items:center;color:#16161e;background:#c0caf5;padding:8px 42px 8px 12px;text-transform:uppercase}.toast .toast-content .toast-text{font-size:13px;padding:22px 15px;margin:0}.toast .toast-close{position:absolute;top:0;right:0;color:#16161e;height:38px;width:38px;border-color:transparent}@media(hover:hover)and (pointer:fine){.toast .toast-close:hover{color:#16161e;background:#16161e1f;border-color:#16161e6b}}@media(hover:none)and (pointer:coarse){.toast .toast-close:active{color:#16161e;background:#16161e1f;border-color:#16161e6b}}.toast.toast-info{border-color:#bb9af7}.toast.toast-info .toast-title{background:#bb9af7}.toast.toast-success{border-color:#9ece6a}.toast.toast-success .toast-title{background:#9ece6a}.toast.toast-warning{border-color:#e0af68}.toast.toast-warning .toast-title{background:#e0af68}.toast.toast-danger{border-color:#f7768e}.toast.toast-danger .toast-title{background:#f7768e}.card{position:relative;max-width:340px;width:100%;overflow:hidden;background:#c0caf50b;border:2px solid #C0CAF5;transition-duration:.2s;transition-timing-function:ease;transition-property:border-color,background,box-shadow,transform}.card:after{content:"";position:absolute;inset:0 auto 0 0;width:34%;background:linear-gradient(90deg,transparent,rgba(192,202,245,.08),transparent);opacity:0;pointer-events:none;transform:translate(-120%)}.card .card-title{color:#16161e;background:#c0caf5;padding:8px 12px;font-weight:700;text-transform:uppercase}.card .card-content{padding:15px;height:100%}.card .card-content .card-thumb{display:block;width:min(68%,190px);margin:18px auto 22px;transition-duration:.2s;transition-timing-function:ease;transition-property:transform,filter}.card .card-content p{margin-top:8px;margin-bottom:0}.card .card-footer{padding:8px 15px 15px}@media(hover:hover)and (pointer:fine){.card:hover{border-color:#7aa2f7;background:#c0caf516;box-shadow:0 14px 32px #16161e57;transform:translateY(-2px)}.card:hover:after{opacity:1;animation:terminal_scan_x .85s ease}.card:hover .card-thumb{filter:saturate(1.12);transform:translateY(-2px)}}@media(hover:none)and (pointer:coarse){.card:active{border-color:#7aa2f7;background:#c0caf516;box-shadow:0 14px 32px #16161e57;transform:translateY(-2px)}.card:active:after{opacity:1;animation:terminal_scan_x .85s ease}.card:active .card-thumb{filter:saturate(1.12);transform:translateY(-2px)}}.card.status-card{max-width:220px;overflow:hidden;transition-duration:.2s;transition-property:border-color}.card.status-card .status-icon-container{position:relative}.card.status-card .status-icon-container .status-indicator{position:absolute;top:-15px;left:-5px;font-size:22px;color:#f7768e}.card.status-card .status-icon-container .status-indicator.status-online{color:#9ece6a}.card.status-card .status-icon-container .status-icon{display:flex;flex-direction:row;align-items:center;justify-content:center;font-size:56px;height:108px;width:100%;transition-duration:.2s;transition-property:color,transform}.card.status-card .card-title{display:flex;width:100%;font-size:14px;font-weight:700;align-items:center;flex-direction:row;flex-wrap:nowrap;justify-content:space-between;transition-duration:.2s;transition-property:background-color,color}.card.status-card .status-name{font-size:13px;line-height:1.4}@media(hover:hover)and (pointer:fine){.card.status-card:hover .status-icon{transform:translateY(-2px) scale(1.03)}}@media(hover:none)and (pointer:coarse){.card.status-card:active .status-icon{transform:translateY(-2px) scale(1.03)}}.card.status-card.card-success{border-color:#9ece6a}.card.status-card.card-success .card-title,.card.status-card.card-success .toast-title,.card.status-card.card-success .modal-title{color:#16161e;background:#9ece6a}.card.status-card.card-success .status-icon{color:#9ece6a}.card.status-card.card-warning{border-color:#e0af68}.card.status-card.card-warning .card-title,.card.status-card.card-warning .toast-title,.card.status-card.card-warning .modal-title{color:#16161e;background:#e0af68}.card.status-card.card-warning .status-icon{color:#e0af68}.card.status-card.card-info{border-color:#bb9af7}.card.status-card.card-info .card-title,.card.status-card.card-info .toast-title,.card.status-card.card-info .modal-title{color:#16161e;background:#bb9af7}.card.status-card.card-info .status-icon{color:#bb9af7}.card.status-card.card-secondary{border-color:#7aa2f7}.card.status-card.card-secondary .card-title,.card.status-card.card-secondary .toast-title,.card.status-card.card-secondary .modal-title{color:#16161e;background:#7aa2f7}.card.status-card.card-secondary .status-icon{color:#7aa2f7}.card.status-card.card-danger,.card.status-card.card-error{border-color:#f7768e}.card.status-card.card-danger .card-title,.card.status-card.card-danger .toast-title,.card.status-card.card-danger .modal-title,.card.status-card.card-error .card-title,.card.status-card.card-error .toast-title,.card.status-card.card-error .modal-title{color:#16161e;background:#f7768e}.card.status-card.card-danger .status-icon,.card.status-card.card-error .status-icon{color:#f7768e}.card.metric-card{max-width:320px;border-color:#c0caf53d}.card.metric-card .card-content{display:flex;flex-direction:column;gap:15px}.card.metric-card .metric-card-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.card.metric-card .metric-card-label{margin:0;color:#a9b1d6;font-size:13px;font-weight:600;text-transform:uppercase}.card.metric-card .metric-card-icon{display:inline-flex;align-items:center;justify-content:center;width:46px;height:46px;color:#16161e;background:#7aa2f7;font-size:22px;transition-duration:.2s;transition-timing-function:ease;transition-property:background,transform}.card.metric-card .metric-card-value{margin:0;color:#c0caf5;font-size:34px;font-weight:700;line-height:1.15}.card.metric-card .metric-card-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px;color:#787c99;font-size:13px}.card.metric-card .metric-card-delta{color:#9ece6a;font-weight:700}.card.metric-card .metric-card-delta.metric-card-delta-negative{color:#f7768e}@media(hover:hover)and (pointer:fine){.card.metric-card:hover .metric-card-icon{background:#c0caf5;transform:translateY(-2px)}}@media(hover:none)and (pointer:coarse){.card.metric-card:active .metric-card-icon{background:#c0caf5;transform:translateY(-2px)}}.card.action-card{max-width:360px;border-color:#7aa2f7}.card.action-card .card-content{display:flex;flex-direction:column;gap:15px}.card.action-card .action-card-kicker{display:inline-flex;width:max-content;padding:5px 8px;color:#16161e;background:#7aa2f7;font-size:12px;font-weight:700;line-height:1;text-transform:uppercase;transition-duration:.2s;transition-timing-function:ease;transition-property:background,transform}.card.action-card .action-card-title{margin:0;font-size:20px;font-weight:700;line-height:1.25;text-transform:uppercase}.card.action-card .action-card-text{margin:0;color:#a9b1d6;font-size:13px;line-height:1.6}.card.action-card .action-card-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}@media(hover:hover)and (pointer:fine){.card.action-card:hover .action-card-kicker{background:#c0caf5;transform:translate(5px)}}@media(hover:none)and (pointer:coarse){.card.action-card:active .action-card-kicker{background:#c0caf5;transform:translate(5px)}}.modal{position:fixed;top:0;bottom:0;left:0;right:0;z-index:1000;display:flex;flex-direction:column;align-items:center;justify-content:center}.modal .modal-backdrop{position:fixed;z-index:1010;top:0;bottom:0;left:0;right:0;background:#16161e;opacity:0;transition-duration:.25s;transition-property:opacity}.modal .modal-panel{position:relative;z-index:1020;width:100%;max-width:960px;margin:200px 18px 18px;height:auto;min-height:200px;max-height:calc(100vh - 48px);padding:0;display:flex;flex-direction:column;gap:15px;background:#16161e;border:2px solid #C0CAF5;border-left-width:6px;opacity:0;transition-duration:.28s;transition-timing-function:ease;transition-property:opacity,margin-top}.modal .modal-panel .modal-header{display:flex;flex-direction:row;justify-content:space-between;align-items:center;padding-right:15px}.modal .modal-panel .modal-header .modal-title{padding:12px 15px;background:#c0caf5;color:#16161e;text-transform:uppercase;letter-spacing:.04em}.modal .modal-panel .modal-body{max-height:700px;overflow-y:auto;padding:18px}.modal .modal-panel .modal-footer{padding:18px}.modal .modal-panel .modal-footer .actions{display:flex;flex-direction:row;justify-content:flex-end;gap:15px;width:100%}.modal.a-show .modal-backdrop{opacity:1}.modal.a-show .modal-panel{opacity:1;margin-top:0}.modal.a-hide .modal-backdrop{opacity:0}.modal.a-hide .modal-panel{opacity:0;margin-top:-200px}.alert{position:relative;overflow:hidden;margin-bottom:12px;padding:12px 15px;border:2px solid transparent;border-left-style:solid;border-left-width:6px;background:#c0caf50b;color:#c0caf5;font-weight:500;line-height:1.4;transition-duration:.2s;transition-timing-function:ease;transition-property:background,color,border-color}.alert:after{content:"";position:absolute;inset:0 auto 0 0;width:36%;background:linear-gradient(90deg,transparent,rgba(192,202,245,.12),transparent);opacity:0;pointer-events:none;transform:translate(-120%)}@media(hover:hover)and (pointer:fine){.alert:hover:after{opacity:1;animation:terminal_scan_x .8s ease}}@media(hover:none)and (pointer:coarse){.alert:active:after{opacity:1;animation:terminal_scan_x .8s ease}}.alert.alert-primary{border-color:#c0caf5;background:#c0caf51a;color:#c0caf5}.alert.alert-success{border-color:#9ece6a;background:#9ece6a1a;color:#9ece6a}.alert.alert-secondary{border-color:#7aa2f7;background:#7aa2f71a;color:#7aa2f7}.alert.alert-info{border-color:#bb9af7;background:#bb9af71a;color:#c0caf5}.alert.alert-warning{border-color:#e0af68;background:#e0af681a;color:#e0af68}.alert.alert-error,.alert.alert-danger{border-color:#f7768e;background:#f7768e1a;color:#f7768e}.advanced-select-container{position:relative;height:0}.advanced-select{position:absolute;z-index:100;top:6px;width:100%;height:auto;max-height:200px;overflow-y:auto;background:#16161e;border:2px solid #C0CAF5;border-left-width:6px;margin-top:20px;opacity:0;visibility:hidden;transition-property:opacity,margin-top,visibility;transition-duration:.2s;transition-timing-function:ease}.advanced-select.a-show{opacity:1;margin-top:0;visibility:visible}.advanced-select .popup-options-container .not-found{width:100%;padding:15px;text-align:center;display:none}.advanced-select .popup-options-container .not-found.show{display:block}.advanced-select .popup-options-container .options{width:100%;display:none}.advanced-select .popup-options-container .options.show{display:block}.advanced-select .popup-options-container .options .option{padding:8px 15px;transition-property:color,background;transition-duration:.15s}.advanced-select .popup-options-container .options .option.hide{display:none}.advanced-select .popup-options-container .options .option:hover,.advanced-select .popup-options-container .options .option.focus{color:#16161e;background:#e0af68}.component.editable-string-component .editable-string-content{display:flex;flex-direction:row;align-items:center;gap:8px;font-size:inherit}.component.editable-string-component .editable-string-content .editable-string{font-size:inherit;border-bottom:2px solid rgba(192,202,245,.24)}@media(hover:hover)and (pointer:fine){.component.editable-string-component .edit-text-btn:hover,.component.editable-string-component .apply-changes-btn:hover,.component.editable-string-component .cancel-changes-btn:hover{color:#16161e;background:#e0af68}}@media(hover:none)and (pointer:coarse){.component.editable-string-component .edit-text-btn:active,.component.editable-string-component .apply-changes-btn:active,.component.editable-string-component .cancel-changes-btn:active{color:#16161e;background:#e0af68}}.component.editable-string-component .apply-changes-btn{color:#e0af68}.component.editable-string-component .editable-string-form{display:flex;flex-direction:row;align-items:center;gap:8px}.component.editable-string-component .editable-string-form .form-group{max-width:260px;margin:0}.component.editable-string-component .editable-string-form .form-group .input{padding:8px 15px}.tabs{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:15px}.tabs .tab{display:inline-flex;align-items:center;min-height:38px;padding:8px 12px;border:2px solid rgba(192,202,245,.24);border-left-width:6px;color:#a9b1d6;background:#c0caf50b;font-family:IBM Plex Mono,monospace;font-size:13px;font-weight:600;line-height:1;text-transform:uppercase;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background,border-color}.tabs .tab:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){.tabs .tab:hover{color:#16161e;background:#7aa2f7;border-color:#7aa2f7}}@media(hover:none)and (pointer:coarse){.tabs .tab:active{color:#16161e;background:#7aa2f7;border-color:#7aa2f7}}.tabs .tab.tab-active,.tabs .tab[aria-selected=true]{color:#16161e;background:#c0caf5;border-color:#c0caf5}.dropdown,.popover{position:relative;display:inline-flex}.dropdown-menu,.popover-panel,.tooltip-panel{z-index:40;background:#1f2335;border:2px solid rgba(192,202,245,.24);border-left-width:6px;box-shadow:0 14px 36px #16161e5c}.dropdown-menu,.popover-panel{position:absolute;top:calc(100% + 8px);left:0;min-width:220px;display:none;transform-origin:top left}.dropdown.is-open .dropdown-menu,.popover.is-open .popover-panel{display:block;animation:overlay_reveal .2s ease both}.dropdown-menu{padding:5px}.dropdown-menu .dropdown-item{display:flex;align-items:center;gap:8px;width:100%;min-height:38px;padding:8px 12px;border:0;color:#c0caf5;background:transparent;font-family:IBM Plex Mono,monospace;font-size:13px;text-align:left;cursor:pointer;transition-duration:.2s;transition-timing-function:ease;transition-property:color,background}.dropdown-menu .dropdown-item .ph,.dropdown-menu .dropdown-item .ph-bold{font-size:18px}.dropdown-menu .dropdown-item:focus-visible{outline:2px solid #E0AF68;outline-offset:3px}@media(hover:hover)and (pointer:fine){.dropdown-menu .dropdown-item:hover{color:#16161e;background:#7aa2f7}}@media(hover:none)and (pointer:coarse){.dropdown-menu .dropdown-item:active{color:#16161e;background:#7aa2f7}}.dropdown-menu .dropdown-item.dropdown-item-danger{color:#f7768e}@media(hover:hover)and (pointer:fine){.dropdown-menu .dropdown-item.dropdown-item-danger:hover{color:#16161e;background:#f7768e}}@media(hover:none)and (pointer:coarse){.dropdown-menu .dropdown-item.dropdown-item-danger:active{color:#16161e;background:#f7768e}}.popover-panel{width:min(320px,100vw - 22px);padding:15px}.popover-panel .popover-title{margin:0 0 8px;font-size:14px;font-weight:700;text-transform:uppercase}.popover-panel .popover-text{margin:0;color:#a9b1d6;font-size:13px;line-height:1.6}.tooltip{position:relative;display:inline-flex}.tooltip-panel{position:absolute;left:50%;bottom:calc(100% + 8px);width:max-content;max-width:260px;padding:8px 12px;color:#c0caf5;font-size:12px;line-height:1.4;transform:translate(-50%);opacity:0;visibility:hidden;pointer-events:none;transition-duration:.15s;transition-timing-function:ease;transition-property:opacity,visibility}.tooltip:hover .tooltip-panel,.tooltip:focus-within .tooltip-panel,.tooltip.is-open .tooltip-panel{opacity:1;visibility:visible;animation:tooltip_reveal .15s ease both}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.g-0{gap:0!important}.gx-0{column-gap:0!important}.gy-0{row-gap:0!important}.m-1{margin:5px!important}.mt-1{margin-top:5px!important}.mr-1{margin-right:5px!important}.mb-1{margin-bottom:5px!important}.ml-1{margin-left:5px!important}.mx-1{margin-left:5px!important;margin-right:5px!important}.my-1{margin-top:5px!important;margin-bottom:5px!important}.p-1{padding:5px!important}.pt-1{padding-top:5px!important}.pr-1{padding-right:5px!important}.pb-1{padding-bottom:5px!important}.pl-1{padding-left:5px!important}.px-1{padding-left:5px!important;padding-right:5px!important}.py-1{padding-top:5px!important;padding-bottom:5px!important}.g-1{gap:5px!important}.gx-1{column-gap:5px!important}.gy-1{row-gap:5px!important}.m-2{margin:8px!important}.mt-2{margin-top:8px!important}.mr-2{margin-right:8px!important}.mb-2{margin-bottom:8px!important}.ml-2{margin-left:8px!important}.mx-2{margin-left:8px!important;margin-right:8px!important}.my-2{margin-top:8px!important;margin-bottom:8px!important}.p-2{padding:8px!important}.pt-2{padding-top:8px!important}.pr-2{padding-right:8px!important}.pb-2{padding-bottom:8px!important}.pl-2{padding-left:8px!important}.px-2{padding-left:8px!important;padding-right:8px!important}.py-2{padding-top:8px!important;padding-bottom:8px!important}.g-2{gap:8px!important}.gx-2{column-gap:8px!important}.gy-2{row-gap:8px!important}.m-3{margin:12px!important}.mt-3{margin-top:12px!important}.mr-3{margin-right:12px!important}.mb-3{margin-bottom:12px!important}.ml-3{margin-left:12px!important}.mx-3{margin-left:12px!important;margin-right:12px!important}.my-3{margin-top:12px!important;margin-bottom:12px!important}.p-3{padding:12px!important}.pt-3{padding-top:12px!important}.pr-3{padding-right:12px!important}.pb-3{padding-bottom:12px!important}.pl-3{padding-left:12px!important}.px-3{padding-left:12px!important;padding-right:12px!important}.py-3{padding-top:12px!important;padding-bottom:12px!important}.g-3{gap:12px!important}.gx-3{column-gap:12px!important}.gy-3{row-gap:12px!important}.m-4{margin:15px!important}.mt-4{margin-top:15px!important}.mr-4{margin-right:15px!important}.mb-4{margin-bottom:15px!important}.ml-4{margin-left:15px!important}.mx-4{margin-left:15px!important;margin-right:15px!important}.my-4{margin-top:15px!important;margin-bottom:15px!important}.p-4{padding:15px!important}.pt-4{padding-top:15px!important}.pr-4{padding-right:15px!important}.pb-4{padding-bottom:15px!important}.pl-4{padding-left:15px!important}.px-4{padding-left:15px!important;padding-right:15px!important}.py-4{padding-top:15px!important;padding-bottom:15px!important}.g-4{gap:15px!important}.gx-4{column-gap:15px!important}.gy-4{row-gap:15px!important}.m-5{margin:18px!important}.mt-5{margin-top:18px!important}.mr-5{margin-right:18px!important}.mb-5{margin-bottom:18px!important}.ml-5{margin-left:18px!important}.mx-5{margin-left:18px!important;margin-right:18px!important}.my-5{margin-top:18px!important;margin-bottom:18px!important}.p-5{padding:18px!important}.pt-5{padding-top:18px!important}.pr-5{padding-right:18px!important}.pb-5{padding-bottom:18px!important}.pl-5{padding-left:18px!important}.px-5{padding-left:18px!important;padding-right:18px!important}.py-5{padding-top:18px!important;padding-bottom:18px!important}.g-5{gap:18px!important}.gx-5{column-gap:18px!important}.gy-5{row-gap:18px!important}.m-6{margin:22px!important}.mt-6{margin-top:22px!important}.mr-6{margin-right:22px!important}.mb-6{margin-bottom:22px!important}.ml-6{margin-left:22px!important}.mx-6{margin-left:22px!important;margin-right:22px!important}.my-6{margin-top:22px!important;margin-bottom:22px!important}.p-6{padding:22px!important}.pt-6{padding-top:22px!important}.pr-6{padding-right:22px!important}.pb-6{padding-bottom:22px!important}.pl-6{padding-left:22px!important}.px-6{padding-left:22px!important;padding-right:22px!important}.py-6{padding-top:22px!important;padding-bottom:22px!important}.g-6{gap:22px!important}.gx-6{column-gap:22px!important}.gy-6{row-gap:22px!important}.m-7{margin:26px!important}.mt-7{margin-top:26px!important}.mr-7{margin-right:26px!important}.mb-7{margin-bottom:26px!important}.ml-7{margin-left:26px!important}.mx-7{margin-left:26px!important;margin-right:26px!important}.my-7{margin-top:26px!important;margin-bottom:26px!important}.p-7{padding:26px!important}.pt-7{padding-top:26px!important}.pr-7{padding-right:26px!important}.pb-7{padding-bottom:26px!important}.pl-7{padding-left:26px!important}.px-7{padding-left:26px!important;padding-right:26px!important}.py-7{padding-top:26px!important;padding-bottom:26px!important}.g-7{gap:26px!important}.gx-7{column-gap:26px!important}.gy-7{row-gap:26px!important}.m-8{margin:34px!important}.mt-8{margin-top:34px!important}.mr-8{margin-right:34px!important}.mb-8{margin-bottom:34px!important}.ml-8{margin-left:34px!important}.mx-8{margin-left:34px!important;margin-right:34px!important}.my-8{margin-top:34px!important;margin-bottom:34px!important}.p-8{padding:34px!important}.pt-8{padding-top:34px!important}.pr-8{padding-right:34px!important}.pb-8{padding-bottom:34px!important}.pl-8{padding-left:34px!important}.px-8{padding-left:34px!important;padding-right:34px!important}.py-8{padding-top:34px!important;padding-bottom:34px!important}.g-8{gap:34px!important}.gx-8{column-gap:34px!important}.gy-8{row-gap:34px!important}.m-9{margin:42px!important}.mt-9{margin-top:42px!important}.mr-9{margin-right:42px!important}.mb-9{margin-bottom:42px!important}.ml-9{margin-left:42px!important}.mx-9{margin-left:42px!important;margin-right:42px!important}.my-9{margin-top:42px!important;margin-bottom:42px!important}.p-9{padding:42px!important}.pt-9{padding-top:42px!important}.pr-9{padding-right:42px!important}.pb-9{padding-bottom:42px!important}.pl-9{padding-left:42px!important}.px-9{padding-left:42px!important;padding-right:42px!important}.py-9{padding-top:42px!important;padding-bottom:42px!important}.g-9{gap:42px!important}.gx-9{column-gap:42px!important}.gy-9{row-gap:42px!important}.m-10{margin:48px!important}.mt-10{margin-top:48px!important}.mr-10{margin-right:48px!important}.mb-10{margin-bottom:48px!important}.ml-10{margin-left:48px!important}.mx-10{margin-left:48px!important;margin-right:48px!important}.my-10{margin-top:48px!important;margin-bottom:48px!important}.p-10{padding:48px!important}.pt-10{padding-top:48px!important}.pr-10{padding-right:48px!important}.pb-10{padding-bottom:48px!important}.pl-10{padding-left:48px!important}.px-10{padding-left:48px!important;padding-right:48px!important}.py-10{padding-top:48px!important;padding-bottom:48px!important}.g-10{gap:48px!important}.gx-10{column-gap:48px!important}.gy-10{row-gap:48px!important}.m-11{margin:64px!important}.mt-11{margin-top:64px!important}.mr-11{margin-right:64px!important}.mb-11{margin-bottom:64px!important}.ml-11{margin-left:64px!important}.mx-11{margin-left:64px!important;margin-right:64px!important}.my-11{margin-top:64px!important;margin-bottom:64px!important}.p-11{padding:64px!important}.pt-11{padding-top:64px!important}.pr-11{padding-right:64px!important}.pb-11{padding-bottom:64px!important}.pl-11{padding-left:64px!important}.px-11{padding-left:64px!important;padding-right:64px!important}.py-11{padding-top:64px!important;padding-bottom:64px!important}.g-11{gap:64px!important}.gx-11{column-gap:64px!important}.gy-11{row-gap:64px!important}.m-12{margin:80px!important}.mt-12{margin-top:80px!important}.mr-12{margin-right:80px!important}.mb-12{margin-bottom:80px!important}.ml-12{margin-left:80px!important}.mx-12{margin-left:80px!important;margin-right:80px!important}.my-12{margin-top:80px!important;margin-bottom:80px!important}.p-12{padding:80px!important}.pt-12{padding-top:80px!important}.pr-12{padding-right:80px!important}.pb-12{padding-bottom:80px!important}.pl-12{padding-left:80px!important}.px-12{padding-left:80px!important;padding-right:80px!important}.py-12{padding-top:80px!important;padding-bottom:80px!important}.g-12{gap:80px!important}.gx-12{column-gap:80px!important}.gy-12{row-gap:80px!important}.row{display:flex;flex-direction:row}@media(max-width:1279px){.row.adaptive{flex-direction:column}}.column{display:flex;flex-direction:column}.f-grid{display:flex;flex-direction:row;flex-wrap:wrap}.grid{display:grid}.grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}.items-start{align-items:flex-start!important}.items-center{align-items:center!important}.items-end{align-items:flex-end!important}.justify-start{justify-content:flex-start!important}.justify-center{justify-content:center!important}.justify-between{justify-content:space-between!important}.justify-end{justify-content:flex-end!important}.w-100{width:100%}.w-auto{width:auto!important}.w-fit{width:fit-content!important}.w-200{width:200%}.h-100{height:100%}.min-w-0{min-width:0!important}.overflow-hidden{overflow:hidden!important}.overflow-auto{overflow:auto!important}.fs-xs{font-size:12px}.fs-sm{font-size:13px}.fs-md{font-size:14px}.fs-base{font-size:15px}.fs-lg{font-size:16px}.fs-xl{font-size:20px}.text-left{text-align:left!important}.text-center{text-align:center!important}.text-right{text-align:right!important}.text-uppercase{text-transform:uppercase!important}.text-nowrap{white-space:nowrap!important}.d-none{display:none!important}.d-block{display:block!important}.d-inline-flex{display:inline-flex!important}.d-flex{display:flex!important}.d-grid{display:grid!important}@media(max-width:767px){.grid-2,.grid-3{grid-template-columns:1fr}}*{box-sizing:border-box}html,body{padding:0;margin:0}body{background-color:#16161e;color:#c0caf5}*::-webkit-scrollbar-corner{background:transparent;height:1px}.ph.normalize{position:relative;top:.15em}html,body{height:100%}*::-webkit-scrollbar{width:10px}*::-webkit-scrollbar-track{width:10px;background:#16161e;cursor:pointer}*::-webkit-scrollbar-thumb{width:10px;background:#414868;cursor:default}*::-webkit-scrollbar-corner{background:transparent}*::-webkit-scrollbar-button{display:none}#app{display:flex;height:100vh;height:100dvh;overflow:hidden}.app-main{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:#16161e}.app-sidebar{width:380px;min-width:380px;max-width:380px;display:flex;flex-direction:column;background:#1f2335;border-right:2px solid rgba(192,202,245,.24);overflow:hidden;flex-shrink:0;transition:width .22s ease,min-width .22s ease,max-width .22s ease,border-color .22s ease,transform .28s ease}.app-sidebar.is-hidden-by-artifacts{width:0;min-width:0;max-width:0;border-right-color:transparent}@media(max-width:1280px){.app-sidebar{position:fixed;top:0;right:0;bottom:0;left:0;z-index:100;width:min(380px,92vw)!important;min-width:min(380px,92vw)!important;transform:translate(-100%);transition:transform .28s ease}.app-sidebar.is-mobile-open{transform:translate(0)}.app-sidebar.is-hidden-by-artifacts{width:min(380px,92vw)!important;min-width:min(380px,92vw)!important;max-width:min(380px,92vw)!important;border-right-color:#c0caf53d}}@media(max-width:980px){.app-sidebar,.app-sidebar.is-hidden-by-artifacts{width:100vw!important;min-width:100vw!important;max-width:100vw!important}}.sidebar-header{padding:15px;border-bottom:2px solid rgba(192,202,245,.24);display:flex;flex-direction:column;gap:8px}.sidebar-controls-row{display:flex;align-items:center;gap:8px}.sidebar-controls-row .sidebar-profile-select{flex:1;min-width:0}.sidebar-logo{display:flex;align-items:center;gap:8px;text-decoration:none}.sidebar-logo img{width:28px;height:28px}.sidebar-logo span{font-size:18px;font-weight:700;color:#c0caf5;letter-spacing:-.3px}.sidebar-sessions{flex:1;overflow:hidden;display:flex;flex-direction:column}.sessions-label{padding:8px 15px;font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:#787c99}.sidebar-profile-select{position:relative}.sidebar-profile-select select{width:100%;-moz-appearance:none;appearance:none;-webkit-appearance:none;min-height:46px;font-family:inherit;font-size:13px;font-weight:500;padding:5px 34px 5px 15px;border:2px solid rgba(192,202,245,.24);border-bottom-width:6px;border-bottom-color:#c0caf5;color:#c0caf5;background-color:#c0caf50b;cursor:pointer;transition:border-color .2s ease,background-color .2s ease;outline:none}.sidebar-profile-select select:hover{border-bottom-color:#787c99}.sidebar-profile-select select:focus{outline:2px solid #E0AF68;outline-offset:3px;border-color:#7aa2f7;background-color:transparent}.sidebar-profile-select select option{background:#1f2335;color:#c0caf5}.sidebar-profile-select:after{content:"";position:absolute;right:15px;top:50%;transform:translateY(-50%);width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid #A9B1D6;pointer-events:none}.session-item{display:flex;align-items:flex-start;gap:8px;padding:8px 15px;cursor:pointer;border-radius:0;transition:background .15s ease;position:relative}.session-item:hover{background:#c0caf50b}.session-item:hover .session-actions{opacity:1}@media(hover:none){.session-item .session-actions{opacity:1}}.session-item.is-active{background:#c0caf516;border-left:6px solid #7AA2F7;padding-left:9px}.session-item.is-pinned{background:#e0af6812}.session-item.is-pinned .session-pin-icon{opacity:1;color:#e0af68}.session-item.is-pinned .session-name{color:#e0af68}.session-pin-icon{color:#787c99;font-size:14px;opacity:0;transition:opacity .15s ease;flex-shrink:0;margin-top:2px}.session-info{flex:1;overflow:hidden}.session-name{font-size:13px;color:#a9b1d6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.4}.session-time{font-size:11px;color:#787c99;line-height:1.4;margin-top:2px}.session-preview{font-size:12px;color:#c0caf5;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;line-height:1.4;margin-top:3px}.session-actions{display:flex;gap:2px;opacity:0;transition:opacity .15s ease;flex-shrink:0;align-self:flex-start;margin-top:1px}.session-actions .btn-icon{width:26px;height:26px;font-size:14px}.chat-area{flex:1 1 0;min-height:0;min-width:0;display:flex;flex-direction:column;overflow:hidden;background:#16161e}.chat-header{display:flex;align-items:center;gap:8px;padding:8px 15px;border-bottom:2px solid rgba(192,202,245,.24);background:#1f2335;flex-shrink:0;min-height:54px}.chat-header-info{flex:1;display:flex;align-items:center;gap:8px;overflow:hidden;min-width:0}@media(max-width:768px){.chat-header-info{flex-direction:column;align-items:flex-start;gap:2px}}.chat-header-title{font-size:14px;font-weight:600;color:#c0caf5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.btn-sidebar-toggle{display:none}@media(max-width:1280px){.btn-sidebar-toggle{display:flex}}.context-bar{display:flex;align-items:center;flex-shrink:0;cursor:default}.profile-badge{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;background:#c0caf50b;border:2px solid rgba(192,202,245,.24);font-size:12px;color:#a9b1d6;white-space:nowrap}.message-list{flex:1;overflow-y:auto;overflow-x:hidden;padding:22px 15px;display:flex;flex-direction:column;gap:15px;min-height:0}@media(max-width:768px){.message-list{padding-left:10px;padding-right:10px}}.message-list .vue-recycle-scroller{flex:1}.message-list-inner{display:flex;flex-direction:column;gap:34px;width:100%;max-width:920px;margin:0 auto;padding:34px 22px;transition:opacity .2s ease}@media(max-width:768px){.message-list-inner{padding-left:0;padding-right:0}}.message-list-inner.is-hidden{opacity:0;pointer-events:none}.msg-user{display:flex;justify-content:flex-end;gap:8px}.msg-user-bubble{background:#7aa2f7;color:#16161e;padding:8px 15px;font-size:14px;line-height:1.6;word-wrap:break-word;width:100%}.msg-user-bubble .msg-user-quote{margin:0 0 5px;padding:2px 0 2px 8px;border-left:3px solid rgba(22,22,30,.35);opacity:.7;font-size:13px}.msg-user-attachments{display:flex;flex-wrap:wrap;gap:5px;margin-top:5px}.msg-user-image{width:80px;height:80px;object-fit:cover;cursor:pointer;transition:opacity .15s}.msg-user-image:hover{opacity:.75}.msg-user-file-pill{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;background:#16161e4d;font-size:12px}.msg-time{font-size:11px;color:#787c99;line-height:1;margin-top:4px}.msg-meta-row{display:flex;align-items:center;gap:8px;margin-top:2px;min-width:0}.msg-meta-item{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:#787c99;white-space:nowrap}.msg-meta-item i{font-size:12px;opacity:.7}.msg-user-wrap{display:flex;flex-direction:column;align-items:flex-end;max-width:70%}@media(max-width:768px){.msg-user-wrap{max-width:90%}}.msg-user-footer{display:flex;align-items:center;gap:5px;align-self:flex-end}.msg-copy-btn{width:22px;height:22px;min-width:22px;padding:0;font-size:12px;opacity:.5;transition:opacity .15s}.msg-copy-btn:hover{opacity:1}.msg-meta-row>.msg-copy-btn{margin-left:auto}.msg-meta-row .msg-rate-btn{width:22px;height:22px;min-width:22px;padding:0;font-size:13px}.msg-assistant{display:flex;flex-direction:column;gap:8px;max-width:100%}.planning-indicator{display:flex;align-items:center;gap:8px;font-size:13px;font-style:italic;color:#787c99;padding:5px 0}.planning-indicator.is-executing{color:#a9b1d6;font-style:normal}.planning-label{opacity:.75;transition:opacity .2s}.msg-assistant-avatar{width:28px;height:28px;border-radius:50%;flex-shrink:0}.msg-assistant-content{font-size:14px;line-height:1.7;color:#c0caf5}.msg-assistant-content p{margin:0 0 15px}.msg-assistant-content p:last-child{margin-bottom:0}.msg-assistant-content h1,.msg-assistant-content h2,.msg-assistant-content h3,.msg-assistant-content h4{margin:22px 0 8px;color:#c0caf5}.msg-assistant-content ul,.msg-assistant-content ol{padding-left:22px;margin-bottom:15px}.msg-assistant-content li{margin-bottom:8px}.msg-assistant-content blockquote{margin:8px 0;padding-left:15px;border-left:6px solid #7AA2F7;color:#a9b1d6}.msg-assistant-content a{color:#7aa2f7}.msg-assistant-content strong{color:#c0caf5}.msg-assistant-content hr{border:none;border-top:1px solid rgba(192,202,245,.24);margin:15px 0}.msg-assistant-content .table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:15px 0}.msg-assistant-content .table{margin:15px 0}.msg-assistant-content .table thead{border-bottom:2px solid #C0CAF5}.msg-assistant-content .table tbody tr{transition:background .2s ease}.msg-assistant-content .table tbody tr:hover{background:#7aa2f714}.msg-assistant-content .table tbody tr:hover td:first-child{color:#7aa2f7}.msg-assistant-content .table tr th,.msg-assistant-content .table tr td{padding:8px 15px;font-size:13px;vertical-align:middle;border-bottom:2px solid rgba(192,202,245,.08)}.msg-assistant-content .table tr th{color:#c0caf5;background:#c0caf50a;text-transform:uppercase;letter-spacing:.06em}.msg-assistant-content :not(pre)>code{font-family:IBM Plex Mono,monospace;font-size:13px;background:#c0caf516;padding:1px 5px;color:#7dcfff}.msg-assistant-content .code-block{margin:15px 0;background:#1f2335;border:2px solid rgba(192,202,245,.24);overflow:hidden}.msg-assistant-content .code-block .code-header{display:flex;align-items:center;justify-content:space-between;padding:5px 15px;background:#c0caf516;border-bottom:2px solid rgba(192,202,245,.24);font-size:12px;color:#787c99;font-family:IBM Plex Mono,monospace}.msg-assistant-content .code-block pre{margin:0;background:#1f2335!important}.msg-assistant-content .code-block pre code{font-family:IBM Plex Mono,monospace;font-size:13px;display:block;padding:15px;overflow-x:auto}.thinking-card{margin-bottom:8px}.thinking-card summary{list-style:none;display:flex;align-items:center;gap:8px;padding:8px 15px;cursor:pointer;color:#787c99;font-size:13px;font-style:italic;background:#c0caf50b;border:2px solid rgba(192,202,245,.24);transition:background .15s ease;-webkit-user-select:none;user-select:none}.thinking-card summary::-webkit-details-marker{display:none}.thinking-card summary:hover{background:#c0caf516}.thinking-card[open] summary{border-bottom-color:transparent}.thinking-card .thinking-chevron{margin-left:auto;font-size:18px;color:#787c99;flex-shrink:0;transition:transform .15s ease}.thinking-card[open] .thinking-chevron{transform:rotate(180deg)}.thinking-card .thinking-body{padding:15px;font-size:13px;font-style:italic;color:#a9b1d6;line-height:1.6;background:#c0caf50b;border:2px solid rgba(192,202,245,.24);border-top:none;white-space:pre-wrap}.plan-card{border:2px solid #BB9AF7;border-left-width:6px;border-left-color:#bb9af7;overflow:hidden;font-size:13px;margin-bottom:8px}.plan-card summary{list-style:none;display:flex;align-items:center;gap:8px;padding:8px 15px;cursor:pointer;background:#bb9af714;color:#bb9af7;font-size:13px;-webkit-user-select:none;user-select:none}.plan-card summary::-webkit-details-marker{display:none}.plan-card summary:hover{background:#bb9af724}.plan-card summary .plan-chevron{margin-left:auto;font-size:18px;color:#bb9af799;transition:transform .15s ease;flex-shrink:0}.plan-card[open] .plan-chevron{transform:rotate(180deg)}.plan-card .plan-body{padding:15px;font-size:13px;color:#a9b1d6;line-height:1.6;background:#bb9af70a;border-top:2px solid rgba(187,154,247,.3)}.plan-card .plan-body p{margin:0 0 8px}.plan-card .plan-body p:last-child{margin-bottom:0}.plan-card .plan-body ul,.plan-card .plan-body ol{padding-left:22px;margin-bottom:8px}.plan-card .plan-body li{margin-bottom:5px}.plan-card .plan-body strong{color:#c0caf5}.tool-card{border:2px solid rgba(192,202,245,.24);border-left-width:6px;margin-bottom:8px;border-left-color:#7aa2f7;overflow:hidden;font-size:13px}.tool-card.is-success{border-left-color:#9ece6a}.tool-card.is-error{border-left-color:#f7768e}.tool-card summary{list-style:none;display:flex;align-items:center;gap:8px;padding:8px 15px;cursor:pointer;background:#c0caf50b;color:#a9b1d6;-webkit-user-select:none;user-select:none}.tool-card summary::-webkit-details-marker{display:none}.tool-card summary:hover{background:#c0caf516}.tool-card .tool-name{flex:1;font-family:IBM Plex Mono,monospace;font-size:12px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool-card .tool-running-time{font-family:IBM Plex Mono,monospace;font-size:11px;color:#787c99;white-space:nowrap}.tool-card .tool-status-icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;font-size:18px;flex-shrink:0}.tool-card .tool-emoji{font-size:18px;line-height:1;flex-shrink:0}.tool-card .tool-chevron{font-size:18px;color:#787c99;flex-shrink:0;transition:transform .15s ease}.tool-card[open] .tool-chevron{transform:rotate(180deg)}.tool-card-body{background:#c0caf50b;border-top:2px solid rgba(192,202,245,.24)}.tool-running-banner{display:flex;align-items:center;gap:8px;padding:8px 15px;color:#a9b1d6;background:#7aa2f714;border-bottom:1px solid rgba(192,202,245,.24);font-size:12px}.tool-section{padding:8px 15px}.tool-section+.tool-section{border-top:1px solid rgba(192,202,245,.24)}.tool-section-label{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#787c99;margin-bottom:5px}.tool-code{font-family:IBM Plex Mono,monospace;font-size:12px;color:#a9b1d6;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto}.subagent-steps{display:flex;flex-direction:column;gap:5px;padding:5px 15px 15px;background:#c0caf50b}.subagent-planning-indicator{display:flex;align-items:center;gap:8px;padding:5px 15px;font-size:12px;font-style:italic;color:#787c99;background:#c0caf50b}.summary-card{border:2px solid #BB9AF7;overflow:hidden;font-size:13px}.summary-card summary{list-style:none;display:flex;align-items:center;gap:8px;padding:8px 15px;cursor:pointer;background:#bb9af714;color:#bb9af7;-webkit-user-select:none;user-select:none}.summary-card summary::-webkit-details-marker{display:none}.compression-notice{font-size:12px}.compression-notice summary{list-style:none;text-align:center;padding:8px;color:#787c99;display:flex;align-items:center;justify-content:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none}.compression-notice summary::-webkit-details-marker{display:none}.compression-notice summary:before,.compression-notice summary:after{content:"";flex:1;height:1px;background:#c0caf53d}.compression-notice .compression-counts{opacity:.7}.compression-notice .compression-chevron{font-size:18px;transition:transform .15s ease}.compression-notice[open] .compression-chevron{transform:rotate(180deg)}.compression-notice .compression-body{padding:15px;font-size:13px;color:#a9b1d6;line-height:1.6;background:#c0caf50b;border:2px solid rgba(192,202,245,.24)}.input-bar{flex-shrink:0;padding:8px 15px 15px;background:#16161e;border-top:2px solid rgba(192,202,245,.24)}.input-dropzone{position:relative}.input-dropzone.is-dragging:after{content:"Drop files here";position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#7aa2f71f;border:2px dashed #7AA2F7;font-size:14px;color:#7aa2f7;pointer-events:none;z-index:10}.file-preview-strip{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:5px}.file-preview-image{position:relative;width:60px;height:60px}.file-preview-image img{width:100%;height:100%;object-fit:cover;border:2px solid rgba(192,202,245,.24)}.file-preview-pill{display:inline-flex;align-items:center;gap:5px;padding:5px 8px;background:#c0caf50b;border:2px solid rgba(192,202,245,.24);font-size:12px;color:#a9b1d6;max-width:180px}.file-preview-pill span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-preview-remove{background:none;border:none;cursor:pointer;color:#787c99;padding:0;display:flex;align-items:center;font-size:14px;transition:color .15s ease;flex-shrink:0}.file-preview-remove:hover{color:#f7768e}.upload-progress{height:2px;background:#c0caf516;margin-bottom:5px;overflow:hidden}.upload-progress-fill{height:100%;background:#7aa2f7;transition:width .2s ease}.input-row{display:flex;align-items:center;gap:8px;background:#1f2335;border:2px solid rgba(192,202,245,.24);padding:8px;transition:border-color .15s ease;max-width:920px;margin:0 auto}.input-row:focus-within{border-color:#7aa2f7}.input-textarea{flex:1;background:none;border:none;outline:none;resize:none;color:#c0caf5;font-size:14px;line-height:1.5;font-family:inherit;min-height:24px;max-height:144px;overflow-y:auto;padding:2px 0}.input-textarea::placeholder{color:#787c99}.welcome-screen{flex:1;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:34px;gap:34px;text-align:center}@media(max-width:768px){.welcome-screen{padding:52px 15px 15px;gap:15px;justify-content:flex-start}}.welcome-logo{display:flex;flex-direction:column;align-items:center;gap:8px}.welcome-logo img{width:64px;height:64px}.welcome-logo h1{font-size:32px;font-weight:700;letter-spacing:-.5px;color:#c0caf5;margin:0}.welcome-logo p{font-size:15px;color:#a9b1d6;margin:0}@media(max-width:768px){.welcome-logo{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:8px}.welcome-logo img{width:36px;height:36px}.welcome-logo h1{font-size:22px}.welcome-logo p{font-size:13px;flex-basis:100%}}.welcome-profiles{display:flex;gap:15px;flex-wrap:wrap;justify-content:center;max-width:600px}@media(max-width:768px){.welcome-profiles{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;width:100%;max-width:100%}}.welcome-profile-card{display:flex;flex-direction:column;align-items:center;gap:8px;padding:15px;background:#c0caf50b;border:2px solid rgba(192,202,245,.24);cursor:pointer;transition:border-color .15s ease,background .15s ease;width:160px;text-align:center}.welcome-profile-card:hover,.welcome-profile-card.is-selected{border-color:#7aa2f7;background:#c0caf516}.welcome-profile-card.is-selected{border-color:#7aa2f7}.welcome-profile-card .profile-icon{font-size:32px;color:#7aa2f7}.welcome-profile-card .profile-name{font-size:14px;font-weight:600;color:#c0caf5}.welcome-profile-card .profile-desc{font-size:12px;color:#787c99;line-height:1.4}@media(max-width:768px){.welcome-profile-card{width:auto;padding:10px;gap:6px}.welcome-profile-card .profile-icon{font-size:22px}.welcome-profile-card .profile-name{font-size:13px}.welcome-profile-card .profile-desc{font-size:11px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}}.empty-chat{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:15px;color:#787c99;padding:34px}.empty-chat .empty-icon{font-size:56px;opacity:.4}.empty-chat p{font-size:15px;margin:0}.spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(192,202,245,.24);border-top-color:#7aa2f7;border-radius:50%;animation:spin .6s linear infinite;flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.fade-enter-active,.fade-leave-active{transition:opacity .15s ease}.fade-enter-from,.fade-leave-to{opacity:0}.msg-enter{animation:msgEnter .2s ease both}@keyframes msgEnter{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.slide-left-enter-active,.slide-left-leave-active{transition:transform .28s ease,opacity .28s ease}.slide-left-enter-from,.slide-left-leave-to{transform:translate(-100%);opacity:0}.modal-enter-active,.modal-leave-active{transition:opacity .28s ease}.modal-enter-active .modal-panel,.modal-leave-active .modal-panel{transition:opacity .28s ease,margin-top .28s ease}.modal-enter-from,.modal-leave-to{opacity:0}.modal-enter-from .modal-panel,.modal-leave-to .modal-panel{opacity:0;margin-top:200px}.btn-icon:not(.with-rotate) .ph{transform:none!important;transition:none!important}.tool-card[open] .tool-chevron,.thinking-card[open] .tool-chevron{transform:rotate(180deg)!important}
diff --git a/webclient/dist/assets/index-C1CG_FUm.js b/webclient/dist/assets/index-C1CG_FUm.js
deleted file mode 100644
index 48d2d12..0000000
--- a/webclient/dist/assets/index-C1CG_FUm.js
+++ /dev/null
@@ -1,93 +0,0 @@
-var jE=Object.defineProperty;var eS=(t,e,n)=>e in t?jE(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var dt=(t,e,n)=>eS(t,typeof e!="symbol"?e+"":e,n);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const a of i)if(a.type==="childList")for(const s of a.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(i){const a={};return i.integrity&&(a.integrity=i.integrity),i.referrerPolicy&&(a.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?a.credentials="include":i.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(i){if(i.ep)return;i.ep=!0;const a=n(i);fetch(i.href,a)}})();/**
-* @vue/shared v3.5.32
-* (c) 2018-present Yuxi (Evan) You and Vue contributors
-* @license MIT
-**/function Oc(t){const e=Object.create(null);for(const n of t.split(","))e[n]=1;return n=>n in e}const ut={},Sr=[],En=()=>{},tg=()=>!1,Ui=t=>t.charCodeAt(0)===111&&t.charCodeAt(1)===110&&(t.charCodeAt(2)>122||t.charCodeAt(2)<97),Fi=t=>t.startsWith("onUpdate:"),Ot=Object.assign,Ic=(t,e)=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)},tS=Object.prototype.hasOwnProperty,it=(t,e)=>tS.call(t,e),Ae=Array.isArray,fr=t=>jr(t)==="[object Map]",ng=t=>jr(t)==="[object Set]",g_=t=>jr(t)==="[object Date]",Ue=t=>typeof t=="function",gt=t=>typeof t=="string",Vt=t=>typeof t=="symbol",at=t=>t!==null&&typeof t=="object",rg=t=>(at(t)||Ue(t))&&Ue(t.then)&&Ue(t.catch),ig=Object.prototype.toString,jr=t=>ig.call(t),nS=t=>jr(t).slice(8,-1),ag=t=>jr(t)==="[object Object]",Bi=t=>gt(t)&&t!=="NaN"&&t[0]!=="-"&&""+parseInt(t,10)===t,kr=Oc(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Gi=t=>{const e=Object.create(null);return(n=>e[n]||(e[n]=t(n)))},rS=/-\w/g,Gt=Gi(t=>t.replace(rS,e=>e.slice(1).toUpperCase())),iS=/\B([A-Z])/g,Gn=Gi(t=>t.replace(iS,"-$1").toLowerCase()),Yi=Gi(t=>t.charAt(0).toUpperCase()+t.slice(1)),Ei=Gi(t=>t?`on${Yi(t)}`:""),mn=(t,e)=>!Object.is(t,e),Si=(t,...e)=>{for(let n=0;n{Object.defineProperty(t,e,{configurable:!0,enumerable:!1,writable:r,value:n})},yc=t=>{const e=parseFloat(t);return isNaN(e)?t:e},aS=t=>{const e=gt(t)?Number(t):NaN;return isNaN(e)?t:e};let E_;const qi=()=>E_||(E_=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function ar(t){if(Ae(t)){const e={};for(let n=0;n{if(n){const r=n.split(sS);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e}function Ze(t){let e="";if(gt(t))e=t;else if(Ae(t))for(let n=0;n!!(t&&t.__v_isRef===!0),Le=t=>gt(t)?t:t==null?"":Ae(t)||at(t)&&(t.toString===ig||!Ue(t.toString))?lg(t)?Le(t.value):JSON.stringify(t,cg,2):String(t),cg=(t,e)=>lg(e)?cg(t,e.value):fr(e)?{[`Map(${e.size})`]:[...e.entries()].reduce((n,[r,i],a)=>(n[sa(r,a)+" =>"]=i,n),{})}:ng(e)?{[`Set(${e.size})`]:[...e.values()].map(n=>sa(n))}:Vt(e)?sa(e):at(e)&&!Ae(e)&&!ag(e)?String(e):e,sa=(t,e="")=>{var n;return Vt(t)?`Symbol(${(n=t.description)!=null?n:e})`:t};/**
-* @vue/reactivity v3.5.32
-* (c) 2018-present Yuxi (Evan) You and Vue contributors
-* @license MIT
-**/let Dt;class _g{constructor(e=!1){this.detached=e,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.__v_skip=!0,this.parent=Dt,!e&&Dt&&(this.index=(Dt.scopes||(Dt.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let e,n;if(this.scopes)for(e=0,n=this.scopes.length;e0&&--this._on===0&&(Dt=this.prevScope,this.prevScope=void 0)}stop(e){if(this._active){this._active=!1;let n,r;for(n=0,r=this.effects.length;n0)return;if(Fr){let e=Fr;for(Fr=void 0;e;){const n=e.next;e.next=void 0,e.flags&=-9,e=n}}let t;for(;Ur;){let e=Ur;for(Ur=void 0;e;){const n=e.next;if(e.next=void 0,e.flags&=-9,e.flags&1)try{e.trigger()}catch(r){t||(t=r)}e=n}}if(t)throw t}function gg(t){for(let e=t.deps;e;e=e.nextDep)e.version=-1,e.prevActiveLink=e.dep.activeLink,e.dep.activeLink=e}function Eg(t){let e,n=t.depsTail,r=n;for(;r;){const i=r.prevDep;r.version===-1?(r===n&&(n=i),Lc(r),gS(r)):e=r,r.dep.activeLink=r.prevActiveLink,r.prevActiveLink=void 0,r=i}t.deps=e,t.depsTail=n}function rc(t){for(let e=t.deps;e;e=e.nextDep)if(e.dep.version!==e.version||e.dep.computed&&(Sg(e.dep.computed)||e.dep.version!==e.version))return!0;return!!t._dirty}function Sg(t){if(t.flags&4&&!(t.flags&16)||(t.flags&=-17,t.globalVersion===$r)||(t.globalVersion=$r,!t.isSSR&&t.flags&128&&(!t.deps&&!t._dirty||!rc(t))))return;t.flags|=2;const e=t.dep,n=pt,r=en;pt=t,en=!0;try{gg(t);const i=t.fn(t._value);(e.version===0||mn(i,t._value))&&(t.flags|=128,t._value=i,e.version++)}catch(i){throw e.version++,i}finally{pt=n,en=r,Eg(t),t.flags&=-3}}function Lc(t,e=!1){const{dep:n,prevSub:r,nextSub:i}=t;if(r&&(r.nextSub=i,t.prevSub=void 0),i&&(i.prevSub=r,t.nextSub=void 0),n.subs===t&&(n.subs=r,!r&&n.computed)){n.computed.flags&=-5;for(let a=n.computed.deps;a;a=a.nextDep)Lc(a,!0)}!e&&!--n.sc&&n.map&&n.map.delete(n.key)}function gS(t){const{prevDep:e,nextDep:n}=t;e&&(e.nextDep=n,t.prevDep=void 0),n&&(n.prevDep=e,t.nextDep=void 0)}let en=!0;const fg=[];function Dn(){fg.push(en),en=!1}function Mn(){const t=fg.pop();en=t===void 0?!0:t}function S_(t){const{cleanup:e}=t;if(t.cleanup=void 0,e){const n=pt;pt=void 0;try{e()}finally{pt=n}}}let $r=0;class ES{constructor(e,n){this.sub=e,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class wc{constructor(e){this.computed=e,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(e){if(!pt||!en||pt===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==pt)n=this.activeLink=new ES(pt,this),pt.deps?(n.prevDep=pt.depsTail,pt.depsTail.nextDep=n,pt.depsTail=n):pt.deps=pt.depsTail=n,Tg(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const r=n.nextDep;r.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=r),n.prevDep=pt.depsTail,n.nextDep=void 0,pt.depsTail.nextDep=n,pt.depsTail=n,pt.deps===n&&(pt.deps=r)}return n}trigger(e){this.version++,$r++,this.notify(e)}notify(e){Mc();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{xc()}}}function Tg(t){if(t.dep.sc++,t.sub.flags&4){const e=t.dep.computed;if(e&&!t.dep.subs){e.flags|=20;for(let r=e.deps;r;r=r.nextDep)Tg(r)}const n=t.dep.subs;n!==t&&(t.prevSub=n,n&&(n.nextSub=t)),t.dep.subs=t}}const hi=new WeakMap,jn=Symbol(""),ic=Symbol(""),Vr=Symbol("");function Mt(t,e,n){if(en&&pt){let r=hi.get(t);r||hi.set(t,r=new Map);let i=r.get(n);i||(r.set(n,i=new wc),i.map=r,i.key=n),i.track()}}function Nn(t,e,n,r,i,a){const s=hi.get(t);if(!s){$r++;return}const o=c=>{c&&c.trigger()};if(Mc(),e==="clear")s.forEach(o);else{const c=Ae(t),_=c&&Bi(n);if(c&&n==="length"){const l=Number(r);s.forEach((d,u)=>{(u==="length"||u===Vr||!Vt(u)&&u>=l)&&o(d)})}else switch((n!==void 0||s.has(void 0))&&o(s.get(n)),_&&o(s.get(Vr)),e){case"add":c?_&&o(s.get("length")):(o(s.get(jn)),fr(t)&&o(s.get(ic)));break;case"delete":c||(o(s.get(jn)),fr(t)&&o(s.get(ic)));break;case"set":fr(t)&&o(s.get(jn));break}}xc()}function SS(t,e){const n=hi.get(t);return n&&n.get(e)}function _r(t){const e=Xe(t);return e===t?e:(Mt(e,"iterate",Vr),$t(t)?e:e.map(tn))}function Hi(t){return Mt(t=Xe(t),"iterate",Vr),t}function un(t,e){return xn(t)?Rr(An(t)?tn(e):e):tn(e)}const fS={__proto__:null,[Symbol.iterator](){return ca(this,Symbol.iterator,t=>un(this,t))},concat(...t){return _r(this).concat(...t.map(e=>Ae(e)?_r(e):e))},entries(){return ca(this,"entries",t=>(t[1]=un(this,t[1]),t))},every(t,e){return Rn(this,"every",t,e,void 0,arguments)},filter(t,e){return Rn(this,"filter",t,e,n=>n.map(r=>un(this,r)),arguments)},find(t,e){return Rn(this,"find",t,e,n=>un(this,n),arguments)},findIndex(t,e){return Rn(this,"findIndex",t,e,void 0,arguments)},findLast(t,e){return Rn(this,"findLast",t,e,n=>un(this,n),arguments)},findLastIndex(t,e){return Rn(this,"findLastIndex",t,e,void 0,arguments)},forEach(t,e){return Rn(this,"forEach",t,e,void 0,arguments)},includes(...t){return _a(this,"includes",t)},indexOf(...t){return _a(this,"indexOf",t)},join(t){return _r(this).join(t)},lastIndexOf(...t){return _a(this,"lastIndexOf",t)},map(t,e){return Rn(this,"map",t,e,void 0,arguments)},pop(){return Ar(this,"pop")},push(...t){return Ar(this,"push",t)},reduce(t,...e){return f_(this,"reduce",t,e)},reduceRight(t,...e){return f_(this,"reduceRight",t,e)},shift(){return Ar(this,"shift")},some(t,e){return Rn(this,"some",t,e,void 0,arguments)},splice(...t){return Ar(this,"splice",t)},toReversed(){return _r(this).toReversed()},toSorted(t){return _r(this).toSorted(t)},toSpliced(...t){return _r(this).toSpliced(...t)},unshift(...t){return Ar(this,"unshift",t)},values(){return ca(this,"values",t=>un(this,t))}};function ca(t,e,n){const r=Hi(t),i=r[e]();return r!==t&&!$t(t)&&(i._next=i.next,i.next=()=>{const a=i._next();return a.done||(a.value=n(a.value)),a}),i}const TS=Array.prototype;function Rn(t,e,n,r,i,a){const s=Hi(t),o=s!==t&&!$t(t),c=s[e];if(c!==TS[e]){const d=c.apply(t,a);return o?tn(d):d}let _=n;s!==t&&(o?_=function(d,u){return n.call(this,un(t,d),u,t)}:n.length>2&&(_=function(d,u){return n.call(this,d,u,t)}));const l=c.call(s,_,r);return o&&i?i(l):l}function f_(t,e,n,r){const i=Hi(t),a=i!==t&&!$t(t);let s=n,o=!1;i!==t&&(a?(o=r.length===0,s=function(_,l,d){return o&&(o=!1,_=un(t,_)),n.call(this,_,un(t,l),d,t)}):n.length>3&&(s=function(_,l,d){return n.call(this,_,l,d,t)}));const c=i[e](s,...r);return o?un(t,c):c}function _a(t,e,n){const r=Xe(t);Mt(r,"iterate",Vr);const i=r[e](...n);return(i===-1||i===!1)&&$i(n[0])?(n[0]=Xe(n[0]),r[e](...n)):i}function Ar(t,e,n=[]){Dn(),Mc();const r=Xe(t)[e].apply(t,n);return xc(),Mn(),r}const bS=Oc("__proto__,__v_isRef,__isVue"),bg=new Set(Object.getOwnPropertyNames(Symbol).filter(t=>t!=="arguments"&&t!=="caller").map(t=>Symbol[t]).filter(Vt));function RS(t){Vt(t)||(t=String(t));const e=Xe(this);return Mt(e,"has",t),e.hasOwnProperty(t)}class Rg{constructor(e=!1,n=!1){this._isReadonly=e,this._isShallow=n}get(e,n,r){if(n==="__v_skip")return e.__v_skip;const i=this._isReadonly,a=this._isShallow;if(n==="__v_isReactive")return!i;if(n==="__v_isReadonly")return i;if(n==="__v_isShallow")return a;if(n==="__v_raw")return r===(i?a?MS:Ng:a?vg:Cg).get(e)||Object.getPrototypeOf(e)===Object.getPrototypeOf(r)?e:void 0;const s=Ae(e);if(!i){let c;if(s&&(c=fS[n]))return c;if(n==="hasOwnProperty")return RS}const o=Reflect.get(e,n,bt(e)?e:r);if((Vt(n)?bg.has(n):bS(n))||(i||Mt(e,"get",n),a))return o;if(bt(o)){const c=s&&Bi(n)?o:o.value;return i&&at(c)?oc(c):c}return at(o)?i?oc(o):ei(o):o}}class hg extends Rg{constructor(e=!1){super(!1,e)}set(e,n,r,i){let a=e[n];const s=Ae(e)&&Bi(n);if(!this._isShallow){const _=xn(a);if(!$t(r)&&!xn(r)&&(a=Xe(a),r=Xe(r)),!s&&bt(a)&&!bt(r))return _||(a.value=r),!0}const o=s?Number(n)t,ci=t=>Reflect.getPrototypeOf(t);function OS(t,e,n){return function(...r){const i=this.__v_raw,a=Xe(i),s=fr(a),o=t==="entries"||t===Symbol.iterator&&s,c=t==="keys"&&s,_=i[t](...r),l=n?ac:e?Rr:tn;return!e&&Mt(a,"iterate",c?ic:jn),Ot(Object.create(_),{next(){const{value:d,done:u}=_.next();return u?{value:d,done:u}:{value:o?[l(d[0]),l(d[1])]:l(d),done:u}}})}}function _i(t){return function(...e){return t==="delete"?!1:t==="clear"?void 0:this}}function IS(t,e){const n={get(i){const a=this.__v_raw,s=Xe(a),o=Xe(i);t||(mn(i,o)&&Mt(s,"get",i),Mt(s,"get",o));const{has:c}=ci(s),_=e?ac:t?Rr:tn;if(c.call(s,i))return _(a.get(i));if(c.call(s,o))return _(a.get(o));a!==s&&a.get(i)},get size(){const i=this.__v_raw;return!t&&Mt(Xe(i),"iterate",jn),i.size},has(i){const a=this.__v_raw,s=Xe(a),o=Xe(i);return t||(mn(i,o)&&Mt(s,"has",i),Mt(s,"has",o)),i===o?a.has(i):a.has(i)||a.has(o)},forEach(i,a){const s=this,o=s.__v_raw,c=Xe(o),_=e?ac:t?Rr:tn;return!t&&Mt(c,"iterate",jn),o.forEach((l,d)=>i.call(a,_(l),_(d),s))}};return Ot(n,t?{add:_i("add"),set:_i("set"),delete:_i("delete"),clear:_i("clear")}:{add(i){const a=Xe(this),s=ci(a),o=Xe(i),c=!e&&!$t(i)&&!xn(i)?o:i;return s.has.call(a,c)||mn(i,c)&&s.has.call(a,i)||mn(o,c)&&s.has.call(a,o)||(a.add(c),Nn(a,"add",c,c)),this},set(i,a){!e&&!$t(a)&&!xn(a)&&(a=Xe(a));const s=Xe(this),{has:o,get:c}=ci(s);let _=o.call(s,i);_||(i=Xe(i),_=o.call(s,i));const l=c.call(s,i);return s.set(i,a),_?mn(a,l)&&Nn(s,"set",i,a):Nn(s,"add",i,a),this},delete(i){const a=Xe(this),{has:s,get:o}=ci(a);let c=s.call(a,i);c||(i=Xe(i),c=s.call(a,i)),o&&o.call(a,i);const _=a.delete(i);return c&&Nn(a,"delete",i,void 0),_},clear(){const i=Xe(this),a=i.size!==0,s=i.clear();return a&&Nn(i,"clear",void 0,void 0),s}}),["keys","values","entries",Symbol.iterator].forEach(i=>{n[i]=OS(i,t,e)}),n}function Pc(t,e){const n=IS(t,e);return(r,i,a)=>i==="__v_isReactive"?!t:i==="__v_isReadonly"?t:i==="__v_raw"?r:Reflect.get(it(n,i)&&i in r?n:r,i,a)}const yS={get:Pc(!1,!1)},AS={get:Pc(!1,!0)},DS={get:Pc(!0,!1)};const Cg=new WeakMap,vg=new WeakMap,Ng=new WeakMap,MS=new WeakMap;function xS(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function LS(t){return t.__v_skip||!Object.isExtensible(t)?0:xS(nS(t))}function ei(t){return xn(t)?t:kc(t,!1,CS,yS,Cg)}function Og(t){return kc(t,!1,NS,AS,vg)}function oc(t){return kc(t,!0,vS,DS,Ng)}function kc(t,e,n,r,i){if(!at(t)||t.__v_raw&&!(e&&t.__v_isReactive))return t;const a=LS(t);if(a===0)return t;const s=i.get(t);if(s)return s;const o=new Proxy(t,a===2?r:n);return i.set(t,o),o}function An(t){return xn(t)?An(t.__v_raw):!!(t&&t.__v_isReactive)}function xn(t){return!!(t&&t.__v_isReadonly)}function $t(t){return!!(t&&t.__v_isShallow)}function $i(t){return t?!!t.__v_raw:!1}function Xe(t){const e=t&&t.__v_raw;return e?Xe(e):t}function Vi(t){return!it(t,"__v_skip")&&Object.isExtensible(t)&&og(t,"__v_skip",!0),t}const tn=t=>at(t)?ei(t):t,Rr=t=>at(t)?oc(t):t;function bt(t){return t?t.__v_isRef===!0:!1}function _e(t){return Ig(t,!1)}function Er(t){return Ig(t,!0)}function Ig(t,e){return bt(t)?t:new wS(t,e)}class wS{constructor(e,n){this.dep=new wc,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?e:Xe(e),this._value=n?e:tn(e),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(e){const n=this._rawValue,r=this.__v_isShallow||$t(e)||xn(e);e=r?e:Xe(e),mn(e,n)&&(this._rawValue=e,this._value=r?e:tn(e),this.dep.trigger())}}function re(t){return bt(t)?t.value:t}function ue(t){return Ue(t)?t():re(t)}const PS={get:(t,e,n)=>e==="__v_raw"?t:re(Reflect.get(t,e,n)),set:(t,e,n,r)=>{const i=t[e];return bt(i)&&!bt(n)?(i.value=n,!0):Reflect.set(t,e,n,r)}};function yg(t){return An(t)?t:new Proxy(t,PS)}function kS(t){const e=Ae(t)?new Array(t.length):{};for(const n in t)e[n]=FS(t,n);return e}class US{constructor(e,n,r){this._object=e,this._defaultValue=r,this.__v_isRef=!0,this._value=void 0,this._key=Vt(n)?n:String(n),this._raw=Xe(e);let i=!0,a=e;if(!Ae(e)||Vt(this._key)||!Bi(this._key))do i=!$i(a)||$t(a);while(i&&(a=a.__v_raw));this._shallow=i}get value(){let e=this._object[this._key];return this._shallow&&(e=re(e)),this._value=e===void 0?this._defaultValue:e}set value(e){if(this._shallow&&bt(this._raw[this._key])){const n=this._object[this._key];if(bt(n)){n.value=e;return}}this._object[this._key]=e}get dep(){return SS(this._raw,this._key)}}function FS(t,e,n){return new US(t,e,n)}class BS{constructor(e,n,r){this.fn=e,this.setter=n,this._value=void 0,this.dep=new wc(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=$r-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=r}notify(){if(this.flags|=16,!(this.flags&8)&&pt!==this)return mg(this,!0),!0}get value(){const e=this.dep.track();return Sg(this),e&&(e.version=this.dep.version),this._value}set value(e){this.setter&&this.setter(e)}}function GS(t,e,n=!1){let r,i;return Ue(t)?r=t:(r=t.get,i=t.set),new BS(r,i,n)}const di={},Ci=new WeakMap;let Qn;function YS(t,e=!1,n=Qn){if(n){let r=Ci.get(n);r||Ci.set(n,r=[]),r.push(t)}}function qS(t,e,n=ut){const{immediate:r,deep:i,once:a,scheduler:s,augmentJob:o,call:c}=n,_=h=>i?h:$t(h)||i===!1||i===0?On(h,1):On(h);let l,d,u,m,p=!1,E=!1;if(bt(t)?(d=()=>t.value,p=$t(t)):An(t)?(d=()=>_(t),p=!0):Ae(t)?(E=!0,p=t.some(h=>An(h)||$t(h)),d=()=>t.map(h=>{if(bt(h))return h.value;if(An(h))return _(h);if(Ue(h))return c?c(h,2):h()})):Ue(t)?e?d=c?()=>c(t,2):t:d=()=>{if(u){Dn();try{u()}finally{Mn()}}const h=Qn;Qn=l;try{return c?c(t,3,[m]):t(m)}finally{Qn=h}}:d=En,e&&i){const h=d,A=i===!0?1/0:i;d=()=>On(h(),A)}const f=dg(),T=()=>{l.stop(),f&&f.active&&Ic(f.effects,l)};if(a&&e){const h=e;e=(...A)=>{h(...A),T()}}let R=E?new Array(t.length).fill(di):di;const C=h=>{if(!(!(l.flags&1)||!l.dirty&&!h))if(e){const A=l.run();if(i||p||(E?A.some((N,x)=>mn(N,R[x])):mn(A,R))){u&&u();const N=Qn;Qn=l;try{const x=[A,R===di?void 0:E&&R[0]===di?[]:R,m];R=A,c?c(e,3,x):e(...x)}finally{Qn=N}}}else l.run()};return o&&o(C),l=new ug(d),l.scheduler=s?()=>s(C,!1):C,m=h=>YS(h,!1,l),u=l.onStop=()=>{const h=Ci.get(l);if(h){if(c)c(h,4);else for(const A of h)A();Ci.delete(l)}},e?r?C(!0):R=l.run():s?s(C.bind(null,!0),!0):l.run(),T.pause=l.pause.bind(l),T.resume=l.resume.bind(l),T.stop=T,T}function On(t,e=1/0,n){if(e<=0||!at(t)||t.__v_skip||(n=n||new Map,(n.get(t)||0)>=e))return t;if(n.set(t,e),e--,bt(t))On(t.value,e,n);else if(Ae(t))for(let r=0;r{On(r,e,n)});else if(ag(t)){for(const r in t)On(t[r],e,n);for(const r of Object.getOwnPropertySymbols(t))Object.prototype.propertyIsEnumerable.call(t,r)&&On(t[r],e,n)}return t}/**
-* @vue/runtime-core v3.5.32
-* (c) 2018-present Yuxi (Evan) You and Vue contributors
-* @license MIT
-**/function ti(t,e,n,r){try{return r?t(...r):t()}catch(i){zi(i,e,n)}}function nn(t,e,n,r){if(Ue(t)){const i=ti(t,e,n,r);return i&&rg(i)&&i.catch(a=>{zi(a,e,n)}),i}if(Ae(t)){const i=[];for(let a=0;a>>1,i=Ut[r],a=zr(i);a=zr(n)?Ut.push(t):Ut.splice($S(e),0,t),t.flags|=1,Dg()}}function Dg(){vi||(vi=Ag.then(xg))}function VS(t){Ae(t)?Tr.push(...t):Fn&&t.id===-1?Fn.splice(ur+1,0,t):t.flags&1||(Tr.push(t),t.flags|=1),Dg()}function T_(t,e,n=_n+1){for(;nzr(n)-zr(r));if(Tr.length=0,Fn){Fn.push(...e);return}for(Fn=e,ur=0;urt.id==null?t.flags&2?-1:1/0:t.id;function xg(t){try{for(_n=0;_n{r._d&&yi(-1);const a=Ni(e);let s;try{s=t(...i)}finally{Ni(a),r._d&&yi(1)}return s};return r._n=!0,r._c=!0,r._d=!0,r}function wg(t,e){if(It===null)return t;const n=Ji(It),r=t.dirs||(t.dirs=[]);for(let i=0;i1)return n&&Ue(e)?e.call(r&&r.proxy):e}}function zS(){return!!($c()||tr)}const WS=Symbol.for("v-scx"),KS=()=>er(WS);function Ye(t,e,n){return Pg(t,e,n)}function Pg(t,e,n=ut){const{immediate:r,deep:i,flush:a,once:s}=n,o=Ot({},n),c=e&&r||!e&&a!=="post";let _;if(Xr){if(a==="sync"){const m=KS();_=m.__watcherHandles||(m.__watcherHandles=[])}else if(!c){const m=()=>{};return m.stop=En,m.resume=En,m.pause=En,m}}const l=Lt;o.call=(m,p,E)=>nn(m,l,p,E);let d=!1;a==="post"?o.scheduler=m=>{kt(m,l&&l.suspense)}:a!=="sync"&&(d=!0,o.scheduler=(m,p)=>{p?m():Uc(m)}),o.augmentJob=m=>{e&&(m.flags|=4),d&&(m.flags|=2,l&&(m.id=l.uid,m.i=l))};const u=qS(t,e,o);return Xr&&(_?_.push(u):c&&u()),u}function QS(t,e,n){const r=this.proxy,i=gt(t)?t.includes(".")?kg(r,t):()=>r[t]:t.bind(r,r);let a;Ue(e)?a=e:(a=e.handler,n=e);const s=ri(this),o=Pg(i,a.bind(r),n);return s(),o}function kg(t,e){const n=e.split(".");return()=>{let r=t;for(let i=0;it.__isTeleport,Xn=t=>t&&(t.disabled||t.disabled===""),XS=t=>t&&(t.defer||t.defer===""),b_=t=>typeof SVGElement<"u"&&t instanceof SVGElement,R_=t=>typeof MathMLElement=="function"&&t instanceof MathMLElement,sc=(t,e)=>{const n=t&&t.to;return gt(n)?e?e(n):null:n},ZS={name:"Teleport",__isTeleport:!0,process(t,e,n,r,i,a,s,o,c,_){const{mc:l,pc:d,pbc:u,o:{insert:m,querySelector:p,createText:E,createComment:f}}=_,T=Xn(e.props);let{dynamicChildren:R}=e;const C=(N,x,O)=>{N.shapeFlag&16&&l(N.children,x,O,i,a,s,o,c)},h=(N=e)=>{const x=Xn(N.props),O=N.target=sc(N.props,p),M=lc(O,N,E,m);O&&(s!=="svg"&&b_(O)?s="svg":s!=="mathml"&&R_(O)&&(s="mathml"),i&&i.isCE&&(i.ce._teleportTargets||(i.ce._teleportTargets=new Set)).add(O),x||(C(N,O,M),wr(N,!1)))},A=N=>{const x=()=>{Vn.get(N)===x&&(Vn.delete(N),Xn(N.props)&&(C(N,n,N.anchor),wr(N,!0)),h(N))};Vn.set(N,x),kt(x,a)};if(t==null){const N=e.el=E(""),x=e.anchor=E("");if(m(N,n,r),m(x,n,r),XS(e.props)||a&&a.pendingBranch){A(e);return}T&&(C(e,n,x),wr(e,!0)),h()}else{e.el=t.el;const N=e.anchor=t.anchor,x=Vn.get(t);if(x){x.flags|=8,Vn.delete(t),A(e);return}e.targetStart=t.targetStart;const O=e.target=t.target,M=e.targetAnchor=t.targetAnchor,q=Xn(t.props),V=q?n:O,I=q?N:M;if(s==="svg"||b_(O)?s="svg":(s==="mathml"||R_(O))&&(s="mathml"),R?(u(t.dynamicChildren,R,V,i,a,s,o),qc(t,e,!0)):c||d(t,e,V,I,i,a,s,o,!1),T)q?e.props&&t.props&&e.props.to!==t.props.to&&(e.props.to=t.props.to):ui(e,n,N,_,1);else if((e.props&&e.props.to)!==(t.props&&t.props.to)){const X=e.target=sc(e.props,p);X&&ui(e,X,null,_,0)}else q&&ui(e,O,M,_,1);wr(e,T)}},remove(t,e,n,{um:r,o:{remove:i}},a){const{shapeFlag:s,children:o,anchor:c,targetStart:_,targetAnchor:l,target:d,props:u}=t;let m=a||!Xn(u);const p=Vn.get(t);if(p&&(p.flags|=8,Vn.delete(t),m=!1),d&&(i(_),i(l)),a&&i(c),s&16)for(let E=0;E{t.isMounted=!0}),or(()=>{t.isUnmounting=!0}),t}const Zt=[Function,Array],Bg={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Zt,onEnter:Zt,onAfterEnter:Zt,onEnterCancelled:Zt,onBeforeLeave:Zt,onLeave:Zt,onAfterLeave:Zt,onLeaveCancelled:Zt,onBeforeAppear:Zt,onAppear:Zt,onAfterAppear:Zt,onAppearCancelled:Zt},Gg=t=>{const e=t.subTree;return e.component?Gg(e.component):e},ef={name:"BaseTransition",props:Bg,setup(t,{slots:e}){const n=$c(),r=jS();return()=>{const i=e.default&&Hg(e.default(),!0);if(!i||!i.length)return;const a=Yg(i),s=Xe(t),{mode:o}=s;if(r.isLeaving)return da(a);const c=h_(a);if(!c)return da(a);let _=cc(c,s,r,n,d=>_=d);c.type!==xt&&Wr(c,_);let l=n.subTree&&h_(n.subTree);if(l&&l.type!==xt&&!Zn(l,c)&&Gg(n).type!==xt){let d=cc(l,s,r,n);if(Wr(l,d),o==="out-in"&&c.type!==xt)return r.isLeaving=!0,d.afterLeave=()=>{r.isLeaving=!1,n.job.flags&8||n.update(),delete d.afterLeave,l=void 0},da(a);o==="in-out"&&c.type!==xt?d.delayLeave=(u,m,p)=>{const E=qg(r,l);E[String(l.key)]=l,u[dn]=()=>{m(),u[dn]=void 0,delete _.delayedLeave,l=void 0},_.delayedLeave=()=>{p(),delete _.delayedLeave,l=void 0}}:l=void 0}else l&&(l=void 0);return a}}};function Yg(t){let e=t[0];if(t.length>1){for(const n of t)if(n.type!==xt){e=n;break}}return e}const tf=ef;function qg(t,e){const{leavingVNodes:n}=t;let r=n.get(e.type);return r||(r=Object.create(null),n.set(e.type,r)),r}function cc(t,e,n,r,i){const{appear:a,mode:s,persisted:o=!1,onBeforeEnter:c,onEnter:_,onAfterEnter:l,onEnterCancelled:d,onBeforeLeave:u,onLeave:m,onAfterLeave:p,onLeaveCancelled:E,onBeforeAppear:f,onAppear:T,onAfterAppear:R,onAppearCancelled:C}=e,h=String(t.key),A=qg(n,t),N=(M,q)=>{M&&nn(M,r,9,q)},x=(M,q)=>{const V=q[1];N(M,q),Ae(M)?M.every(I=>I.length<=1)&&V():M.length<=1&&V()},O={mode:s,persisted:o,beforeEnter(M){let q=c;if(!n.isMounted)if(a)q=f||c;else return;M[dn]&&M[dn](!0);const V=A[h];V&&Zn(t,V)&&V.el[dn]&&V.el[dn](),N(q,[M])},enter(M){if(A[h]===t)return;let q=_,V=l,I=d;if(!n.isMounted)if(a)q=T||_,V=R||l,I=C||d;else return;let X=!1;M[Dr]=Se=>{X||(X=!0,Se?N(I,[M]):N(V,[M]),O.delayedLeave&&O.delayedLeave(),M[Dr]=void 0)};const te=M[Dr].bind(null,!1);q?x(q,[M,te]):te()},leave(M,q){const V=String(t.key);if(M[Dr]&&M[Dr](!0),n.isUnmounting)return q();N(u,[M]);let I=!1;M[dn]=te=>{I||(I=!0,q(),te?N(E,[M]):N(p,[M]),M[dn]=void 0,A[V]===t&&delete A[V])};const X=M[dn].bind(null,!1);A[V]=t,m?x(m,[M,X]):X()},clone(M){const q=cc(M,e,n,r,i);return i&&i(q),q}};return O}function da(t){if(Wi(t))return t=Bn(t),t.children=null,t}function h_(t){if(!Wi(t))return Fg(t.type)&&t.children?Yg(t.children):t;if(t.component)return t.component.subTree;const{shapeFlag:e,children:n}=t;if(n){if(e&16)return n[0];if(e&32&&Ue(n.default))return n.default()}}function Wr(t,e){t.shapeFlag&6&&t.component?(t.transition=e,Wr(t.component.subTree,e)):t.shapeFlag&128?(t.ssContent.transition=e.clone(t.ssContent),t.ssFallback.transition=e.clone(t.ssFallback)):t.transition=e}function Hg(t,e=!1,n){let r=[],i=0;for(let a=0;a1)for(let a=0;aBr(E,e&&(Ae(e)?e[f]:e),n,r,i));return}if(br(r)&&!i){r.shapeFlag&512&&r.type.__asyncResolved&&r.component.subTree.component&&Br(t,e,n,r.component.subTree);return}const a=r.shapeFlag&4?Ji(r.component):r.el,s=i?null:a,{i:o,r:c}=t,_=e&&e.r,l=o.refs===ut?o.refs={}:o.refs,d=o.setupState,u=Xe(d),m=d===ut?tg:E=>C_(l,E)?!1:it(u,E),p=(E,f)=>!(f&&C_(l,f));if(_!=null&&_!==c){if(v_(e),gt(_))l[_]=null,m(_)&&(d[_]=null);else if(bt(_)){const E=e;p(_,E.k)&&(_.value=null),E.k&&(l[E.k]=null)}}if(Ue(c))ti(c,o,12,[s,l]);else{const E=gt(c),f=bt(c);if(E||f){const T=()=>{if(t.f){const R=E?m(c)?d[c]:l[c]:p()||!t.k?c.value:l[t.k];if(i)Ae(R)&&Ic(R,a);else if(Ae(R))R.includes(a)||R.push(a);else if(E)l[c]=[a],m(c)&&(d[c]=l[c]);else{const C=[a];p(c,t.k)&&(c.value=C),t.k&&(l[t.k]=C)}}else E?(l[c]=s,m(c)&&(d[c]=s)):f&&(p(c,t.k)&&(c.value=s),t.k&&(l[t.k]=s))};if(s){const R=()=>{T(),Oi.delete(t)};R.id=-1,Oi.set(t,R),kt(R,n)}else v_(t),T()}}}function v_(t){const e=Oi.get(t);e&&(e.flags|=8,Oi.delete(t))}qi().requestIdleCallback;qi().cancelIdleCallback;const br=t=>!!t.type.__asyncLoader,Wi=t=>t.type.__isKeepAlive;function Bc(t,e){zg(t,"a",e)}function Vg(t,e){zg(t,"da",e)}function zg(t,e,n=Lt){const r=t.__wdc||(t.__wdc=()=>{let i=n;for(;i;){if(i.isDeactivated)return;i=i.parent}return t()});if(Ki(e,r,n),n){let i=n.parent;for(;i&&i.parent;)Wi(i.parent.vnode)&&nf(r,e,n,i),i=i.parent}}function nf(t,e,n,r){const i=Ki(e,t,r,!0);Yn(()=>{Ic(r[e],i)},n)}function Ki(t,e,n=Lt,r=!1){if(n){const i=n[t]||(n[t]=[]),a=e.__weh||(e.__weh=(...s)=>{Dn();const o=ri(n),c=nn(e,n,t,s);return o(),Mn(),c});return r?i.unshift(a):i.push(a),a}}const Ln=t=>(e,n=Lt)=>{(!Xr||t==="sp")&&Ki(t,(...r)=>e(...r),n)},rf=Ln("bm"),Sn=Ln("m"),af=Ln("bu"),of=Ln("u"),or=Ln("bum"),Yn=Ln("um"),sf=Ln("sp"),lf=Ln("rtg"),cf=Ln("rtc");function _f(t,e=Lt){Ki("ec",t,e)}const df="components",Wg=Symbol.for("v-ndc");function Qi(t){return gt(t)?uf(df,t,!1)||t:t||Wg}function uf(t,e,n=!0,r=!1){const i=It||Lt;if(i){const a=i.type;{const o=Zf(a,!1);if(o&&(o===e||o===Gt(e)||o===Yi(Gt(e))))return a}const s=N_(i[t]||a[t],e)||N_(i.appContext[t],e);return!s&&r?a:s}}function N_(t,e){return t&&(t[e]||t[Gt(e)]||t[Yi(Gt(e))])}function rn(t,e,n,r){let i;const a=n,s=Ae(t);if(s||gt(t)){const o=s&&An(t);let c=!1,_=!1;o&&(c=!$t(t),_=xn(t),t=Hi(t)),i=new Array(t.length);for(let l=0,d=t.length;le(o,c,void 0,a));else{const o=Object.keys(t);i=new Array(o.length);for(let c=0,_=o.length;c<_;c++){const l=o[c];i[c]=e(t[l],l,c,a)}}else i=[];return i}function pf(t,e){for(let n=0;n{const a=r.fn(...i);return a&&(a.key=r.key),a}:r.fn)}return t}function gn(t,e,n={},r,i){if(It.ce||It.parent&&br(It.parent)&&It.parent.ce){const _=Object.keys(n).length>0;return e!=="default"&&(n.name=e),w(),ft(ct,null,[Qe("slot",n,r)],_?-2:64)}let a=t[e];a&&a._c&&(a._d=!1),w();const s=a&&Kg(a(n)),o=n.key||s&&s.key,c=ft(ct,{key:(o&&!Vt(o)?o:`_${e}`)+(!s&&r?"_fb":"")},s||[],s&&t._===1?64:-2);return c.scopeId&&(c.slotScopeIds=[c.scopeId+"-s"]),a&&a._c&&(a._d=!0),c}function Kg(t){return t.some(e=>Qr(e)?!(e.type===xt||e.type===ct&&!Kg(e.children)):!0)?t:null}function mf(t,e){const n={};for(const r in t)n[Ei(r)]=t[r];return n}const _c=t=>t?mE(t)?Ji(t):_c(t.parent):null,Gr=Ot(Object.create(null),{$:t=>t,$el:t=>t.vnode.el,$data:t=>t.data,$props:t=>t.props,$attrs:t=>t.attrs,$slots:t=>t.slots,$refs:t=>t.refs,$parent:t=>_c(t.parent),$root:t=>_c(t.root),$host:t=>t.ce,$emit:t=>t.emit,$options:t=>Xg(t),$forceUpdate:t=>t.f||(t.f=()=>{Uc(t.update)}),$nextTick:t=>t.n||(t.n=Ft.bind(t.proxy)),$watch:t=>QS.bind(t)}),ua=(t,e)=>t!==ut&&!t.__isScriptSetup&&it(t,e),gf={get({_:t},e){if(e==="__v_skip")return!0;const{ctx:n,setupState:r,data:i,props:a,accessCache:s,type:o,appContext:c}=t;if(e[0]!=="$"){const u=s[e];if(u!==void 0)switch(u){case 1:return r[e];case 2:return i[e];case 4:return n[e];case 3:return a[e]}else{if(ua(r,e))return s[e]=1,r[e];if(i!==ut&&it(i,e))return s[e]=2,i[e];if(it(a,e))return s[e]=3,a[e];if(n!==ut&&it(n,e))return s[e]=4,n[e];dc&&(s[e]=0)}}const _=Gr[e];let l,d;if(_)return e==="$attrs"&&Mt(t.attrs,"get",""),_(t);if((l=o.__cssModules)&&(l=l[e]))return l;if(n!==ut&&it(n,e))return s[e]=4,n[e];if(d=c.config.globalProperties,it(d,e))return d[e]},set({_:t},e,n){const{data:r,setupState:i,ctx:a}=t;return ua(i,e)?(i[e]=n,!0):r!==ut&&it(r,e)?(r[e]=n,!0):it(t.props,e)||e[0]==="$"&&e.slice(1)in t?!1:(a[e]=n,!0)},has({_:{data:t,setupState:e,accessCache:n,ctx:r,appContext:i,props:a,type:s}},o){let c;return!!(n[o]||t!==ut&&o[0]!=="$"&&it(t,o)||ua(e,o)||it(a,o)||it(r,o)||it(Gr,o)||it(i.config.globalProperties,o)||(c=s.__cssModules)&&c[o])},defineProperty(t,e,n){return n.get!=null?t._.accessCache[e]=0:it(n,"value")&&this.set(t,e,n.value,null),Reflect.defineProperty(t,e,n)}};function O_(t){return Ae(t)?t.reduce((e,n)=>(e[n]=null,e),{}):t}let dc=!0;function Ef(t){const e=Xg(t),n=t.proxy,r=t.ctx;dc=!1,e.beforeCreate&&I_(e.beforeCreate,t,"bc");const{data:i,computed:a,methods:s,watch:o,provide:c,inject:_,created:l,beforeMount:d,mounted:u,beforeUpdate:m,updated:p,activated:E,deactivated:f,beforeDestroy:T,beforeUnmount:R,destroyed:C,unmounted:h,render:A,renderTracked:N,renderTriggered:x,errorCaptured:O,serverPrefetch:M,expose:q,inheritAttrs:V,components:I,directives:X,filters:te}=e;if(_&&Sf(_,r,null),s)for(const se in s){const be=s[se];Ue(be)&&(r[se]=be.bind(n))}if(i){const se=i.call(n,n);at(se)&&(t.data=ei(se))}if(dc=!0,a)for(const se in a){const be=a[se],me=Ue(be)?be.bind(n,n):Ue(be.get)?be.get.bind(n,n):En,xe=!Ue(be)&&Ue(be.set)?be.set.bind(n):En,Be=Te({get:me,set:xe});Object.defineProperty(r,se,{enumerable:!0,configurable:!0,get:()=>Be.value,set:He=>Be.value=He})}if(o)for(const se in o)Qg(o[se],r,n,se);if(c){const se=Ue(c)?c.call(n):c;Reflect.ownKeys(se).forEach(be=>{pr(be,se[be])})}l&&I_(l,t,"c");function oe(se,be){Ae(be)?be.forEach(me=>se(me.bind(n))):be&&se(be.bind(n))}if(oe(rf,d),oe(Sn,u),oe(af,m),oe(of,p),oe(Bc,E),oe(Vg,f),oe(_f,O),oe(cf,N),oe(lf,x),oe(or,R),oe(Yn,h),oe(sf,M),Ae(q))if(q.length){const se=t.exposed||(t.exposed={});q.forEach(be=>{Object.defineProperty(se,be,{get:()=>n[be],set:me=>n[be]=me,enumerable:!0})})}else t.exposed||(t.exposed={});A&&t.render===En&&(t.render=A),V!=null&&(t.inheritAttrs=V),I&&(t.components=I),X&&(t.directives=X),M&&$g(t)}function Sf(t,e,n=En){Ae(t)&&(t=uc(t));for(const r in t){const i=t[r];let a;at(i)?"default"in i?a=er(i.from||r,i.default,!0):a=er(i.from||r):a=er(i),bt(a)?Object.defineProperty(e,r,{enumerable:!0,configurable:!0,get:()=>a.value,set:s=>a.value=s}):e[r]=a}}function I_(t,e,n){nn(Ae(t)?t.map(r=>r.bind(e.proxy)):t.bind(e.proxy),e,n)}function Qg(t,e,n,r){let i=r.includes(".")?kg(n,r):()=>n[r];if(gt(t)){const a=e[t];Ue(a)&&Ye(i,a)}else if(Ue(t))Ye(i,t.bind(n));else if(at(t))if(Ae(t))t.forEach(a=>Qg(a,e,n,r));else{const a=Ue(t.handler)?t.handler.bind(n):e[t.handler];Ue(a)&&Ye(i,a,t)}}function Xg(t){const e=t.type,{mixins:n,extends:r}=e,{mixins:i,optionsCache:a,config:{optionMergeStrategies:s}}=t.appContext,o=a.get(e);let c;return o?c=o:!i.length&&!n&&!r?c=e:(c={},i.length&&i.forEach(_=>Ii(c,_,s,!0)),Ii(c,e,s)),at(e)&&a.set(e,c),c}function Ii(t,e,n,r=!1){const{mixins:i,extends:a}=e;a&&Ii(t,a,n,!0),i&&i.forEach(s=>Ii(t,s,n,!0));for(const s in e)if(!(r&&s==="expose")){const o=ff[s]||n&&n[s];t[s]=o?o(t[s],e[s]):e[s]}return t}const ff={data:y_,props:A_,emits:A_,methods:Pr,computed:Pr,beforeCreate:Pt,created:Pt,beforeMount:Pt,mounted:Pt,beforeUpdate:Pt,updated:Pt,beforeDestroy:Pt,beforeUnmount:Pt,destroyed:Pt,unmounted:Pt,activated:Pt,deactivated:Pt,errorCaptured:Pt,serverPrefetch:Pt,components:Pr,directives:Pr,watch:bf,provide:y_,inject:Tf};function y_(t,e){return e?t?function(){return Ot(Ue(t)?t.call(this,this):t,Ue(e)?e.call(this,this):e)}:e:t}function Tf(t,e){return Pr(uc(t),uc(e))}function uc(t){if(Ae(t)){const e={};for(let n=0;ne==="modelValue"||e==="model-value"?t.modelModifiers:t[`${e}Modifiers`]||t[`${Gt(e)}Modifiers`]||t[`${Gn(e)}Modifiers`];function vf(t,e,...n){if(t.isUnmounted)return;const r=t.vnode.props||ut;let i=n;const a=e.startsWith("update:"),s=a&&Cf(r,e.slice(7));s&&(s.trim&&(i=n.map(l=>gt(l)?l.trim():l)),s.number&&(i=n.map(yc)));let o,c=r[o=Ei(e)]||r[o=Ei(Gt(e))];!c&&a&&(c=r[o=Ei(Gn(e))]),c&&nn(c,t,6,i);const _=r[o+"Once"];if(_){if(!t.emitted)t.emitted={};else if(t.emitted[o])return;t.emitted[o]=!0,nn(_,t,6,i)}}const Nf=new WeakMap;function Jg(t,e,n=!1){const r=n?Nf:e.emitsCache,i=r.get(t);if(i!==void 0)return i;const a=t.emits;let s={},o=!1;if(!Ue(t)){const c=_=>{const l=Jg(_,e,!0);l&&(o=!0,Ot(s,l))};!n&&e.mixins.length&&e.mixins.forEach(c),t.extends&&c(t.extends),t.mixins&&t.mixins.forEach(c)}return!a&&!o?(at(t)&&r.set(t,null),null):(Ae(a)?a.forEach(c=>s[c]=null):Ot(s,a),at(t)&&r.set(t,s),s)}function Xi(t,e){return!t||!Ui(e)?!1:(e=e.slice(2).replace(/Once$/,""),it(t,e[0].toLowerCase()+e.slice(1))||it(t,Gn(e))||it(t,e))}function D_(t){const{type:e,vnode:n,proxy:r,withProxy:i,propsOptions:[a],slots:s,attrs:o,emit:c,render:_,renderCache:l,props:d,data:u,setupState:m,ctx:p,inheritAttrs:E}=t,f=Ni(t);let T,R;try{if(n.shapeFlag&4){const h=i||r,A=h;T=pn(_.call(A,h,l,d,m,u,p)),R=o}else{const h=e;T=pn(h.length>1?h(d,{attrs:o,slots:s,emit:c}):h(d,null)),R=e.props?o:Of(o)}}catch(h){Yr.length=0,zi(h,t,1),T=Qe(xt)}let C=T;if(R&&E!==!1){const h=Object.keys(R),{shapeFlag:A}=C;h.length&&A&7&&(a&&h.some(Fi)&&(R=If(R,a)),C=Bn(C,R,!1,!0))}return n.dirs&&(C=Bn(C,null,!1,!0),C.dirs=C.dirs?C.dirs.concat(n.dirs):n.dirs),n.transition&&Wr(C,n.transition),T=C,Ni(f),T}const Of=t=>{let e;for(const n in t)(n==="class"||n==="style"||Ui(n))&&((e||(e={}))[n]=t[n]);return e},If=(t,e)=>{const n={};for(const r in t)(!Fi(r)||!(r.slice(9)in e))&&(n[r]=t[r]);return n};function yf(t,e,n){const{props:r,children:i,component:a}=t,{props:s,children:o,patchFlag:c}=e,_=a.emitsOptions;if(e.dirs||e.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return r?M_(r,s,_):!!s;if(c&8){const l=e.dynamicProps;for(let d=0;dObject.create(eE),nE=t=>Object.getPrototypeOf(t)===eE;function Df(t,e,n,r=!1){const i={},a=tE();t.propsDefaults=Object.create(null),rE(t,e,i,a);for(const s in t.propsOptions[0])s in i||(i[s]=void 0);n?t.props=r?i:Og(i):t.type.props?t.props=i:t.props=a,t.attrs=a}function Mf(t,e,n,r){const{props:i,attrs:a,vnode:{patchFlag:s}}=t,o=Xe(i),[c]=t.propsOptions;let _=!1;if((r||s>0)&&!(s&16)){if(s&8){const l=t.vnode.dynamicProps;for(let d=0;d{c=!0;const[u,m]=iE(d,e,!0);Ot(s,u),m&&o.push(...m)};!n&&e.mixins.length&&e.mixins.forEach(l),t.extends&&l(t.extends),t.mixins&&t.mixins.forEach(l)}if(!a&&!c)return at(t)&&r.set(t,Sr),Sr;if(Ae(a))for(let l=0;lt==="_"||t==="_ctx"||t==="$stable",Yc=t=>Ae(t)?t.map(pn):[pn(t)],Lf=(t,e,n)=>{if(e._n)return e;const r=yt((...i)=>Yc(e(...i)),n);return r._c=!1,r},aE=(t,e,n)=>{const r=t._ctx;for(const i in t){if(Gc(i))continue;const a=t[i];if(Ue(a))e[i]=Lf(i,a,r);else if(a!=null){const s=Yc(a);e[i]=()=>s}}},oE=(t,e)=>{const n=Yc(e);t.slots.default=()=>n},sE=(t,e,n)=>{for(const r in e)(n||!Gc(r))&&(t[r]=e[r])},wf=(t,e,n)=>{const r=t.slots=tE();if(t.vnode.shapeFlag&32){const i=e._;i?(sE(r,e,n),n&&og(r,"_",i,!0)):aE(e,r)}else e&&oE(t,e)},Pf=(t,e,n)=>{const{vnode:r,slots:i}=t;let a=!0,s=ut;if(r.shapeFlag&32){const o=e._;o?n&&o===1?a=!1:sE(i,e,n):(a=!e.$stable,aE(e,i)),s=e}else e&&(oE(t,e),s={default:1});if(a)for(const o in i)!Gc(o)&&s[o]==null&&delete i[o]},kt=Gf;function kf(t){return Uf(t)}function Uf(t,e){const n=qi();n.__VUE__=!0;const{insert:r,remove:i,patchProp:a,createElement:s,createText:o,createComment:c,setText:_,setElementText:l,parentNode:d,nextSibling:u,setScopeId:m=En,insertStaticContent:p}=t,E=(g,S,y,U=null,F=null,B=null,Q=void 0,J=null,Z=!!S.dynamicChildren)=>{if(g===S)return;g&&!Zn(g,S)&&(U=D(g),He(g,F,B,!0),g=null),S.patchFlag===-2&&(Z=!1,S.dynamicChildren=null);const{type:W,ref:Ce,shapeFlag:ce}=S;switch(W){case Zi:f(g,S,y,U);break;case xt:T(g,S,y,U);break;case fi:g==null&&R(S,y,U,Q);break;case ct:I(g,S,y,U,F,B,Q,J,Z);break;default:ce&1?A(g,S,y,U,F,B,Q,J,Z):ce&6?X(g,S,y,U,F,B,Q,J,Z):(ce&64||ce&128)&&W.process(g,S,y,U,F,B,Q,J,Z,j)}Ce!=null&&F?Br(Ce,g&&g.ref,B,S||g,!S):Ce==null&&g&&g.ref!=null&&Br(g.ref,null,B,g,!0)},f=(g,S,y,U)=>{if(g==null)r(S.el=o(S.children),y,U);else{const F=S.el=g.el;S.children!==g.children&&_(F,S.children)}},T=(g,S,y,U)=>{g==null?r(S.el=c(S.children||""),y,U):S.el=g.el},R=(g,S,y,U)=>{[g.el,g.anchor]=p(g.children,S,y,U,g.el,g.anchor)},C=({el:g,anchor:S},y,U)=>{let F;for(;g&&g!==S;)F=u(g),r(g,y,U),g=F;r(S,y,U)},h=({el:g,anchor:S})=>{let y;for(;g&&g!==S;)y=u(g),i(g),g=y;i(S)},A=(g,S,y,U,F,B,Q,J,Z)=>{if(S.type==="svg"?Q="svg":S.type==="math"&&(Q="mathml"),g==null)N(S,y,U,F,B,Q,J,Z);else{const W=g.el&&g.el._isVueCE?g.el:null;try{W&&W._beginPatch(),M(g,S,F,B,Q,J,Z)}finally{W&&W._endPatch()}}},N=(g,S,y,U,F,B,Q,J)=>{let Z,W;const{props:Ce,shapeFlag:ce,transition:le,dirs:ve}=g;if(Z=g.el=s(g.type,B,Ce&&Ce.is,Ce),ce&8?l(Z,g.children):ce&16&&O(g.children,Z,null,U,F,pa(g,B),Q,J),ve&&$n(g,null,U,"created"),x(Z,g,g.scopeId,Q,U),Ce){for(const qe in Ce)qe!=="value"&&!kr(qe)&&a(Z,qe,null,Ce[qe],B,U);"value"in Ce&&a(Z,"value",null,Ce.value,B),(W=Ce.onVnodeBeforeMount)&&ln(W,U,g)}ve&&$n(g,null,U,"beforeMount");const Me=Ff(F,le);Me&&le.beforeEnter(Z),r(Z,S,y),((W=Ce&&Ce.onVnodeMounted)||Me||ve)&&kt(()=>{try{W&&ln(W,U,g),Me&&le.enter(Z),ve&&$n(g,null,U,"mounted")}finally{}},F)},x=(g,S,y,U,F)=>{if(y&&m(g,y),U)for(let B=0;B{for(let W=Z;W{const J=S.el=g.el;let{patchFlag:Z,dynamicChildren:W,dirs:Ce}=S;Z|=g.patchFlag&16;const ce=g.props||ut,le=S.props||ut;let ve;if(y&&zn(y,!1),(ve=le.onVnodeBeforeUpdate)&&ln(ve,y,S,g),Ce&&$n(S,g,y,"beforeUpdate"),y&&zn(y,!0),(ce.innerHTML&&le.innerHTML==null||ce.textContent&&le.textContent==null)&&l(J,""),W?q(g.dynamicChildren,W,J,y,U,pa(S,F),B):Q||be(g,S,J,null,y,U,pa(S,F),B,!1),Z>0){if(Z&16)V(J,ce,le,y,F);else if(Z&2&&ce.class!==le.class&&a(J,"class",null,le.class,F),Z&4&&a(J,"style",ce.style,le.style,F),Z&8){const Me=S.dynamicProps;for(let qe=0;qe{ve&&ln(ve,y,S,g),Ce&&$n(S,g,y,"updated")},U)},q=(g,S,y,U,F,B,Q)=>{for(let J=0;J{if(S!==y){if(S!==ut)for(const B in S)!kr(B)&&!(B in y)&&a(g,B,S[B],null,F,U);for(const B in y){if(kr(B))continue;const Q=y[B],J=S[B];Q!==J&&B!=="value"&&a(g,B,J,Q,F,U)}"value"in y&&a(g,"value",S.value,y.value,F)}},I=(g,S,y,U,F,B,Q,J,Z)=>{const W=S.el=g?g.el:o(""),Ce=S.anchor=g?g.anchor:o("");let{patchFlag:ce,dynamicChildren:le,slotScopeIds:ve}=S;ve&&(J=J?J.concat(ve):ve),g==null?(r(W,y,U),r(Ce,y,U),O(S.children||[],y,Ce,F,B,Q,J,Z)):ce>0&&ce&64&&le&&g.dynamicChildren&&g.dynamicChildren.length===le.length?(q(g.dynamicChildren,le,y,F,B,Q,J),(S.key!=null||F&&S===F.subTree)&&qc(g,S,!0)):be(g,S,y,Ce,F,B,Q,J,Z)},X=(g,S,y,U,F,B,Q,J,Z)=>{S.slotScopeIds=J,g==null?S.shapeFlag&512?F.ctx.activate(S,y,U,Q,Z):te(S,y,U,F,B,Q,Z):Se(g,S,Z)},te=(g,S,y,U,F,B,Q)=>{const J=g.component=zf(g,U,F);if(Wi(g)&&(J.ctx.renderer=j),Wf(J,!1,Q),J.asyncDep){if(F&&F.registerDep(J,oe,Q),!g.el){const Z=J.subTree=Qe(xt);T(null,Z,S,y),g.placeholder=Z.el}}else oe(J,g,S,y,F,B,Q)},Se=(g,S,y)=>{const U=S.component=g.component;if(yf(g,S,y))if(U.asyncDep&&!U.asyncResolved){se(U,S,y);return}else U.next=S,U.update();else S.el=g.el,U.vnode=S},oe=(g,S,y,U,F,B,Q)=>{const J=()=>{if(g.isMounted){let{next:ce,bu:le,u:ve,parent:Me,vnode:qe}=g;{const H=lE(g);if(H){ce&&(ce.el=qe.el,se(g,ce,Q)),H.asyncDep.then(()=>{kt(()=>{g.isUnmounted||W()},F)});return}}let We=ce,nt;zn(g,!1),ce?(ce.el=qe.el,se(g,ce,Q)):ce=qe,le&&Si(le),(nt=ce.props&&ce.props.onVnodeBeforeUpdate)&&ln(nt,Me,ce,qe),zn(g,!0);const Ke=D_(g),k=g.subTree;g.subTree=Ke,E(k,Ke,d(k.el),D(k),g,F,B),ce.el=Ke.el,We===null&&Af(g,Ke.el),ve&&kt(ve,F),(nt=ce.props&&ce.props.onVnodeUpdated)&&kt(()=>ln(nt,Me,ce,qe),F)}else{let ce;const{el:le,props:ve}=S,{bm:Me,m:qe,parent:We,root:nt,type:Ke}=g,k=br(S);zn(g,!1),Me&&Si(Me),!k&&(ce=ve&&ve.onVnodeBeforeMount)&&ln(ce,We,S),zn(g,!0);{nt.ce&&nt.ce._hasShadowRoot()&&nt.ce._injectChildStyle(Ke,g.parent?g.parent.type:void 0);const H=g.subTree=D_(g);E(null,H,y,U,g,F,B),S.el=H.el}if(qe&&kt(qe,F),!k&&(ce=ve&&ve.onVnodeMounted)){const H=S;kt(()=>ln(ce,We,H),F)}(S.shapeFlag&256||We&&br(We.vnode)&&We.vnode.shapeFlag&256)&&g.a&&kt(g.a,F),g.isMounted=!0,S=y=U=null}};g.scope.on();const Z=g.effect=new ug(J);g.scope.off();const W=g.update=Z.run.bind(Z),Ce=g.job=Z.runIfDirty.bind(Z);Ce.i=g,Ce.id=g.uid,Z.scheduler=()=>Uc(Ce),zn(g,!0),W()},se=(g,S,y)=>{S.component=g;const U=g.vnode.props;g.vnode=S,g.next=null,Mf(g,S.props,U,y),Pf(g,S.children,y),Dn(),T_(g),Mn()},be=(g,S,y,U,F,B,Q,J,Z=!1)=>{const W=g&&g.children,Ce=g?g.shapeFlag:0,ce=S.children,{patchFlag:le,shapeFlag:ve}=S;if(le>0){if(le&128){xe(W,ce,y,U,F,B,Q,J,Z);return}else if(le&256){me(W,ce,y,U,F,B,Q,J,Z);return}}ve&8?(Ce&16&&K(W,F,B),ce!==W&&l(y,ce)):Ce&16?ve&16?xe(W,ce,y,U,F,B,Q,J,Z):K(W,F,B,!0):(Ce&8&&l(y,""),ve&16&&O(ce,y,U,F,B,Q,J,Z))},me=(g,S,y,U,F,B,Q,J,Z)=>{g=g||Sr,S=S||Sr;const W=g.length,Ce=S.length,ce=Math.min(W,Ce);let le;for(le=0;leCe?K(g,F,B,!0,!1,ce):O(S,y,U,F,B,Q,J,Z,ce)},xe=(g,S,y,U,F,B,Q,J,Z)=>{let W=0;const Ce=S.length;let ce=g.length-1,le=Ce-1;for(;W<=ce&&W<=le;){const ve=g[W],Me=S[W]=Z?vn(S[W]):pn(S[W]);if(Zn(ve,Me))E(ve,Me,y,null,F,B,Q,J,Z);else break;W++}for(;W<=ce&&W<=le;){const ve=g[ce],Me=S[le]=Z?vn(S[le]):pn(S[le]);if(Zn(ve,Me))E(ve,Me,y,null,F,B,Q,J,Z);else break;ce--,le--}if(W>ce){if(W<=le){const ve=le+1,Me=vele)for(;W<=ce;)He(g[W],F,B,!0),W++;else{const ve=W,Me=W,qe=new Map;for(W=Me;W<=le;W++){const Ee=S[W]=Z?vn(S[W]):pn(S[W]);Ee.key!=null&&qe.set(Ee.key,W)}let We,nt=0;const Ke=le-Me+1;let k=!1,H=0;const ae=new Array(Ke);for(W=0;W=Ke){He(Ee,F,B,!0);continue}let he;if(Ee.key!=null)he=qe.get(Ee.key);else for(We=Me;We<=le;We++)if(ae[We-Me]===0&&Zn(Ee,S[We])){he=We;break}he===void 0?He(Ee,F,B,!0):(ae[he-Me]=W+1,he>=H?H=he:k=!0,E(Ee,S[he],y,null,F,B,Q,J,Z),nt++)}const Ie=k?Bf(ae):Sr;for(We=Ie.length-1,W=Ke-1;W>=0;W--){const Ee=Me+W,he=S[Ee],we=S[Ee+1],ze=Ee+1{const{el:B,type:Q,transition:J,children:Z,shapeFlag:W}=g;if(W&6){Be(g.component.subTree,S,y,U);return}if(W&128){g.suspense.move(S,y,U);return}if(W&64){Q.move(g,S,y,j);return}if(Q===ct){r(B,S,y);for(let ce=0;ceJ.enter(B),F);else{const{leave:ce,delayLeave:le,afterLeave:ve}=J,Me=()=>{g.ctx.isUnmounted?i(B):r(B,S,y)},qe=()=>{B._isLeaving&&B[dn](!0),ce(B,()=>{Me(),ve&&ve()})};le?le(B,Me,qe):qe()}else r(B,S,y)},He=(g,S,y,U=!1,F=!1)=>{const{type:B,props:Q,ref:J,children:Z,dynamicChildren:W,shapeFlag:Ce,patchFlag:ce,dirs:le,cacheIndex:ve,memo:Me}=g;if(ce===-2&&(F=!1),J!=null&&(Dn(),Br(J,null,y,g,!0),Mn()),ve!=null&&(S.renderCache[ve]=void 0),Ce&256){S.ctx.deactivate(g);return}const qe=Ce&1&&le,We=!br(g);let nt;if(We&&(nt=Q&&Q.onVnodeBeforeUnmount)&&ln(nt,S,g),Ce&6)$(g.component,y,U);else{if(Ce&128){g.suspense.unmount(y,U);return}qe&&$n(g,null,S,"beforeUnmount"),Ce&64?g.type.remove(g,S,y,j,U):W&&!W.hasOnce&&(B!==ct||ce>0&&ce&64)?K(W,S,y,!1,!0):(B===ct&&ce&384||!F&&Ce&16)&&K(Z,S,y),U&&st(g)}const Ke=Me!=null&&ve==null;(We&&(nt=Q&&Q.onVnodeUnmounted)||qe||Ke)&&kt(()=>{nt&&ln(nt,S,g),qe&&$n(g,null,S,"unmounted"),Ke&&(g.el=null)},y)},st=g=>{const{type:S,el:y,anchor:U,transition:F}=g;if(S===ct){L(y,U);return}if(S===fi){h(g);return}const B=()=>{i(y),F&&!F.persisted&&F.afterLeave&&F.afterLeave()};if(g.shapeFlag&1&&F&&!F.persisted){const{leave:Q,delayLeave:J}=F,Z=()=>Q(y,B);J?J(g.el,B,Z):Z()}else B()},L=(g,S)=>{let y;for(;g!==S;)y=u(g),i(g),g=y;i(S)},$=(g,S,y)=>{const{bum:U,scope:F,job:B,subTree:Q,um:J,m:Z,a:W}=g;L_(Z),L_(W),U&&Si(U),F.stop(),B&&(B.flags|=8,He(Q,g,S,y)),J&&kt(J,S),kt(()=>{g.isUnmounted=!0},S)},K=(g,S,y,U=!1,F=!1,B=0)=>{for(let Q=B;Q{if(g.shapeFlag&6)return D(g.component.subTree);if(g.shapeFlag&128)return g.suspense.next();const S=u(g.anchor||g.el),y=S&&S[Ug];return y?u(y):S};let P=!1;const z=(g,S,y)=>{let U;g==null?S._vnode&&(He(S._vnode,null,null,!0),U=S._vnode.component):E(S._vnode||null,g,S,null,null,null,y),S._vnode=g,P||(P=!0,T_(U),Mg(),P=!1)},j={p:E,um:He,m:Be,r:st,mt:te,mc:O,pc:be,pbc:q,n:D,o:t};return{render:z,hydrate:void 0,createApp:hf(z)}}function pa({type:t,props:e},n){return n==="svg"&&t==="foreignObject"||n==="mathml"&&t==="annotation-xml"&&e&&e.encoding&&e.encoding.includes("html")?void 0:n}function zn({effect:t,job:e},n){n?(t.flags|=32,e.flags|=4):(t.flags&=-33,e.flags&=-5)}function Ff(t,e){return(!t||t&&!t.pendingBranch)&&e&&!e.persisted}function qc(t,e,n=!1){const r=t.children,i=e.children;if(Ae(r)&&Ae(i))for(let a=0;a>1,t[n[o]]<_?a=o+1:s=o;_0&&(e[r]=n[a-1]),n[a]=r)}}for(a=n.length,s=n[a-1];a-- >0;)n[a]=s,s=e[s];return n}function lE(t){const e=t.subTree.component;if(e)return e.asyncDep&&!e.asyncResolved?e:lE(e)}function L_(t){if(t)for(let e=0;et.__isSuspense;function Gf(t,e){e&&e.pendingBranch?Ae(t)?e.effects.push(...t):e.effects.push(t):VS(t)}const ct=Symbol.for("v-fgt"),Zi=Symbol.for("v-txt"),xt=Symbol.for("v-cmt"),fi=Symbol.for("v-stc"),Yr=[];let Ht=null;function w(t=!1){Yr.push(Ht=t?null:[])}function Yf(){Yr.pop(),Ht=Yr[Yr.length-1]||null}let Kr=1;function yi(t,e=!1){Kr+=t,t<0&&Ht&&e&&(Ht.hasOnce=!0)}function dE(t){return t.dynamicChildren=Kr>0?Ht||Sr:null,Yf(),Kr>0&&Ht&&Ht.push(t),t}function G(t,e,n,r,i,a){return dE(v(t,e,n,r,i,a,!0))}function ft(t,e,n,r,i){return dE(Qe(t,e,n,r,i,!0))}function Qr(t){return t?t.__v_isVNode===!0:!1}function Zn(t,e){return t.type===e.type&&t.key===e.key}const uE=({key:t})=>t??null,Ti=({ref:t,ref_key:e,ref_for:n})=>(typeof t=="number"&&(t=""+t),t!=null?gt(t)||bt(t)||Ue(t)?{i:It,r:t,k:e,f:!!n}:t:null);function v(t,e=null,n=null,r=0,i=null,a=t===ct?0:1,s=!1,o=!1){const c={__v_isVNode:!0,__v_skip:!0,type:t,props:e,key:e&&uE(e),ref:e&&Ti(e),scopeId:Lg,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:r,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:It};return o?(Hc(c,n),a&128&&t.normalize(c)):n&&(c.shapeFlag|=gt(n)?8:16),Kr>0&&!s&&Ht&&(c.patchFlag>0||a&6)&&c.patchFlag!==32&&Ht.push(c),c}const Qe=qf;function qf(t,e=null,n=null,r=0,i=null,a=!1){if((!t||t===Wg)&&(t=xt),Qr(t)){const o=Bn(t,e,!0);return n&&Hc(o,n),Kr>0&&!a&&Ht&&(o.shapeFlag&6?Ht[Ht.indexOf(t)]=o:Ht.push(o)),o.patchFlag=-2,o}if(Jf(t)&&(t=t.__vccOpts),e){e=pE(e);let{class:o,style:c}=e;o&&!gt(o)&&(e.class=Ze(o)),at(c)&&($i(c)&&!Ae(c)&&(c=Ot({},c)),e.style=ar(c))}const s=gt(t)?1:_E(t)?128:Fg(t)?64:at(t)?4:Ue(t)?2:0;return v(t,e,n,r,i,s,a,!0)}function pE(t){return t?$i(t)||nE(t)?Ot({},t):t:null}function Bn(t,e,n=!1,r=!1){const{props:i,ref:a,patchFlag:s,children:o,transition:c}=t,_=e?Ai(i||{},e):i,l={__v_isVNode:!0,__v_skip:!0,type:t.type,props:_,key:_&&uE(_),ref:e&&e.ref?n&&a?Ae(a)?a.concat(Ti(e)):[a,Ti(e)]:Ti(e):a,scopeId:t.scopeId,slotScopeIds:t.slotScopeIds,children:o,target:t.target,targetStart:t.targetStart,targetAnchor:t.targetAnchor,staticCount:t.staticCount,shapeFlag:t.shapeFlag,patchFlag:e&&t.type!==ct?s===-1?16:s|16:s,dynamicProps:t.dynamicProps,dynamicChildren:t.dynamicChildren,appContext:t.appContext,dirs:t.dirs,transition:c,component:t.component,suspense:t.suspense,ssContent:t.ssContent&&Bn(t.ssContent),ssFallback:t.ssFallback&&Bn(t.ssFallback),placeholder:t.placeholder,el:t.el,anchor:t.anchor,ctx:t.ctx,ce:t.ce};return c&&r&&Wr(l,c.clone(l)),l}function At(t=" ",e=0){return Qe(Zi,null,t,e)}function Hf(t,e){const n=Qe(fi,null,t);return n.staticCount=e,n}function ye(t="",e=!1){return e?(w(),ft(xt,null,t)):Qe(xt,null,t)}function pn(t){return t==null||typeof t=="boolean"?Qe(xt):Ae(t)?Qe(ct,null,t.slice()):Qr(t)?vn(t):Qe(Zi,null,String(t))}function vn(t){return t.el===null&&t.patchFlag!==-1||t.memo?t:Bn(t)}function Hc(t,e){let n=0;const{shapeFlag:r}=t;if(e==null)e=null;else if(Ae(e))n=16;else if(typeof e=="object")if(r&65){const i=e.default;i&&(i._c&&(i._d=!1),Hc(t,i()),i._c&&(i._d=!0));return}else{n=32;const i=e._;!i&&!nE(e)?e._ctx=It:i===3&&It&&(It.slots._===1?e._=1:(e._=2,t.patchFlag|=1024))}else Ue(e)?(e={default:e,_ctx:It},n=32):(e=String(e),r&64?(n=16,e=[At(e)]):n=8);t.children=e,t.shapeFlag|=n}function Ai(...t){const e={};for(let n=0;nLt||It;let Di,mc;{const t=qi(),e=(n,r)=>{let i;return(i=t[n])||(i=t[n]=[]),i.push(r),a=>{i.length>1?i.forEach(s=>s(a)):i[0](a)}};Di=e("__VUE_INSTANCE_SETTERS__",n=>Lt=n),mc=e("__VUE_SSR_SETTERS__",n=>Xr=n)}const ri=t=>{const e=Lt;return Di(t),t.scope.on(),()=>{t.scope.off(),Di(e)}},w_=()=>{Lt&&Lt.scope.off(),Di(null)};function mE(t){return t.vnode.shapeFlag&4}let Xr=!1;function Wf(t,e=!1,n=!1){e&&mc(e);const{props:r,children:i}=t.vnode,a=mE(t);Df(t,r,a,e),wf(t,i,n||e);const s=a?Kf(t,e):void 0;return e&&mc(!1),s}function Kf(t,e){const n=t.type;t.accessCache=Object.create(null),t.proxy=new Proxy(t.ctx,gf);const{setup:r}=n;if(r){Dn();const i=t.setupContext=r.length>1?Xf(t):null,a=ri(t),s=ti(r,t,0,[t.props,i]),o=rg(s);if(Mn(),a(),(o||t.sp)&&!br(t)&&$g(t),o){if(s.then(w_,w_),e)return s.then(c=>{P_(t,c)}).catch(c=>{zi(c,t,0)});t.asyncDep=s}else P_(t,s)}else gE(t)}function P_(t,e,n){Ue(e)?t.type.__ssrInlineRender?t.ssrRender=e:t.render=e:at(e)&&(t.setupState=yg(e)),gE(t)}function gE(t,e,n){const r=t.type;t.render||(t.render=r.render||En);{const i=ri(t);Dn();try{Ef(t)}finally{Mn(),i()}}}const Qf={get(t,e){return Mt(t,"get",""),t[e]}};function Xf(t){const e=n=>{t.exposed=n||{}};return{attrs:new Proxy(t.attrs,Qf),slots:t.slots,emit:t.emit,expose:e}}function Ji(t){return t.exposed?t.exposeProxy||(t.exposeProxy=new Proxy(yg(Vi(t.exposed)),{get(e,n){if(n in e)return e[n];if(n in Gr)return Gr[n](t)},has(e,n){return n in e||n in Gr}})):t.proxy}function Zf(t,e=!0){return Ue(t)?t.displayName||t.name:t.name||e&&t.__name}function Jf(t){return Ue(t)&&"__vccOpts"in t}const Te=(t,e)=>GS(t,e,Xr);function jf(t,e,n){try{yi(-1);const r=arguments.length;return r===2?at(e)&&!Ae(e)?Qr(e)?Qe(t,null,[e]):Qe(t,e):Qe(t,null,e):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Qr(n)&&(n=[n]),Qe(t,e,n))}finally{yi(1)}}const eT="3.5.32";/**
-* @vue/runtime-dom v3.5.32
-* (c) 2018-present Yuxi (Evan) You and Vue contributors
-* @license MIT
-**/let gc;const k_=typeof window<"u"&&window.trustedTypes;if(k_)try{gc=k_.createPolicy("vue",{createHTML:t=>t})}catch{}const EE=gc?t=>gc.createHTML(t):t=>t,tT="http://www.w3.org/2000/svg",nT="http://www.w3.org/1998/Math/MathML",Cn=typeof document<"u"?document:null,U_=Cn&&Cn.createElement("template"),rT={insert:(t,e,n)=>{e.insertBefore(t,n||null)},remove:t=>{const e=t.parentNode;e&&e.removeChild(t)},createElement:(t,e,n,r)=>{const i=e==="svg"?Cn.createElementNS(tT,t):e==="mathml"?Cn.createElementNS(nT,t):n?Cn.createElement(t,{is:n}):Cn.createElement(t);return t==="select"&&r&&r.multiple!=null&&i.setAttribute("multiple",r.multiple),i},createText:t=>Cn.createTextNode(t),createComment:t=>Cn.createComment(t),setText:(t,e)=>{t.nodeValue=e},setElementText:(t,e)=>{t.textContent=e},parentNode:t=>t.parentNode,nextSibling:t=>t.nextSibling,querySelector:t=>Cn.querySelector(t),setScopeId(t,e){t.setAttribute(e,"")},insertStaticContent(t,e,n,r,i,a){const s=n?n.previousSibling:e.lastChild;if(i&&(i===a||i.nextSibling))for(;e.insertBefore(i.cloneNode(!0),n),!(i===a||!(i=i.nextSibling)););else{U_.innerHTML=EE(r==="svg"?``:r==="mathml"?``:t);const o=U_.content;if(r==="svg"||r==="mathml"){const c=o.firstChild;for(;c.firstChild;)o.appendChild(c.firstChild);o.removeChild(c)}e.insertBefore(o,n)}return[s?s.nextSibling:e.firstChild,n?n.previousSibling:e.lastChild]}},kn="transition",Mr="animation",Zr=Symbol("_vtc"),SE={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},iT=Ot({},Bg,SE),aT=t=>(t.displayName="Transition",t.props=iT,t),hr=aT((t,{slots:e})=>jf(tf,oT(t),e)),Wn=(t,e=[])=>{Ae(t)?t.forEach(n=>n(...e)):t&&t(...e)},F_=t=>t?Ae(t)?t.some(e=>e.length>1):t.length>1:!1;function oT(t){const e={};for(const I in t)I in SE||(e[I]=t[I]);if(t.css===!1)return e;const{name:n="v",type:r,duration:i,enterFromClass:a=`${n}-enter-from`,enterActiveClass:s=`${n}-enter-active`,enterToClass:o=`${n}-enter-to`,appearFromClass:c=a,appearActiveClass:_=s,appearToClass:l=o,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:u=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=t,p=sT(i),E=p&&p[0],f=p&&p[1],{onBeforeEnter:T,onEnter:R,onEnterCancelled:C,onLeave:h,onLeaveCancelled:A,onBeforeAppear:N=T,onAppear:x=R,onAppearCancelled:O=C}=e,M=(I,X,te,Se)=>{I._enterCancelled=Se,Kn(I,X?l:o),Kn(I,X?_:s),te&&te()},q=(I,X)=>{I._isLeaving=!1,Kn(I,d),Kn(I,m),Kn(I,u),X&&X()},V=I=>(X,te)=>{const Se=I?x:R,oe=()=>M(X,I,te);Wn(Se,[X,oe]),B_(()=>{Kn(X,I?c:a),hn(X,I?l:o),F_(Se)||G_(X,r,E,oe)})};return Ot(e,{onBeforeEnter(I){Wn(T,[I]),hn(I,a),hn(I,s)},onBeforeAppear(I){Wn(N,[I]),hn(I,c),hn(I,_)},onEnter:V(!1),onAppear:V(!0),onLeave(I,X){I._isLeaving=!0;const te=()=>q(I,X);hn(I,d),I._enterCancelled?(hn(I,u),H_(I)):(H_(I),hn(I,u)),B_(()=>{I._isLeaving&&(Kn(I,d),hn(I,m),F_(h)||G_(I,r,f,te))}),Wn(h,[I,te])},onEnterCancelled(I){M(I,!1,void 0,!0),Wn(C,[I])},onAppearCancelled(I){M(I,!0,void 0,!0),Wn(O,[I])},onLeaveCancelled(I){q(I),Wn(A,[I])}})}function sT(t){if(t==null)return null;if(at(t))return[ma(t.enter),ma(t.leave)];{const e=ma(t);return[e,e]}}function ma(t){return aS(t)}function hn(t,e){e.split(/\s+/).forEach(n=>n&&t.classList.add(n)),(t[Zr]||(t[Zr]=new Set)).add(e)}function Kn(t,e){e.split(/\s+/).forEach(r=>r&&t.classList.remove(r));const n=t[Zr];n&&(n.delete(e),n.size||(t[Zr]=void 0))}function B_(t){requestAnimationFrame(()=>{requestAnimationFrame(t)})}let lT=0;function G_(t,e,n,r){const i=t._endId=++lT,a=()=>{i===t._endId&&r()};if(n!=null)return setTimeout(a,n);const{type:s,timeout:o,propCount:c}=cT(t,e);if(!s)return r();const _=s+"end";let l=0;const d=()=>{t.removeEventListener(_,u),a()},u=m=>{m.target===t&&++l>=c&&d()};setTimeout(()=>{l(n[p]||"").split(", "),i=r(`${kn}Delay`),a=r(`${kn}Duration`),s=Y_(i,a),o=r(`${Mr}Delay`),c=r(`${Mr}Duration`),_=Y_(o,c);let l=null,d=0,u=0;e===kn?s>0&&(l=kn,d=s,u=a.length):e===Mr?_>0&&(l=Mr,d=_,u=c.length):(d=Math.max(s,_),l=d>0?s>_?kn:Mr:null,u=l?l===kn?a.length:c.length:0);const m=l===kn&&/\b(?:transform|all)(?:,|$)/.test(r(`${kn}Property`).toString());return{type:l,timeout:d,propCount:u,hasTransform:m}}function Y_(t,e){for(;t.lengthq_(n)+q_(t[r])))}function q_(t){return t==="auto"?0:Number(t.slice(0,-1).replace(",","."))*1e3}function H_(t){return(t?t.ownerDocument:document).body.offsetHeight}function _T(t,e,n){const r=t[Zr];r&&(e=(e?[e,...r]:[...r]).join(" ")),e==null?t.removeAttribute("class"):n?t.setAttribute("class",e):t.className=e}const $_=Symbol("_vod"),dT=Symbol("_vsh"),uT=Symbol(""),pT=/(?:^|;)\s*display\s*:/;function mT(t,e,n){const r=t.style,i=gt(n);let a=!1;if(n&&!i){if(e)if(gt(e))for(const s of e.split(";")){const o=s.slice(0,s.indexOf(":")).trim();n[o]==null&&bi(r,o,"")}else for(const s in e)n[s]==null&&bi(r,s,"");for(const s in n)s==="display"&&(a=!0),bi(r,s,n[s])}else if(i){if(e!==n){const s=r[uT];s&&(n+=";"+s),r.cssText=n,a=pT.test(n)}}else e&&t.removeAttribute("style");$_ in t&&(t[$_]=a?r.display:"",t[dT]&&(r.display="none"))}const V_=/\s*!important$/;function bi(t,e,n){if(Ae(n))n.forEach(r=>bi(t,e,r));else if(n==null&&(n=""),e.startsWith("--"))t.setProperty(e,n);else{const r=gT(t,e);V_.test(n)?t.setProperty(Gn(r),n.replace(V_,""),"important"):t[r]=n}}const z_=["Webkit","Moz","ms"],ga={};function gT(t,e){const n=ga[e];if(n)return n;let r=Gt(e);if(r!=="filter"&&r in t)return ga[e]=r;r=Yi(r);for(let i=0;iEa||(TT.then(()=>Ea=0),Ea=Date.now());function RT(t,e){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;nn(hT(r,n.value),e,5,[r])};return n.value=t,n.attached=bT(),n}function hT(t,e){if(Ae(e)){const n=t.stopImmediatePropagation;return t.stopImmediatePropagation=()=>{n.call(t),t._stopped=!0},e.map(r=>i=>!i._stopped&&r&&r(i))}else return e}const J_=t=>t.charCodeAt(0)===111&&t.charCodeAt(1)===110&&t.charCodeAt(2)>96&&t.charCodeAt(2)<123,CT=(t,e,n,r,i,a)=>{const s=i==="svg";e==="class"?_T(t,r,s):e==="style"?mT(t,n,r):Ui(e)?Fi(e)||ST(t,e,n,r,a):(e[0]==="."?(e=e.slice(1),!0):e[0]==="^"?(e=e.slice(1),!1):vT(t,e,r,s))?(Q_(t,e,r),!t.tagName.includes("-")&&(e==="value"||e==="checked"||e==="selected")&&K_(t,e,r,s,a,e!=="value")):t._isVueCE&&(NT(t,e)||t._def.__asyncLoader&&(/[A-Z]/.test(e)||!gt(r)))?Q_(t,Gt(e),r,a,e):(e==="true-value"?t._trueValue=r:e==="false-value"&&(t._falseValue=r),K_(t,e,r,s))};function vT(t,e,n,r){if(r)return!!(e==="innerHTML"||e==="textContent"||e in t&&J_(e)&&Ue(n));if(e==="spellcheck"||e==="draggable"||e==="translate"||e==="autocorrect"||e==="sandbox"&&t.tagName==="IFRAME"||e==="form"||e==="list"&&t.tagName==="INPUT"||e==="type"&&t.tagName==="TEXTAREA")return!1;if(e==="width"||e==="height"){const i=t.tagName;if(i==="IMG"||i==="VIDEO"||i==="CANVAS"||i==="SOURCE")return!1}return J_(e)&>(n)?!1:e in t}function NT(t,e){const n=t._def.props;if(!n)return!1;const r=Gt(e);return Array.isArray(n)?n.some(i=>Gt(i)===r):Object.keys(n).some(i=>Gt(i)===r)}const j_=t=>{const e=t.props["onUpdate:modelValue"]||!1;return Ae(e)?n=>Si(e,n):e};function OT(t){t.target.composing=!0}function ed(t){const e=t.target;e.composing&&(e.composing=!1,e.dispatchEvent(new Event("input")))}const Sa=Symbol("_assign");function td(t,e,n){return e&&(t=t.trim()),n&&(t=yc(t)),t}const IT={created(t,{modifiers:{lazy:e,trim:n,number:r}},i){t[Sa]=j_(i);const a=r||i.props&&i.props.type==="number";mr(t,e?"change":"input",s=>{s.target.composing||t[Sa](td(t.value,n,a))}),(n||a)&&mr(t,"change",()=>{t.value=td(t.value,n,a)}),e||(mr(t,"compositionstart",OT),mr(t,"compositionend",ed),mr(t,"change",ed))},mounted(t,{value:e}){t.value=e??""},beforeUpdate(t,{value:e,oldValue:n,modifiers:{lazy:r,trim:i,number:a}},s){if(t[Sa]=j_(s),t.composing)return;const o=(a||t.type==="number")&&!/^0\d/.test(t.value)?yc(t.value):t.value,c=e??"";if(o===c)return;const _=t.getRootNode();(_ instanceof Document||_ instanceof ShadowRoot)&&_.activeElement===t&&t.type!=="range"&&(r&&e===n||i&&t.value.trim()===c)||(t.value=c)}},yT=["ctrl","shift","alt","meta"],AT={stop:t=>t.stopPropagation(),prevent:t=>t.preventDefault(),self:t=>t.target!==t.currentTarget,ctrl:t=>!t.ctrlKey,shift:t=>!t.shiftKey,alt:t=>!t.altKey,meta:t=>!t.metaKey,left:t=>"button"in t&&t.button!==0,middle:t=>"button"in t&&t.button!==1,right:t=>"button"in t&&t.button!==2,exact:(t,e)=>yT.some(n=>t[`${n}Key`]&&!e.includes(n))},rr=(t,e)=>{if(!t)return t;const n=t._withMods||(t._withMods={}),r=e.join(".");return n[r]||(n[r]=((i,...a)=>{for(let s=0;s{const n=t._withKeys||(t._withKeys={}),r=e.join(".");return n[r]||(n[r]=(i=>{if(!("key"in i))return;const a=Gn(i.key);if(e.some(s=>s===a||DT[s]===a))return t(i)}))},MT=Ot({patchProp:CT},rT);let rd;function xT(){return rd||(rd=kf(MT))}const LT=((...t)=>{const e=xT().createApp(...t),{mount:n}=e;return e.mount=r=>{const i=PT(r);if(!i)return;const a=e._component;!Ue(a)&&!a.render&&!a.template&&(a.template=i.innerHTML),i.nodeType===1&&(i.textContent="");const s=n(i,!1,wT(i));return i instanceof Element&&(i.removeAttribute("v-cloak"),i.setAttribute("data-v-app","")),s},e});function wT(t){if(t instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&t instanceof MathMLElement)return"mathml"}function PT(t){return gt(t)?document.querySelector(t):t}/*!
- * pinia v3.0.4
- * (c) 2025 Eduardo San Martin Morote
- * @license MIT
- */let fE;const ji=t=>fE=t,TE=Symbol();function Ec(t){return t&&typeof t=="object"&&Object.prototype.toString.call(t)==="[object Object]"&&typeof t.toJSON!="function"}var qr;(function(t){t.direct="direct",t.patchObject="patch object",t.patchFunction="patch function"})(qr||(qr={}));function kT(){const t=Dc(!0),e=t.run(()=>_e({}));let n=[],r=[];const i=Vi({install(a){ji(i),i._a=a,a.provide(TE,i),a.config.globalProperties.$pinia=i,r.forEach(s=>n.push(s)),r=[]},use(a){return this._a?n.push(a):r.push(a),this},_p:n,_a:null,_e:t,_s:new Map,state:e});return i}const bE=()=>{};function id(t,e,n,r=bE){t.add(e);const i=()=>{t.delete(e)&&r()};return!n&&dg()&&mS(i),i}function dr(t,...e){t.forEach(n=>{n(...e)})}const UT=t=>t(),ad=Symbol(),fa=Symbol();function Sc(t,e){t instanceof Map&&e instanceof Map?e.forEach((n,r)=>t.set(r,n)):t instanceof Set&&e instanceof Set&&e.forEach(t.add,t);for(const n in e){if(!e.hasOwnProperty(n))continue;const r=e[n],i=t[n];Ec(i)&&Ec(r)&&t.hasOwnProperty(n)&&!bt(r)&&!An(r)?t[n]=Sc(i,r):t[n]=r}return t}const FT=Symbol();function BT(t){return!Ec(t)||!Object.prototype.hasOwnProperty.call(t,FT)}const{assign:Un}=Object;function GT(t){return!!(bt(t)&&t.effect)}function YT(t,e,n,r){const{state:i,actions:a,getters:s}=e,o=n.state.value[t];let c;function _(){o||(n.state.value[t]=i?i():{});const l=kS(n.state.value[t]);return Un(l,a,Object.keys(s||{}).reduce((d,u)=>(d[u]=Vi(Te(()=>{ji(n);const m=n._s.get(t);return s[u].call(m,m)})),d),{}))}return c=RE(t,_,e,n,r,!0),c}function RE(t,e,n={},r,i,a){let s;const o=Un({actions:{}},n),c={deep:!0};let _,l,d=new Set,u=new Set,m;const p=r.state.value[t];!a&&!p&&(r.state.value[t]={});let E;function f(O){let M;_=l=!1,typeof O=="function"?(O(r.state.value[t]),M={type:qr.patchFunction,storeId:t,events:m}):(Sc(r.state.value[t],O),M={type:qr.patchObject,payload:O,storeId:t,events:m});const q=E=Symbol();Ft().then(()=>{E===q&&(_=!0)}),l=!0,dr(d,M,r.state.value[t])}const T=a?function(){const{state:M}=n,q=M?M():{};this.$patch(V=>{Un(V,q)})}:bE;function R(){s.stop(),d.clear(),u.clear(),r._s.delete(t)}const C=(O,M="")=>{if(ad in O)return O[fa]=M,O;const q=function(){ji(r);const V=Array.from(arguments),I=new Set,X=new Set;function te(se){I.add(se)}function Se(se){X.add(se)}dr(u,{args:V,name:q[fa],store:A,after:te,onError:Se});let oe;try{oe=O.apply(this&&this.$id===t?this:A,V)}catch(se){throw dr(X,se),se}return oe instanceof Promise?oe.then(se=>(dr(I,se),se)).catch(se=>(dr(X,se),Promise.reject(se))):(dr(I,oe),oe)};return q[ad]=!0,q[fa]=M,q},h={_p:r,$id:t,$onAction:id.bind(null,u),$patch:f,$reset:T,$subscribe(O,M={}){const q=id(d,O,M.detached,()=>V()),V=s.run(()=>Ye(()=>r.state.value[t],I=>{(M.flush==="sync"?l:_)&&O({storeId:t,type:qr.direct,events:m},I)},Un({},c,M)));return q},$dispose:R},A=ei(h);r._s.set(t,A);const x=(r._a&&r._a.runWithContext||UT)(()=>r._e.run(()=>(s=Dc()).run(()=>e({action:C}))));for(const O in x){const M=x[O];if(bt(M)&&!GT(M)||An(M))a||(p&&BT(M)&&(bt(M)?M.value=p[O]:Sc(M,p[O])),r.state.value[t][O]=M);else if(typeof M=="function"){const q=C(M,O);x[O]=q,o.actions[O]=M}}return Un(A,x),Un(Xe(A),x),Object.defineProperty(A,"$state",{get:()=>r.state.value[t],set:O=>{f(M=>{Un(M,O)})}}),r._p.forEach(O=>{Un(A,s.run(()=>O({store:A,app:r._a,pinia:r,options:o})))}),p&&a&&n.hydrate&&n.hydrate(A.$state,p),_=!0,l=!0,A}/*! #__NO_SIDE_EFFECTS__ */function Vc(t,e,n){let r;const i=typeof e=="function";r=i?n:e;function a(s,o){const c=zS();return s=s||(c?er(TE,null):null),s&&ji(s),s=fE,s._s.has(t)||(i?RE(t,e,r,s):YT(t,r,s)),s._s.get(t)}return a.$id=t,a}const hE="";window.addEventListener("unhandledrejection",t=>{console.error("[API] Unhandled rejection:",t.reason)});async function an(t,e,n){const r={method:t,headers:{}};n!==void 0&&(r.headers["Content-Type"]="application/json",r.body=JSON.stringify(n));const i=await fetch(`${hE}${e}`,r);if(!i.ok){const a=await i.text().catch(()=>"");throw new Error(`${t} ${e} → ${i.status}: ${a}`)}return i.status===204?null:i.json()}function qT(){return an("GET","/agents/profiles")}function od({limit:t=30,offset:e=0,profileId:n=null}={}){const r=new URLSearchParams({limit:String(t),offset:String(e)});return n&&r.set("profile_id",n),an("GET",`/sessions?${r.toString()}`)}function sd(t){return an("GET",`/sessions/${t}`)}function HT(t){return an("POST","/sessions",{profile_id:t})}function $T(t){return an("DELETE",`/sessions/${t}`)}function VT(t,e){return an("PATCH",`/sessions/${t}/pin`,{pinned:e})}function zT(t){return an("POST",`/sessions/${t}/stop`)}function WT(t){return an("POST",`/sessions/${t}/generate-name`)}function KT(t){return an("GET",`/sessions/${t}/content`)}function QT(t){return an("GET",`/eval/feedback/${t}`)}function XT(t,e,n){return an("POST","/eval/feedback",{session_id:t,message_index:e,rating:n})}async function ZT(t,e){const n=new FormData;n.append("file",e);const r=await fetch(`${hE}/sessions/${t}/files`,{method:"POST",body:n});if(!r.ok){const i=await r.text().catch(()=>"");throw new Error(`Upload failed: ${r.status}: ${i}`)}return r.json()}const sr=Vc("sessions",()=>{const e=_e([]),n=_e(!1),r=_e(!1),i=_e(!0),a=_e(0),s=_e(null);async function o(p=null){s.value=p,n.value=!0;try{const E=await od({limit:30,offset:0,profileId:p}),f=Array.isArray(E)?E:E.items;e.value=f,i.value=Array.isArray(E)?!1:E.has_more,a.value=Array.isArray(E)?f.length:E.next_offset}finally{n.value=!1}}async function c(){if(!(n.value||r.value||!i.value)){r.value=!0;try{const p=await od({limit:30,offset:a.value,profileId:s.value}),E=Array.isArray(p)?p:p.items,f=new Set(e.value.map(T=>T.session_id));e.value=[...e.value,...E.filter(T=>!f.has(T.session_id))],i.value=Array.isArray(p)?!1:p.has_more,a.value=Array.isArray(p)?e.value.length:p.next_offset}finally{r.value=!1}}}async function _(p){const E=await HT(p);return e.value.unshift({session_id:E.session_id,profile_id:E.profile_id,created_at:E.created_at,last_active:E.created_at,message_count:0,preview:"",pinned:!1}),a.value+=1,E}async function l(p){await $T(p),e.value=e.value.filter(E=>E.session_id!==p),a.value=Math.max(0,a.value-1)}async function d(p,E){await VT(p,E);const f=e.value.map(T=>T.session_id===p?{...T,pinned:E}:T);f.sort((T,R)=>(R.pinned?1:0)-(T.pinned?1:0)),e.value=f}function u(p,E){const f=e.value.find(T=>T.session_id===p);f&&(f.preview=E)}function m(p,E){const f=e.value.find(T=>T.session_id===p);f&&(f.name=E)}return{sessions:e,loading:n,loadingMore:r,hasMore:i,currentProfileId:s,fetchSessions:o,fetchMoreSessions:c,createSession:_,deleteSession:l,pinSession:d,updatePreview:u,updateName:m}}),ii=Vc("profiles",()=>{const t=_e([]),e=_e(null),n=_e(!1);async function r(){n.value=!0;try{t.value=await qT(),t.value.length&&!e.value&&(e.value=t.value[0].id)}finally{n.value=!1}}function i(a){return t.value.find(s=>s.id===a)??null}return{profiles:t,selectedProfileId:e,loading:n,fetchProfiles:r,getProfile:i}});let ld=null;async function JT(t){try{const e=sr(),n=e.sessions.find(i=>i.session_id===t);if(n!=null&&n.name)return;const{name:r}=await WT(t);r&&e.updateName(t,r)}catch{}}const qt=Vc("chat",()=>{const t=_e(null),e=_e(null),n=_e([]),r=_e(!1),i=_e([]),a=_e([]),s=_e([]),o=_e(0),c=_e(0),_=_e(!1),l=Er(null),d=_e(!1);async function u(L){if(t.value!==L){ld=L,_.value=!0,n.value=[],s.value=[],r.value=!1,l.value=null,o.value=0,c.value=0;try{const $=await sd(L);if(ld!==L)return;e.value=$.profile_id??null,n.value=st($.messages??[]),await E(L),await f(L),$.context_token_count&&(o.value=$.context_token_count),$.max_context_tokens&&(c.value=$.max_context_tokens),t.value=L,location.hash=L}finally{_.value=!1}}}function m(){t.value=null,e.value=null,n.value=[],s.value=[],r.value=!1,l.value=null,o.value=0,c.value=0,location.hash=""}async function p(L){if(L)try{const $=await sd(L);e.value=$.profile_id??null,n.value=st($.messages??[]),await E(L),await f(L),$.context_token_count&&(o.value=$.context_token_count),$.max_context_tokens&&(c.value=$.max_context_tokens),l.value=null,r.value=!1}catch{}}async function E(L){var $,K;try{const{feedback:D=[]}=await QT(L);if(!D.length)return;const P=new Map(D.map(z=>[z.message_index,z.rating]));for(const z of n.value){if(z.role!=="assistant")continue;const j=(K=($=z.id)==null?void 0:$.startsWith)!=null&&K.call($,"h_")?Number(z.id.slice(2)):NaN;Number.isInteger(j)&&P.has(j)&&(z.rating=P.get(j))}}catch{}}async function f(L=t.value){if(!L){s.value=[];return}try{const{content:$=[]}=await KT(L);s.value=$}catch{s.value=[]}}function T(L){if(!(L!=null&&L.filename))return;const $=L.id||L.filename,K=s.value.findIndex(P=>(P.id||P.filename)===$),D={...L};K===-1?s.value.unshift(D):s.value.splice(K,1,{...s.value[K],...D})}async function R(L,$){var z,j;if(!t.value||!L)return;const K=(j=(z=L.id)==null?void 0:z.startsWith)!=null&&j.call(z,"h_")?Number(L.id.slice(2)):NaN;if(!Number.isInteger(K))return;const D=L.rating===$?0:$,P=L.rating??0;L.rating=D;try{await XT(t.value,K,D)}catch(ge){throw L.rating=P,ge}}function C(L){t.value&&(L?localStorage.setItem(`draft:${t.value}`,L):localStorage.removeItem(`draft:${t.value}`))}function h(L){return localStorage.getItem(`draft:${L}`)??""}function A(){if(l.value){const $=n.value.indexOf(l.value);$!==-1&&n.value.splice($,1),l.value=null}r.value=!0;const L={id:`stream_${Date.now()}`,role:"assistant",type:"stream",thinking:null,tools:[],text:"",done:!1,time:new Date().toISOString(),animate:!d.value,statusLabel:null};n.value.push(L),l.value=n.value[n.value.length-1]}function N(){d.value=!0}function x(){d.value=!1,l.value&&(l.value.animate=!0)}function O(L){const $=l.value;$&&($.thinking||($.thinking={text:"",done:!1}),$.thinking.text+=L)}function M(){const L=l.value;L!=null&&L.thinking&&(L.thinking.done=!0)}function q(L){for(let $=L.tools.length-1;$>=0;$--){const K=L.tools[$];if(K.kind==="tool"&&K.name==="spawn_agent")return K}}function V(L){const $=l.value;if(!$)return;const K={kind:"turn_thinking",isSubagent:L.is_subagent??!1,thinking:{text:L.thinking??"",done:!0}};if(L.is_subagent){const D=q($);if(D){D.steps.push(K);return}}$.tools.push(K)}function I(L){const $=l.value;if($){if(L.is_subagent){const K=q($);K&&(K.planningLabel=L.label??"");return}$.statusLabel=L.label??""}}function X(L){const $=l.value;if($){if(L.is_subagent){const K=q($);K&&(K.planningLabel=null,K.steps.push({kind:"plan",text:L.plan??""}));return}$.statusLabel=null,$.tools.push({kind:"plan",text:L.plan??""})}}function te(L){const $=l.value;if(!$)return;const K={kind:"tool",id:`tool_${Date.now()}`,name:L.tool,args:L.args,result:null,success:null,pending:!0,startedAt:Date.now(),isSubagent:L.is_subagent??!1,steps:[]};if(L.is_subagent){const D=q($);if(D){D.steps.push(K);return}}$.tools.push(K)}function Se(L){var D;const $=l.value;if(!$)return;if(L.is_subagent){const P=q($);if(P){let z=null;for(let j=P.steps.length-1;j>=0;j--){const ge=P.steps[j];if(ge.kind==="tool"&&ge.name===L.tool&&ge.pending){z=ge;break}}if(z){z.result=L.result,z.success=L.success!==!1,z.pending=!1;return}}}let K=null;for(let P=$.tools.length-1;P>=0;P--){const z=$.tools[P];if(z.kind==="tool"&&z.name===L.tool&&z.pending){K=z;break}}if(K&&(K.result=L.result,K.success=L.success!==!1,K.pending=!1,L.metadata&&(K.metadata=L.metadata),L.tool==="content_publish"&&K.success&&L.metadata&&T(L.metadata),L.tool==="filesystem"&&K.success&&t.value)){const P=typeof K.args=="object"?(D=K.args)==null?void 0:D.action:null;["write","edit"].includes(P)&&f(t.value)}}function oe(L){const $=l.value;$&&($.statusLabel&&($.statusLabel=null),$.text+=L)}function se(L){const $=l.value;$&&($.done=!0,$.elapsed_seconds=(L==null?void 0:L.elapsed_seconds)??null,$.tool_call_count=(L==null?void 0:L.tool_call_count)??null,$.token_count=(L==null?void 0:L.token_count)??null,l.value=null,!$.thinking&&!$.tools.length&&!$.text&&(n.value=n.value.filter(K=>K!==$))),r.value=!1,(L==null?void 0:L.context_tokens)!=null&&(o.value=L.context_tokens),(L==null?void 0:L.max_context_tokens)!=null&&(c.value=L.max_context_tokens),t.value&&($!=null&&$.text)&&sr().updatePreview(t.value,$.text.slice(0,80)),t.value&&JT(t.value)}function be(){const L=l.value;L&&(L.done=!0,l.value=null,!L.thinking&&!L.tools.length&&!L.text&&(n.value=n.value.filter($=>$!==L))),r.value=!1}function me(L){e.value=L.profile_id}function xe(L){(L==null?void 0:L.context_tokens)!=null&&(o.value=L.context_tokens),(L==null?void 0:L.max_context_tokens)!=null&&(c.value=L.max_context_tokens),n.value.push({id:`compress_${Date.now()}`,role:"system",type:"compression_notice",before:L.messages_before,after:L.messages_after,summary:L.summary??""})}function Be(L){r.value=!1,l.value=null,n.value.push({id:`err_${Date.now()}`,role:"system",type:"error",text:L.message??"An error occurred"})}function He(L,$,K){n.value.push({id:`user_${Date.now()}`,role:"user",text:L,images:[...$],files:[...K],time:new Date().toISOString(),animate:!0})}function st(L){var D,P;const $=[];let K=0;for(;Ktypeof ge=="string"&&ge.startsWith("data:")?ge:`data:image/jpeg;base64,${String(ge??"")}`);$.push({id:`h_${K}`,role:"user",text:z.content??"",images:j,files:z.files??[],time:z.created_at??null}),K++;continue}if(z.role==="assistant"){const j=`h_${K}`,ge=[];let g=null,S="",y=null;for(;K=L.length||L[K].role!=="assistant")break}}if(g||ge.length||S){let U=null,F=null,B=null;const Q=Number(j.slice(2));for(let J=Q;J>>0,1)},emit:function(e,n){(t.get(e)||[]).slice().map(function(r){r(n)}),(t.get("*")||[]).slice().map(function(r){r(e,n)})}}}function zc(t,e,n){if(!n)return e;const r=t==null?void 0:t[n];if(r==null)throw new Error(`Key is ${r} on item (keyField is '${n}')`);return r}function Jn(t,e){return t.map((n,r)=>zc(n,r,e))}function eb(t,e,n){const r=[],i=[];for(let a=0;a0?c:null)}return{keys:r,sizes:i}}function tb(t,e,n){if(!t||t.keys.length!==e.length||t.sizes.length!==e.length)return!1;for(let r=0;r0&&(r[t.keys[i]]=a)}return r}function vE(t,e){if(!t.length||e.length<=t.length)return 0;const n=t[0],r=e.indexOf(n);if(r<=0||r+t.lengthe.length-r)return 0;for(let i=0;i=n&&c<=o?null:t{}:n.onVscrollUpdate(f),d=Te(()=>{const I=ue(t);if(n.vscrollData.simpleArray){if(I.index==null)throw new Error("index is required when using simple-array mode with dynamic item measurement");return I.index}if(n.vscrollData.keyField in I.item)return I.item[n.vscrollData.keyField];throw new Error(`keyField '${n.vscrollData.keyField}' not found in your item. You should set a valid keyField prop on your Scroller`)}),u=Te(()=>n.vscrollData.sizes[d.value]||0),m=Te(()=>ue(t).active&&n.vscrollData.active);function p(){m.value?a!==d.value&&(a=d.value,i=null,s=null,h(d.value)):i=d.value}function E(){ue(t).watchData&&!n.resizeObserver?c=Ye(()=>ue(t).item,()=>{T()},{deep:!0}):c&&(c(),c=null)}function f({force:I}){!m.value&&I&&(s=d.value),(i===d.value||I||!u.value)&&p()}function T(){p()}function R(I){n.undefinedMap[I]&&n.undefinedSizeCount.value--,n.undefinedMap[I]=void 0}function C(I,X){if(n.vscrollData.sizes[I]){R(I);return}if(X){n.undefinedMap[I]||n.undefinedSizeCount.value++,n.undefinedMap[I]=!0;return}n.undefinedMap[I]&&(n.undefinedSizeCount.value--,n.undefinedMap[I]=!1)}function h(I){Ft(()=>{if(d.value===I){const X=ue(e);if(!X)return;const te=X.offsetWidth,Se=X.offsetHeight;A(te,Se)}a=null})}function A(I,X){const te=~~(n.direction.value==="vertical"?X:I);te&&u.value!==te&&N(te)}function N(I){var X,te;R(d.value),n.vscrollData.sizes[d.value]=I,ue(t).emitResize&&((te=(X=ue(r))==null?void 0:X.onResize)==null||te.call(X,d.value))}function x(){if(!n.resizeObserver||o)return;const I=ue(e);I&&(n.resizeObserver.observe(I),I.$_vs_id=d.value,I.$_vs_onResize=M,o=!0)}function O(){if(!n.resizeObserver||!o)return;const I=ue(e);I&&(n.resizeObserver.unobserve(I),I.$_vs_onResize=void 0,o=!1)}function M(I,X,te){d.value===I&&A(X,te)}_.push(Ye(()=>ue(t).watchData,()=>{E()})),n.resizeObserver||_.push(Ye(()=>ue(t).sizeDependencies,()=>{T()},{deep:!0})),_.push(Ye(d,(I,X)=>{const te=ue(e);te&&(te.$_vs_id=I),R(X),C(I,m.value);const Se=n.vscrollData.sizes[I];if(!Se){i=I,T();return}R(I),o&&(n.vscrollData.sizes[I]=Se)})),_.push(Ye(m,I=>{C(d.value,I),n.resizeObserver?I?x():O():I&&s===d.value&&p()})),E();function q(){m.value&&(p(),x())}function V(){l(),O(),R(d.value);const I=ue(e);I&&(I.$_vs_id=void 0,I.$_vs_onResize=void 0),c&&(c(),c=null);for(const X of _)X();_.length=0}return{id:d,size:u,finalActive:m,updateSize:p,mount:q,unmount:V}}const nb={itemsLimit:1e3};function OE(t){return typeof window<"u"&&t===window}const rb=(()=>{if(typeof document>"u")return"negative";const t=document.createElement("div"),e=document.createElement("div");t.style.width="4px",t.style.height="1px",t.style.overflow="auto",t.style.direction="rtl",e.style.width="8px",e.style.height="1px",t.appendChild(e),document.body.appendChild(t),t.scrollLeft=-1;const n=t.scrollLeft<0;return document.body.removeChild(t),n?"negative":"default"})();function gr(t,e,n){return e!=="horizontal"||!n||OE(n)||getComputedStyle(n).direction!=="rtl"?t:rb==="negative"?-t:t}function ib(t,e,n){return gr(t,e,n)}function Ta(t,e,n,r){const i=ib(n,e,t),a=!!(r!=null&&r.smooth);if(OE(t)){e==="vertical"?t.scrollTo({top:i,behavior:a?"smooth":"auto"}):t.scrollTo({left:i,behavior:a?"smooth":"auto"});return}if(typeof t.scrollTo=="function"){t.scrollTo(e==="vertical"?{top:i,behavior:a?"smooth":"auto"}:{left:i,behavior:a?"smooth":"auto"});return}e==="vertical"?t.scrollTop=i:t.scrollLeft=i}function ab(t,e,n){return n?e==="vertical"?window.innerHeight:window.innerWidth:e==="vertical"?t.clientHeight:t.clientWidth}const ob=/auto|scroll/;function IE(t,e){return t.parentNode===null?e:IE(t.parentNode,[...e,t])}function ba(t,e){return getComputedStyle(t,null).getPropertyValue(e)}function sb(t){return ba(t,"overflow")+ba(t,"overflow-y")+ba(t,"overflow-x")}function lb(t){return ob.test(sb(t))}function pi(t){if(!(t instanceof HTMLElement||t instanceof SVGElement))return;const e=IE(t.parentNode,[]);for(let n=0;n{const k=ue(t);return k.items.length>0&&typeof k.items[0]!="object"}),X=Te(()=>{const k=ue(t);if(k.itemSize===null){const H={[-1]:{accumulator:0}},ae=k.items,Ie=k.sizeField??"size",Ee=k.minItemSize,he=V.value;let we=1e4,ze=0,Ct;for(let Pe=0,Et=ae.length;Pea.value.filter(k=>k.nr.used).sort((k,H)=>k.nr.index-H.nr.index)),Se=Te(()=>{const k=ue(t),H=I.value?null:k.keyField;return eb(k.items,H,(ae,Ie,Ee)=>k.itemSize!=null?k.itemSize:V.value[Ee]||(ae==null?void 0:ae[k.sizeField??"size"])||void 0)});function oe(k){const H=ue(t);return V.value=fc(k,H.items,I.value?null:H.keyField),Object.keys(V.value).length>0}function se(k){let H=d.get(k);return H||(H=[],d.set(k,H)),H}function be(k,H,ae,Ie,Ee){const he=Vi({id:_b++,index:H,used:!0,key:Ie,type:Ee}),we=Og({item:ae,position:0,offset:0,nr:he,_vs_styleStamp:0});return k.push(we),we}function me(k){const H=se(k);if(H&&H.length){const ae=H.pop();return ae.nr.used=!0,Ra(ae),ae}}function xe(k){const H=k.nr.type;se(H).push(k),k.nr.used=!1,k.position=-9999,Ra(k),l.delete(k.nr.key)}function Be(){l.clear(),d.clear();for(let k=0,H=a.value.length;k{q.delete(H),k()}),q.add(H),H}function st(){for(const k of q)cancelAnimationFrame(k);q.clear()}function L(){f&&(clearTimeout(f),f=null),T&&(clearTimeout(T),T=null),R&&(clearTimeout(R),R=null),x&&(clearTimeout(x),x=null),O&&(clearTimeout(O),O=null)}function $(){var k;(k=i==null?void 0:i.onResize)==null||k.call(i),o.value&&le(!1)}function K(){N&&!M&&U();const k=ue(t);if(!u){if(u=!0,f)return;const H=()=>He(()=>{u=!1;const{continuous:ae}=le(!1,!0);ae||(T&&clearTimeout(T),T=setTimeout(K,k.updateInterval+100))});H(),k.updateInterval&&(f=setTimeout(()=>{f=null,u&&H()},k.updateInterval))}}function D(k,H){var ae,Ie;o.value&&(k||H.boundingClientRect.width!==0||H.boundingClientRect.height!==0?((ae=i==null?void 0:i.onVisible)==null||ae.call(i),He(()=>{le(!1)})):(Ie=i==null?void 0:i.onHidden)==null||Ie.call(i))}function P(){const k=ue(e),H=k?pi(k):void 0;return window.document&&(H===window.document.documentElement||H===window.document.body)?window:H||window}function z(){const k=ue(n);return k?ue(t).direction==="vertical"?k.scrollHeight:k.scrollWidth:0}function j(){const k=ue(e);if(!k)return{start:0,end:0};const H=ue(t),ae=H.direction==="vertical";let Ie;if(H.pageMode){const Ee=k.getBoundingClientRect(),he=ae?Ee.height:Ee.width;let we=-(ae?Ee.top:Ee.left),ze=ae?window.innerHeight:window.innerWidth;we<0&&(ze+=we,we=0),we+ze>he&&(ze=he-we),Ie={start:we,end:we+ze}}else ae?Ie={start:k.scrollTop,end:k.scrollTop+k.clientHeight}:Ie={start:gr(k.scrollLeft,H.direction,k),end:gr(k.scrollLeft,H.direction,k)+k.clientWidth};return Ie}function ge(){const k=ue(e);if(!k)return{start:0,end:0};if(ue(t).direction==="vertical"){const H=gr(k.scrollLeft,"horizontal",k);return{start:H,end:H+k.clientWidth}}return{start:k.scrollTop,end:k.scrollTop+k.clientHeight}}function g(k){const H=ue(t);if(H.itemSize!=null)return H.itemSize;const ae=X.value[k];return(ae==null?void 0:ae.size)||Number(H.minItemSize)||0}function S(k){var H;const ae=ue(t),Ie=ae.gridItems||1;return k<=0?0:ae.itemSize!=null?Math.floor(k/Ie)*ae.itemSize:((H=X.value[k-1])==null?void 0:H.accumulator)||0}function y(k){const H=ue(t),ae=H.items.length,Ie=H.gridItems||1;if(!ae)return 0;if(H.itemSize!=null){const ze=Math.floor(k/H.itemSize)*Ie;return Math.min(Math.max(ze,0),ae-1)}let Ee=0,he=ae-1,we=0;for(;Ee<=he;){const ze=Math.floor((Ee+he)/2);S(ze)<=k?(we=ze,Ee=ze+1):he=ze-1}return we}function U(){x&&(clearTimeout(x),x=null),N=null}function F(){x&&clearTimeout(x),x=setTimeout(()=>{N=null,x=null},150)}function B(k,H){if(!k.length){U();return}const ae=Math.max(j().start-z(),0),Ie=Math.min(y(ae),k.length-1),Ee=k[Ie],he=H?Ee==null?void 0:Ee[H]:Ie;if(he==null){U();return}const we=z()+S(Ie);N={key:he,offset:j().start-we}}function Q(k){if(!N)return!1;const H=ue(t),ae=k??H.items,Ie=I.value?null:H.keyField,Ee=Jn(ae,Ie).indexOf(N.key);if(Ee===-1)return U(),!1;const he=z()+S(Ee)+N.offset,we=j().start;return Math.abs(he-we)<.5?!1:(M=!0,nt(he),He(()=>{M=!1}),!0)}function J(){ue(t).pageMode?Z():W()}function Z(){h=P(),h.addEventListener("scroll",K,cb()?{passive:!0}:!1),h.addEventListener("resize",$)}function W(){h&&(h.removeEventListener("scroll",K),h.removeEventListener("resize",$),h=null)}function Ce(k,H,ae,Ie,Ee,he){const we=Math.ceil(k/H)*ae,ze=Math.max(0,Math.floor(Ee.start/ae)),Ct=Math.min(Math.ceil(Ee.end/ae),Math.ceil(k/H)),Pe=Math.max(0,Math.floor(he.start/Ie)),Et=Math.min(Math.ceil(he.end/Ie),H),St=[];for(let Y=ze;Y=k)break;St.push(je)}}const Je=St[0]??0,b=St.at(-1)??-1;return{renderedIndices:St,startIndex:Je,endIndex:b+1,visibleStartIndex:Je,visibleEndIndex:b,totalSize:we}}function ce(){const k=ue(t);if(!k.gridItems||k.itemSize==null)return!1;const H=ue(e);if(!H)return!1;const ae=k.itemSecondarySize||k.itemSize,Ie=k.direction==="vertical"?H.clientWidth:H.clientHeight;return ae*k.gridItems>Ie}function le(k,H=!1){var ae,Ie;const Ee=ue(t),he=Ee.itemSize,we=Ee.gridItems||1,ze=Ee.itemSecondarySize||he,Ct=C,Pe=Ee.typeField,Et=I.value?null:Ee.keyField,St=Ee.items,Je=St.length,b=X.value,Y=l,ne=a.value;let Ne=null,je=null,Ge,ie,pe,Re,rt;if(!Je)Ge=ie=Re=rt=pe=0;else if(E)Ge=Re=0,ie=rt=Math.min(Ee.prerender,St.length),pe=0;else{const $e=j(),Rt=ge();if(H){let Tt=$e.start-m;Tt<0&&(Tt=-Tt);let on=Rt.start-p;on<0&&(on=-on);const qn=he===null&&Tt>=Ct||he!==null&&Tt>=he,mt=we>1&&he!=null&&on>=ze;if(!qn&&!mt)return{continuous:!0}}m=$e.start,p=Rt.start;const Wt=Ee.buffer;$e.start-=Wt,$e.end+=Wt,Rt.start-=Wt,Rt.end+=Wt;let Jt=0;const wn=ue(n);wn&&(Jt=wn.scrollHeight,$e.start-=Jt);const Pn=ue(r);if(Pn){const Tt=Pn.scrollHeight;$e.end+=Tt}if(he===null){let Tt,on=0,qn=Je-1,mt=~~(Je/2),cr;do cr=mt,Tt=b[mt].accumulator,Tt<$e.start?on=mt:mt$e.start&&(qn=mt),mt=~~((on+qn)/2);while(mt!==cr);for(mt<0&&(mt=0),Ge=mt,pe=b[Je-1].accumulator,ie=mt;ieJe&&(ie=Je)),Re=Ge;Re1){const Tt=Ce(Je,we,he,ze,$e,Rt);Ne=Tt.renderedIndices,je=new Set(Ne),Ge=Tt.startIndex,ie=Tt.endIndex,Re=Tt.visibleStartIndex,rt=Tt.visibleEndIndex,pe=Tt.totalSize}else{Ge=~~($e.start/he*we);const Tt=Ge%we;Ge-=Tt,ie=Math.ceil($e.end/he*we),Re=Math.max(0,Math.floor(($e.start-Jt)/he*we)),rt=Math.floor(($e.end-Jt)/he*we),Ge<0&&(Ge=0),ie>Je&&(ie=Je),Re<0&&(Re=0),rt>Je&&(rt=Je),pe=Math.ceil(Je/we)*he}}ie-Ge>nb.itemsLimit&&ve(),s.value=pe;let De;const fn=Ge<=_&&ie>=c;if(!fn||k)Be();else for(let $e=0,Rt=ne.length;$e