From c0fc736ff12d4ad15393c865eec6b3835e5d2f41 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Mon, 1 Jun 2026 16:50:28 -0400 Subject: [PATCH] =?UTF-8?q?feat(automation):=20Phase=20B=20=E2=80=94=20ins?= =?UTF-8?q?ight=20auto-refresh,=20foundation=20auto-check,=20anchor=20life?= =?UTF-8?q?cycle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SSE event bus (backend/glossa_lab/api/events.py) with /api/v1/events/stream - Add foundation check automation (backend/glossa_lab/api/foundation.py) with POST /check, GET /status, PATCH /config, 15-min auto-check background task - Emit insight_trigger events on loop complete, staging archive, discovery fetch - Add anchor candidate auto-lifecycle: approved→verified→auto-archived when SA improves; rejected→expired after 7 days; auto-archive to anchor_staging_archive.json - Add POST /staging/archive endpoint for manual archive override - Mark foundation dirty on anchor changes and loop completion - Frontend: 20-min throttled insight auto-refresh with SSE subscription, freshness indicator (countdown/up-to-date/waiting), configurable interval (10/15/20/30/60m stored in localStorage) - DeciphermentPanel: foundation auto-check status display with toggle button - ResearchLoopPanel: lifecycle stage badges (staged→approved→verified→archived), auto-verified count in all-reviewed CTA - Register events_router and foundation_automation_router in main.py - Start foundation auto-check background task on app startup Co-Authored-By: Oz --- backend/glossa_lab/api/events.py | 96 + backend/glossa_lab/api/foundation.py | 168 ++ backend/glossa_lab/api/research_loop.py | 197 ++ backend/glossa_lab/main.py | 9 + frontend/dist/assets/index-BXsZCCru.js | 2412 ----------------- frontend/dist/assets/index-Cc6zRBpg.js | 2412 +++++++++++++++++ frontend/dist/index.html | 4 +- frontend/src/api.ts | 39 + frontend/src/components/DashboardView.tsx | 108 + frontend/src/components/DeciphermentPanel.tsx | 81 +- frontend/src/components/ResearchLoopPanel.tsx | 48 +- 11 files changed, 3152 insertions(+), 2422 deletions(-) create mode 100644 backend/glossa_lab/api/events.py create mode 100644 backend/glossa_lab/api/foundation.py delete mode 100644 frontend/dist/assets/index-BXsZCCru.js create mode 100644 frontend/dist/assets/index-Cc6zRBpg.js diff --git a/backend/glossa_lab/api/events.py b/backend/glossa_lab/api/events.py new file mode 100644 index 00000000..521f5bbc --- /dev/null +++ b/backend/glossa_lab/api/events.py @@ -0,0 +1,96 @@ +"""Lightweight in-memory event bus + SSE endpoint. + +Provides a simple pub/sub mechanism for broadcasting real-time events +to frontend subscribers via Server-Sent Events. + +Usage (emitting events from other modules): + from glossa_lab.api.events import emit_event + await emit_event("insight_trigger", reason="loop_complete") + +Usage (subscribing from frontend): + const es = new EventSource("/api/v1/events/stream"); + es.onmessage = (e) => { const data = JSON.parse(e.data); ... }; +""" +from __future__ import annotations + +import asyncio +import json +import logging +from datetime import UTC, datetime +from typing import Any + +from fastapi import APIRouter +from fastapi.responses import StreamingResponse + +router = APIRouter(prefix="/api/v1/events", tags=["events"]) +_log = logging.getLogger("glossa_lab.api.events") + +# ── In-memory event bus ────────────────────────────────────────────────── +# Maps event_name → set of asyncio.Queue subscribers. +# Each subscriber gets its own queue; emit fans out to all of them. +_subscribers: dict[str, set[asyncio.Queue]] = {} +_ALL = "__all__" # wildcard channel — receives every event + + +def _ensure_channel(channel: str) -> set[asyncio.Queue]: + if channel not in _subscribers: + _subscribers[channel] = set() + return _subscribers[channel] + + +async def emit_event(event_type: str, **kwargs: Any) -> None: + """Broadcast an event to all subscribers of *event_type* and the wildcard channel.""" + payload = { + "type": event_type, + "timestamp": datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z"), + **kwargs, + } + _log.debug("Event emitted: %s", event_type) + for channel in (event_type, _ALL): + for q in list(_ensure_channel(channel)): + try: + q.put_nowait(payload) + except asyncio.QueueFull: + pass # drop if subscriber is slow + + +def subscribe(channel: str = _ALL, maxsize: int = 64) -> asyncio.Queue: + """Create a new subscription queue for the given channel.""" + q: asyncio.Queue = asyncio.Queue(maxsize=maxsize) + _ensure_channel(channel).add(q) + return q + + +def unsubscribe(q: asyncio.Queue, channel: str = _ALL) -> None: + """Remove a subscription queue.""" + subs = _subscribers.get(channel) + if subs: + subs.discard(q) + + +# ── SSE endpoint ───────────────────────────────────────────────────────── + +@router.get("/stream") +async def event_stream() -> StreamingResponse: + """SSE endpoint — streams all events to the client with 30 s keep-alive.""" + + async def _generate(): + q = subscribe(_ALL) + try: + while True: + try: + payload = await asyncio.wait_for(q.get(), timeout=30.0) + yield f"data: {json.dumps(payload)}\n\n" + except asyncio.TimeoutError: + # Keep-alive comment so proxies don't close the connection + yield ": keep-alive\n\n" + except asyncio.CancelledError: + pass + finally: + unsubscribe(q, _ALL) + + return StreamingResponse( + _generate(), + media_type="text/event-stream", + headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}, + ) diff --git a/backend/glossa_lab/api/foundation.py b/backend/glossa_lab/api/foundation.py new file mode 100644 index 00000000..156ba02b --- /dev/null +++ b/backend/glossa_lab/api/foundation.py @@ -0,0 +1,168 @@ +"""Foundation check automation API. + +POST /api/v1/foundation/check — run foundation check synchronously +GET /api/v1/foundation/status — last check result + auto-check state +PATCH /api/v1/foundation/config — enable/disable auto-checks + +A background task runs every 15 minutes; if the `foundation_dirty` flag +is set (by anchor changes or SA experiments), it triggers a check +automatically and clears the flag. +""" +from __future__ import annotations + +import asyncio +import json +import logging +from datetime import UTC, datetime +from pathlib import Path +from typing import Any + +from fastapi import APIRouter +from pydantic import BaseModel + +router = APIRouter(prefix="/api/v1/foundation", tags=["foundation"]) +_log = logging.getLogger("glossa_lab.api.foundation") + +_REPO = Path(__file__).resolve().parents[3] +_CONFIG_PATH = _REPO / "backend" / "outputs" / "foundation_config.json" + +# ── Mutable state ──────────────────────────────────────────────────────── +_foundation_dirty: bool = False +_last_result: dict[str, Any] | None = None +_last_checked_at: str | None = None +_check_running: bool = False +_bg_task: asyncio.Task | None = None + + +# ── Config persistence ─────────────────────────────────────────────────── + +def _load_config() -> dict[str, Any]: + try: + if _CONFIG_PATH.exists(): + return json.loads(_CONFIG_PATH.read_text(encoding="utf-8")) + except Exception: # noqa: BLE001 + pass + return {"auto_check_enabled": True} + + +def _save_config(cfg: dict[str, Any]) -> None: + try: + _CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) + _CONFIG_PATH.write_text(json.dumps(cfg, indent=2), encoding="utf-8") + except Exception as exc: # noqa: BLE001 + _log.warning("Could not save foundation config: %s", exc) + + +def mark_dirty() -> None: + """Set the dirty flag — call when anchors change or SA experiments finish.""" + global _foundation_dirty # noqa: PLW0603 + _foundation_dirty = True + _log.debug("Foundation marked dirty") + + +# ── Core check runner ──────────────────────────────────────────────────── + +async def _run_check() -> dict[str, Any]: + """Run foundation check synchronously (reuses existing _run_foundation_check).""" + global _last_result, _last_checked_at, _check_running, _foundation_dirty # noqa: PLW0603 + if _check_running: + return _last_result or {"error": "check already in progress"} + _check_running = True + try: + from glossa_lab.api.research_loop import _run_foundation_check # noqa: PLC0415 + result = await _run_foundation_check() + now = datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z") + _last_result = result + _last_checked_at = now + _foundation_dirty = False + + # Emit event for frontend + try: + from glossa_lab.api.events import emit_event # noqa: PLC0415 + await emit_event("foundation_complete", result=result) + except Exception: # noqa: BLE001 + pass + + _log.info( + "Foundation check complete: %d ok, %d fail, %d warn", + result.get("n_ok", 0), result.get("n_fail", 0), result.get("n_warn", 0), + ) + return result + except Exception as exc: # noqa: BLE001 + _log.warning("Foundation check failed: %s", exc) + return {"error": str(exc)} + finally: + _check_running = False + + +# ── Background auto-check task ─────────────────────────────────────────── + +async def _auto_check_loop() -> None: + """Background task: checks every 15 minutes if dirty and enabled.""" + while True: + await asyncio.sleep(15 * 60) # 15 minutes + try: + cfg = _load_config() + if not cfg.get("auto_check_enabled", True): + continue + if not _foundation_dirty: + continue + if _check_running: + continue + _log.info("Auto foundation check triggered (dirty flag set)") + await _run_check() + except Exception as exc: # noqa: BLE001 + _log.warning("Auto foundation check error: %s", exc) + + +def start_auto_check() -> None: + """Start the background auto-check task (call once at app startup).""" + global _bg_task # noqa: PLW0603 + if _bg_task is None or _bg_task.done(): + _bg_task = asyncio.create_task(_auto_check_loop()) + _log.info("Foundation auto-check background task started") + + +# ── API endpoints ──────────────────────────────────────────────────────── + +@router.post("/check") +async def check_foundation() -> dict[str, Any]: + """Run foundation check synchronously and return results.""" + return await _run_check() + + +@router.get("/status") +async def foundation_status() -> dict[str, Any]: + """Return last check result and auto-check state.""" + cfg = _load_config() + result: dict[str, Any] = { + "last_checked_at": _last_checked_at, + "auto_check_enabled": cfg.get("auto_check_enabled", True), + "dirty": _foundation_dirty, + "running": _check_running, + } + if _last_result: + result["verdict"] = _last_result.get("verdict", "UNKNOWN") + result["n_ok"] = _last_result.get("n_ok", 0) + result["n_fail"] = _last_result.get("n_fail", 0) + result["n_warn"] = _last_result.get("n_warn", 0) + else: + result["verdict"] = None + result["n_ok"] = 0 + result["n_fail"] = 0 + result["n_warn"] = 0 + return result + + +class FoundationConfigUpdate(BaseModel): + auto_check_enabled: bool | None = None + + +@router.patch("/config") +async def update_foundation_config(body: FoundationConfigUpdate) -> dict[str, Any]: + """Enable/disable auto-checks.""" + cfg = _load_config() + if body.auto_check_enabled is not None: + cfg["auto_check_enabled"] = body.auto_check_enabled + _save_config(cfg) + return {"ok": True, **cfg} diff --git a/backend/glossa_lab/api/research_loop.py b/backend/glossa_lab/api/research_loop.py index ba81b8b2..7f6a1571 100644 --- a/backend/glossa_lab/api/research_loop.py +++ b/backend/glossa_lab/api/research_loop.py @@ -15,6 +15,7 @@ import logging import subprocess import sys +import time as _time from datetime import UTC, datetime from pathlib import Path from typing import Any @@ -245,6 +246,26 @@ def _producer(): except Exception: # noqa: BLE001 pass + # ── Anchor lifecycle: auto-verify approved candidates ─────────── + _run_anchor_lifecycle(loop, synthesis) + + # ── Emit event for SSE subscribers ────────────────────────────── + try: + from glossa_lab.api.events import emit_event # noqa: PLC0415 + asyncio.create_task(emit_event( + "insight_trigger", reason="loop_complete", + job_id=job_id, cycles=cycles_done, + )) + except Exception: # noqa: BLE001 + pass + + # Mark foundation dirty after loop run + try: + from glossa_lab.api.foundation import mark_dirty # noqa: PLC0415 + mark_dirty() + except Exception: # noqa: BLE001 + pass + yield f"data: {json.dumps({'type': 'complete', 'job_id': job_id, **loop.get_full_results(), 'synthesis': synthesis})}\n\n" return StreamingResponse( @@ -493,10 +514,186 @@ async def staging_action(body: dict[str, Any]) -> dict[str, Any]: remaining = sum(1 for c in updated if c.get("review_status") == "staged") _log.info("Staging action %s on %s=%s; %d staged remaining", action, sign, reading, remaining) + + # Mark foundation dirty when anchors change + if action in ("approve", "reject"): + try: + from glossa_lab.api.foundation import mark_dirty # noqa: PLC0415 + mark_dirty() + except Exception: # noqa: BLE001 + pass + return {"ok": True, "action": action, "sign": sign, "proposed_reading": reading, "staged_remaining": remaining} +_ARCHIVE_JSON = _REPO / "outputs" / "anchor_staging_archive.json" + + +def _run_anchor_lifecycle( + loop: Any, + synthesis: dict[str, Any], +) -> None: + """Auto-lifecycle for anchor candidates after a loop run. + + - Approved candidates become 'verified' if SA confidence improved, + stay 'approved' if inconclusive. + - Verified candidates are auto-archived. + - Rejected candidates older than 7 days become 'expired' and are archived. + """ + if not _STAGING_JSON.exists(): + return + try: + candidates: list[dict] = json.loads( + _STAGING_JSON.read_text(encoding="utf-8")) + except Exception: + return + + now_iso = datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z") + now_ts = _time.time() + sa_delta = 0.0 + + # Check if SA confidence improved from synthesis foundation_check + fc = synthesis.get("foundation_check", {}) + if fc and not fc.get("skipped"): + # Positive signal if no failures + sa_delta = 0.1 if fc.get("n_fail", 0) == 0 else -0.05 + + to_archive: list[dict] = [] + remaining: list[dict] = [] + auto_verified_count = 0 + + for c in candidates: + status = c.get("review_status", "staged") + + # Approved → verified if SA improved + if status == "approved" and sa_delta > 0: + c["review_status"] = "verified" + c["verified_at"] = now_iso + c["sa_delta"] = sa_delta + auto_verified_count += 1 + # Auto-archive verified candidates + c["archived_at"] = now_iso + c["archived_reason"] = "auto_verified" + to_archive.append(c) + continue + + # Rejected for > 7 days → expired and archived + if status == "rejected": + rejected_at = c.get("rejected_at", "") + if rejected_at: + try: + rej_ts = datetime.fromisoformat( + rejected_at.replace("Z", "+00:00") + ).timestamp() + if now_ts - rej_ts > 7 * 86400: + c["review_status"] = "expired" + c["expired_at"] = now_iso + c["archived_at"] = now_iso + c["archived_reason"] = "expired_after_7d" + to_archive.append(c) + continue + except Exception: # noqa: BLE001 + pass + + remaining.append(c) + + if to_archive: + # Append to archive file + archive: list[dict] = [] + if _ARCHIVE_JSON.exists(): + try: + archive = json.loads(_ARCHIVE_JSON.read_text(encoding="utf-8")) + except Exception: # noqa: BLE001 + pass + archive.extend(to_archive) + _ARCHIVE_JSON.write_text( + json.dumps(archive, indent=2, ensure_ascii=False), encoding="utf-8") + + # Update staging with remaining + _STAGING_JSON.write_text( + json.dumps(remaining, indent=2, ensure_ascii=False), encoding="utf-8") + + _log.info( + "Anchor lifecycle: %d auto-verified and archived, %d remaining", + auto_verified_count, len(remaining), + ) + + # Emit lifecycle event + try: + from glossa_lab.api.events import emit_event # noqa: PLC0415 + import asyncio as _aio # noqa: PLC0415 + _aio.create_task(emit_event( + "lifecycle_advance", + auto_verified=auto_verified_count, + archived=len(to_archive), + remaining=len(remaining), + )) + except Exception: # noqa: BLE001 + pass + + +@router.post("/staging/archive") +async def archive_staging() -> dict[str, Any]: + """Archive all approved and rejected candidates from staging. + + Moves them to anchor_staging_archive.json with timestamps. + Manual override — the auto-lifecycle also archives verified candidates. + """ + if not _STAGING_JSON.exists(): + return {"ok": False, "error": "staging file not found"} + + try: + candidates: list[dict] = json.loads( + _STAGING_JSON.read_text(encoding="utf-8")) + except Exception as exc: + return {"ok": False, "error": f"could not read staging: {exc}"} + + now = datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z") + to_archive = [] + remaining = [] + + for c in candidates: + status = c.get("review_status", "staged") + if status in ("approved", "rejected", "verified", "expired"): + c["archived_at"] = now + c.setdefault("archived_reason", "manual_archive") + to_archive.append(c) + else: + remaining.append(c) + + if not to_archive: + return {"ok": True, "archived": 0, "remaining": len(remaining)} + + # Append to archive + archive: list[dict] = [] + if _ARCHIVE_JSON.exists(): + try: + archive = json.loads(_ARCHIVE_JSON.read_text(encoding="utf-8")) + except Exception: # noqa: BLE001 + pass + archive.extend(to_archive) + _ARCHIVE_JSON.write_text( + json.dumps(archive, indent=2, ensure_ascii=False), encoding="utf-8") + + # Update staging + _STAGING_JSON.write_text( + json.dumps(remaining, indent=2, ensure_ascii=False), encoding="utf-8") + + _log.info("Manual archive: %d candidates archived, %d remaining", + len(to_archive), len(remaining)) + + # Emit event + try: + from glossa_lab.api.events import emit_event # noqa: PLC0415 + await emit_event("insight_trigger", reason="staging_archived", + archived=len(to_archive)) + except Exception: # noqa: BLE001 + pass + + return {"ok": True, "archived": len(to_archive), "remaining": len(remaining)} + + @router.get("/last-run") async def last_run() -> dict[str, Any]: """Return the synthesis + full results from the most recently completed loop job. diff --git a/backend/glossa_lab/main.py b/backend/glossa_lab/main.py index 55ef1992..067a3c57 100644 --- a/backend/glossa_lab/main.py +++ b/backend/glossa_lab/main.py @@ -30,6 +30,8 @@ from glossa_lab.api.dashboard import router as dashboard_router from glossa_lab.api.discovery import router as discovery_router from glossa_lab.api.env import router as env_router +from glossa_lab.api.events import router as events_router +from glossa_lab.api.foundation import router as foundation_automation_router from glossa_lab.api.experiment_graphs import router as experiment_graphs_router from glossa_lab.api.experiments import router as experiments_router from glossa_lab.api.foundation_check import router as foundation_check_router @@ -292,6 +294,11 @@ async def _auto_startup_fetch() -> None: _log.info("Auto-fetch: skipped or failed (%s)", _exc) asyncio.create_task(_auto_startup_fetch()) + + # Start foundation auto-check background task + from glossa_lab.api.foundation import start_auto_check # noqa: PLC0415 + start_auto_check() + yield # Shutdown: stop engine + scheduler, close database, flush logs _log.info("=== Glossa Lab shutting down ===") @@ -378,6 +385,8 @@ def create_app() -> FastAPI: application.include_router(model_intelligence_router) # /api/v1/model-intelligence application.include_router(indus_evidence_router) # already prefixed at /api/v1/indus-evidence application.include_router(research_loop_router) # already prefixed at /api/v1/research-loop + application.include_router(events_router) # already prefixed at /api/v1/events + application.include_router(foundation_automation_router) # already prefixed at /api/v1/foundation # Serve built frontend # Skipped silently in dev if the dist directory does not yet exist. diff --git a/frontend/dist/assets/index-BXsZCCru.js b/frontend/dist/assets/index-BXsZCCru.js deleted file mode 100644 index c349e9f9..00000000 --- a/frontend/dist/assets/index-BXsZCCru.js +++ /dev/null @@ -1,2412 +0,0 @@ -(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))l(c);new MutationObserver(c=>{for(const d of c)if(d.type==="childList")for(const u of d.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&l(u)}).observe(document,{childList:!0,subtree:!0});function r(c){const d={};return c.integrity&&(d.integrity=c.integrity),c.referrerPolicy&&(d.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?d.credentials="include":c.crossOrigin==="anonymous"?d.credentials="omit":d.credentials="same-origin",d}function l(c){if(c.ep)return;c.ep=!0;const d=r(c);fetch(c.href,d)}})();function cb(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Cf={exports:{}},fa={};/** - * @license React - * react-jsx-runtime.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Hx;function Yw(){if(Hx)return fa;Hx=1;var t=Symbol.for("react.transitional.element"),o=Symbol.for("react.fragment");function r(l,c,d){var u=null;if(d!==void 0&&(u=""+d),c.key!==void 0&&(u=""+c.key),"key"in c){d={};for(var p in c)p!=="key"&&(d[p]=c[p])}else d=c;return c=d.ref,{$$typeof:t,type:l,key:u,ref:c!==void 0?c:null,props:d}}return fa.Fragment=o,fa.jsx=r,fa.jsxs=r,fa}var Wx;function Vw(){return Wx||(Wx=1,Cf.exports=Yw()),Cf.exports}var n=Vw(),Tf={exports:{}},Xe={};/** - * @license React - * react.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Ux;function Xw(){if(Ux)return Xe;Ux=1;var t=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),l=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),d=Symbol.for("react.consumer"),u=Symbol.for("react.context"),p=Symbol.for("react.forward_ref"),g=Symbol.for("react.suspense"),h=Symbol.for("react.memo"),v=Symbol.for("react.lazy"),y=Symbol.for("react.activity"),b=Symbol.iterator;function S(N){return N===null||typeof N!="object"?null:(N=b&&N[b]||N["@@iterator"],typeof N=="function"?N:null)}var k={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,T={};function w(N,O,$){this.props=N,this.context=O,this.refs=T,this.updater=$||k}w.prototype.isReactComponent={},w.prototype.setState=function(N,O){if(typeof N!="object"&&typeof N!="function"&&N!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,N,O,"setState")},w.prototype.forceUpdate=function(N){this.updater.enqueueForceUpdate(this,N,"forceUpdate")};function C(){}C.prototype=w.prototype;function j(N,O,$){this.props=N,this.context=O,this.refs=T,this.updater=$||k}var L=j.prototype=new C;L.constructor=j,_(L,w.prototype),L.isPureReactComponent=!0;var W=Array.isArray;function P(){}var z={H:null,A:null,T:null,S:null},M=Object.prototype.hasOwnProperty;function q(N,O,$){var F=$.ref;return{$$typeof:t,type:N,key:O,ref:F!==void 0?F:null,props:$}}function K(N,O){return q(N.type,O,N.props)}function D(N){return typeof N=="object"&&N!==null&&N.$$typeof===t}function Y(N){var O={"=":"=0",":":"=2"};return"$"+N.replace(/[=:]/g,function($){return O[$]})}var H=/\/+/g;function A(N,O){return typeof N=="object"&&N!==null&&N.key!=null?Y(""+N.key):O.toString(36)}function G(N){switch(N.status){case"fulfilled":return N.value;case"rejected":throw N.reason;default:switch(typeof N.status=="string"?N.then(P,P):(N.status="pending",N.then(function(O){N.status==="pending"&&(N.status="fulfilled",N.value=O)},function(O){N.status==="pending"&&(N.status="rejected",N.reason=O)})),N.status){case"fulfilled":return N.value;case"rejected":throw N.reason}}throw N}function R(N,O,$,F,I){var J=typeof N;(J==="undefined"||J==="boolean")&&(N=null);var ne=!1;if(N===null)ne=!0;else switch(J){case"bigint":case"string":case"number":ne=!0;break;case"object":switch(N.$$typeof){case t:case o:ne=!0;break;case v:return ne=N._init,R(ne(N._payload),O,$,F,I)}}if(ne)return I=I(N),ne=F===""?"."+A(N,0):F,W(I)?($="",ne!=null&&($=ne.replace(H,"$&/")+"/"),R(I,O,$,"",function(_e){return _e})):I!=null&&(D(I)&&(I=K(I,$+(I.key==null||N&&N.key===I.key?"":(""+I.key).replace(H,"$&/")+"/")+ne)),O.push(I)),1;ne=0;var se=F===""?".":F+":";if(W(N))for(var pe=0;pe>>1,Q=R[V];if(0>>1;Vc($,B))Fc(I,$)?(R[V]=I,R[F]=B,V=F):(R[V]=$,R[O]=B,V=O);else if(Fc(I,B))R[V]=I,R[F]=B,V=F;else break e}}return X}function c(R,X){var B=R.sortIndex-X.sortIndex;return B!==0?B:R.id-X.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var d=performance;t.unstable_now=function(){return d.now()}}else{var u=Date,p=u.now();t.unstable_now=function(){return u.now()-p}}var g=[],h=[],v=1,y=null,b=3,S=!1,k=!1,_=!1,T=!1,w=typeof setTimeout=="function"?setTimeout:null,C=typeof clearTimeout=="function"?clearTimeout:null,j=typeof setImmediate<"u"?setImmediate:null;function L(R){for(var X=r(h);X!==null;){if(X.callback===null)l(h);else if(X.startTime<=R)l(h),X.sortIndex=X.expirationTime,o(g,X);else break;X=r(h)}}function W(R){if(_=!1,L(R),!k)if(r(g)!==null)k=!0,P||(P=!0,Y());else{var X=r(h);X!==null&&G(W,X.startTime-R)}}var P=!1,z=-1,M=5,q=-1;function K(){return T?!0:!(t.unstable_now()-qR&&K());){var V=y.callback;if(typeof V=="function"){y.callback=null,b=y.priorityLevel;var Q=V(y.expirationTime<=R);if(R=t.unstable_now(),typeof Q=="function"){y.callback=Q,L(R),X=!0;break t}y===r(g)&&l(g),L(R)}else l(g);y=r(g)}if(y!==null)X=!0;else{var N=r(h);N!==null&&G(W,N.startTime-R),X=!1}}break e}finally{y=null,b=B,S=!1}X=void 0}}finally{X?Y():P=!1}}}var Y;if(typeof j=="function")Y=function(){j(D)};else if(typeof MessageChannel<"u"){var H=new MessageChannel,A=H.port2;H.port1.onmessage=D,Y=function(){A.postMessage(null)}}else Y=function(){w(D,0)};function G(R,X){z=w(function(){R(t.unstable_now())},X)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(R){R.callback=null},t.unstable_forceFrameRate=function(R){0>R||125V?(R.sortIndex=B,o(h,R),r(g)===null&&R===r(h)&&(_?(C(z),z=-1):_=!0,G(W,B-V))):(R.sortIndex=Q,o(g,R),k||S||(k=!0,P||(P=!0,Y()))),R},t.unstable_shouldYield=K,t.unstable_wrapCallback=function(R){var X=b;return function(){var B=b;b=X;try{return R.apply(this,arguments)}finally{b=B}}}})(Rf)),Rf}var Px;function Qw(){return Px||(Px=1,Ef.exports=Kw()),Ef.exports}var Af={exports:{}},mn={};/** - * @license React - * react-dom.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Fx;function Zw(){if(Fx)return mn;Fx=1;var t=Fa();function o(g){var h="https://react.dev/errors/"+g;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(o){console.error(o)}}return t(),Af.exports=Zw(),Af.exports}/** - * @license React - * react-dom-client.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Vx;function e2(){if(Vx)return pa;Vx=1;var t=Qw(),o=Fa(),r=db();function l(e){var i="https://react.dev/errors/"+e;if(1Q||(e.current=V[Q],V[Q]=null,Q--)}function $(e,i){Q++,V[Q]=e.current,e.current=i}var F=N(null),I=N(null),J=N(null),ne=N(null);function se(e,i){switch($(J,i),$(I,e),$(F,null),i.nodeType){case 9:case 11:e=(e=i.documentElement)&&(e=e.namespaceURI)?cx(e):0;break;default:if(e=i.tagName,i=i.namespaceURI)i=cx(i),e=dx(i,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}O(F),$(F,e)}function pe(){O(F),O(I),O(J)}function _e(e){e.memoizedState!==null&&$(ne,e);var i=F.current,s=dx(i,e.type);i!==s&&($(I,e),$(F,s))}function we(e){I.current===e&&(O(F),O(I)),ne.current===e&&(O(ne),la._currentValue=B)}var ke,te;function de(e){if(ke===void 0)try{throw Error()}catch(s){var i=s.stack.trim().match(/\n( *(at )?)/);ke=i&&i[1]||"",te=-1)":-1f||Z[a]!==ce[f]){var be=` -`+Z[a].replace(" at new "," at ");return e.displayName&&be.includes("")&&(be=be.replace("",e.displayName)),be}while(1<=a&&0<=f);break}}}finally{Ce=!1,Error.prepareStackTrace=s}return(s=e?e.displayName||e.name:"")?de(s):""}function ve(e,i){switch(e.tag){case 26:case 27:case 5:return de(e.type);case 16:return de("Lazy");case 13:return e.child!==i&&i!==null?de("Suspense Fallback"):de("Suspense");case 19:return de("SuspenseList");case 0:case 15:return ze(e.type,!1);case 11:return ze(e.type.render,!1);case 1:return ze(e.type,!0);case 31:return de("Activity");default:return""}}function De(e){try{var i="",s=null;do i+=ve(e,s),s=e,e=e.return;while(e);return i}catch(a){return` -Error generating stack: `+a.message+` -`+a.stack}}var Me=Object.prototype.hasOwnProperty,Ve=t.unstable_scheduleCallback,Le=t.unstable_cancelCallback,Ae=t.unstable_shouldYield,Ue=t.unstable_requestPaint,Oe=t.unstable_now,dt=t.unstable_getCurrentPriorityLevel,it=t.unstable_ImmediatePriority,lt=t.unstable_UserBlockingPriority,Je=t.unstable_NormalPriority,yt=t.unstable_LowPriority,Jt=t.unstable_IdlePriority,rn=t.log,zt=t.unstable_setDisableYieldValue,ae=null,He=null;function Ze(e){if(typeof rn=="function"&&zt(e),He&&typeof He.setStrictMode=="function")try{He.setStrictMode(ae,e)}catch{}}var ut=Math.clz32?Math.clz32:yn,Ut=Math.log,Nt=Math.LN2;function yn(e){return e>>>=0,e===0?32:31-(Ut(e)/Nt|0)|0}var fe=256,ft=262144,Et=4194304;function qt(e){var i=e&42;if(i!==0)return i;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Gt(e,i,s){var a=e.pendingLanes;if(a===0)return 0;var f=0,m=e.suspendedLanes,E=e.pingedLanes;e=e.warmLanes;var U=a&134217727;return U!==0?(a=U&~m,a!==0?f=qt(a):(E&=U,E!==0?f=qt(E):s||(s=U&~e,s!==0&&(f=qt(s))))):(U=a&~m,U!==0?f=qt(U):E!==0?f=qt(E):s||(s=a&~e,s!==0&&(f=qt(s)))),f===0?0:i!==0&&i!==f&&(i&m)===0&&(m=f&-f,s=i&-i,m>=s||m===32&&(s&4194048)!==0)?i:f}function Ct(e,i){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&i)===0}function oe(e,i){switch(e){case 1:case 2:case 4:case 8:case 64:return i+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return i+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ne(){var e=Et;return Et<<=1,(Et&62914560)===0&&(Et=4194304),e}function We(e){for(var i=[],s=0;31>s;s++)i.push(e);return i}function mt(e,i){e.pendingLanes|=i,i!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function St(e,i,s,a,f,m){var E=e.pendingLanes;e.pendingLanes=s,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=s,e.entangledLanes&=s,e.errorRecoveryDisabledLanes&=s,e.shellSuspendCounter=0;var U=e.entanglements,Z=e.expirationTimes,ce=e.hiddenUpdates;for(s=E&~s;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Yt=/[\n"\\]/g;function At(e){return e.replace(Yt,function(i){return"\\"+i.charCodeAt(0).toString(16)+" "})}function Wt(e,i,s,a,f,m,E,U){e.name="",E!=null&&typeof E!="function"&&typeof E!="symbol"&&typeof E!="boolean"?e.type=E:e.removeAttribute("type"),i!=null?E==="number"?(i===0&&e.value===""||e.value!=i)&&(e.value=""+Te(i)):e.value!==""+Te(i)&&(e.value=""+Te(i)):E!=="submit"&&E!=="reset"||e.removeAttribute("value"),i!=null?cn(e,E,Te(i)):s!=null?cn(e,E,Te(s)):a!=null&&e.removeAttribute("value"),f==null&&m!=null&&(e.defaultChecked=!!m),f!=null&&(e.checked=f&&typeof f!="function"&&typeof f!="symbol"),U!=null&&typeof U!="function"&&typeof U!="symbol"&&typeof U!="boolean"?e.name=""+Te(U):e.removeAttribute("name")}function Qt(e,i,s,a,f,m,E,U){if(m!=null&&typeof m!="function"&&typeof m!="symbol"&&typeof m!="boolean"&&(e.type=m),i!=null||s!=null){if(!(m!=="submit"&&m!=="reset"||i!=null)){Pe(e);return}s=s!=null?""+Te(s):"",i=i!=null?""+Te(i):s,U||i===e.value||(e.value=i),e.defaultValue=i}a=a??f,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=U?e.checked:!!a,e.defaultChecked=!!a,E!=null&&typeof E!="function"&&typeof E!="symbol"&&typeof E!="boolean"&&(e.name=E),Pe(e)}function cn(e,i,s){i==="number"&&wt(e.ownerDocument)===e||e.defaultValue===""+s||(e.defaultValue=""+s)}function Mt(e,i,s,a){if(e=e.options,i){i={};for(var f=0;f"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),_d=!1;if(zi)try{var Cr={};Object.defineProperty(Cr,"passive",{get:function(){_d=!0}}),window.addEventListener("test",Cr,Cr),window.removeEventListener("test",Cr,Cr)}catch{_d=!1}var eo=null,Cd=null,ol=null;function dh(){if(ol)return ol;var e,i=Cd,s=i.length,a,f="value"in eo?eo.value:eo.textContent,m=f.length;for(e=0;e=Er),mh=" ",xh=!1;function yh(e,i){switch(e){case"keyup":return gS.indexOf(i.keyCode)!==-1;case"keydown":return i.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function bh(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ms=!1;function xS(e,i){switch(e){case"compositionend":return bh(i);case"keypress":return i.which!==32?null:(xh=!0,mh);case"textInput":return e=i.data,e===mh&&xh?null:e;default:return null}}function yS(e,i){if(ms)return e==="compositionend"||!Ad&&yh(e,i)?(e=dh(),ol=Cd=eo=null,ms=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(i.ctrlKey||i.altKey||i.metaKey)||i.ctrlKey&&i.altKey){if(i.char&&1=i)return{node:s,offset:i-e};e=a}e:{for(;s;){if(s.nextSibling){s=s.nextSibling;break e}s=s.parentNode}s=void 0}s=Th(s)}}function Eh(e,i){return e&&i?e===i?!0:e&&e.nodeType===3?!1:i&&i.nodeType===3?Eh(e,i.parentNode):"contains"in e?e.contains(i):e.compareDocumentPosition?!!(e.compareDocumentPosition(i)&16):!1:!1}function Rh(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var i=wt(e.document);i instanceof e.HTMLIFrameElement;){try{var s=typeof i.contentWindow.location.href=="string"}catch{s=!1}if(s)e=i.contentWindow;else break;i=wt(e.document)}return i}function Ld(e){var i=e&&e.nodeName&&e.nodeName.toLowerCase();return i&&(i==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||i==="textarea"||e.contentEditable==="true")}var CS=zi&&"documentMode"in document&&11>=document.documentMode,xs=null,Nd=null,Dr=null,Bd=!1;function Ah(e,i,s){var a=s.window===s?s.document:s.nodeType===9?s:s.ownerDocument;Bd||xs==null||xs!==wt(a)||(a=xs,"selectionStart"in a&&Ld(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Dr&&Mr(Dr,a)||(Dr=a,a=Kl(Nd,"onSelect"),0>=E,f-=E,gi=1<<32-ut(i)+f|s<Qe?(rt=$e,$e=null):rt=$e.sibling;var gt=ue(re,$e,le[Qe],Se);if(gt===null){$e===null&&($e=rt);break}e&&$e&>.alternate===null&&i(re,$e),ie=m(gt,ie,Qe),ht===null?Ge=gt:ht.sibling=gt,ht=gt,$e=rt}if(Qe===le.length)return s(re,$e),ct&&Ri(re,Qe),Ge;if($e===null){for(;QeQe?(rt=$e,$e=null):rt=$e.sibling;var jo=ue(re,$e,gt.value,Se);if(jo===null){$e===null&&($e=rt);break}e&&$e&&jo.alternate===null&&i(re,$e),ie=m(jo,ie,Qe),ht===null?Ge=jo:ht.sibling=jo,ht=jo,$e=rt}if(gt.done)return s(re,$e),ct&&Ri(re,Qe),Ge;if($e===null){for(;!gt.done;Qe++,gt=le.next())gt=je(re,gt.value,Se),gt!==null&&(ie=m(gt,ie,Qe),ht===null?Ge=gt:ht.sibling=gt,ht=gt);return ct&&Ri(re,Qe),Ge}for($e=a($e);!gt.done;Qe++,gt=le.next())gt=ge($e,re,Qe,gt.value,Se),gt!==null&&(e&>.alternate!==null&&$e.delete(gt.key===null?Qe:gt.key),ie=m(gt,ie,Qe),ht===null?Ge=gt:ht.sibling=gt,ht=gt);return e&&$e.forEach(function(Fw){return i(re,Fw)}),ct&&Ri(re,Qe),Ge}function _t(re,ie,le,Se){if(typeof le=="object"&&le!==null&&le.type===_&&le.key===null&&(le=le.props.children),typeof le=="object"&&le!==null){switch(le.$$typeof){case S:e:{for(var Ge=le.key;ie!==null;){if(ie.key===Ge){if(Ge=le.type,Ge===_){if(ie.tag===7){s(re,ie.sibling),Se=f(ie,le.props.children),Se.return=re,re=Se;break e}}else if(ie.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===M&&Wo(Ge)===ie.type){s(re,ie.sibling),Se=f(ie,le.props),$r(Se,le),Se.return=re,re=Se;break e}s(re,ie);break}else i(re,ie);ie=ie.sibling}le.type===_?(Se=Bo(le.props.children,re.mode,Se,le.key),Se.return=re,re=Se):(Se=hl(le.type,le.key,le.props,null,re.mode,Se),$r(Se,le),Se.return=re,re=Se)}return E(re);case k:e:{for(Ge=le.key;ie!==null;){if(ie.key===Ge)if(ie.tag===4&&ie.stateNode.containerInfo===le.containerInfo&&ie.stateNode.implementation===le.implementation){s(re,ie.sibling),Se=f(ie,le.children||[]),Se.return=re,re=Se;break e}else{s(re,ie);break}else i(re,ie);ie=ie.sibling}Se=qd(le,re.mode,Se),Se.return=re,re=Se}return E(re);case M:return le=Wo(le),_t(re,ie,le,Se)}if(G(le))return Be(re,ie,le,Se);if(Y(le)){if(Ge=Y(le),typeof Ge!="function")throw Error(l(150));return le=Ge.call(le),Fe(re,ie,le,Se)}if(typeof le.then=="function")return _t(re,ie,Sl(le),Se);if(le.$$typeof===j)return _t(re,ie,xl(re,le),Se);wl(re,le)}return typeof le=="string"&&le!==""||typeof le=="number"||typeof le=="bigint"?(le=""+le,ie!==null&&ie.tag===6?(s(re,ie.sibling),Se=f(ie,le),Se.return=re,re=Se):(s(re,ie),Se=Ud(le,re.mode,Se),Se.return=re,re=Se),E(re)):s(re,ie)}return function(re,ie,le,Se){try{Ir=0;var Ge=_t(re,ie,le,Se);return zs=null,Ge}catch($e){if($e===Ts||$e===bl)throw $e;var ht=Dn(29,$e,null,re.mode);return ht.lanes=Se,ht.return=re,ht}finally{}}}var qo=eg(!0),tg=eg(!1),so=!1;function tu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function nu(e,i){e=e.updateQueue,i.updateQueue===e&&(i.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function ro(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function ao(e,i,s){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(xt&2)!==0){var f=a.pending;return f===null?i.next=i:(i.next=f.next,f.next=i),a.pending=i,i=pl(e),Ih(e,null,s),i}return fl(e,a,i,s),pl(e)}function Hr(e,i,s){if(i=i.updateQueue,i!==null&&(i=i.shared,(s&4194048)!==0)){var a=i.lanes;a&=e.pendingLanes,s|=a,i.lanes=s,Kt(e,s)}}function iu(e,i){var s=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,s===a)){var f=null,m=null;if(s=s.firstBaseUpdate,s!==null){do{var E={lane:s.lane,tag:s.tag,payload:s.payload,callback:null,next:null};m===null?f=m=E:m=m.next=E,s=s.next}while(s!==null);m===null?f=m=i:m=m.next=i}else f=m=i;s={baseState:a.baseState,firstBaseUpdate:f,lastBaseUpdate:m,shared:a.shared,callbacks:a.callbacks},e.updateQueue=s;return}e=s.lastBaseUpdate,e===null?s.firstBaseUpdate=i:e.next=i,s.lastBaseUpdate=i}var ou=!1;function Wr(){if(ou){var e=Cs;if(e!==null)throw e}}function Ur(e,i,s,a){ou=!1;var f=e.updateQueue;so=!1;var m=f.firstBaseUpdate,E=f.lastBaseUpdate,U=f.shared.pending;if(U!==null){f.shared.pending=null;var Z=U,ce=Z.next;Z.next=null,E===null?m=ce:E.next=ce,E=Z;var be=e.alternate;be!==null&&(be=be.updateQueue,U=be.lastBaseUpdate,U!==E&&(U===null?be.firstBaseUpdate=ce:U.next=ce,be.lastBaseUpdate=Z))}if(m!==null){var je=f.baseState;E=0,be=ce=Z=null,U=m;do{var ue=U.lane&-536870913,ge=ue!==U.lane;if(ge?(st&ue)===ue:(a&ue)===ue){ue!==0&&ue===_s&&(ou=!0),be!==null&&(be=be.next={lane:0,tag:U.tag,payload:U.payload,callback:null,next:null});e:{var Be=e,Fe=U;ue=i;var _t=s;switch(Fe.tag){case 1:if(Be=Fe.payload,typeof Be=="function"){je=Be.call(_t,je,ue);break e}je=Be;break e;case 3:Be.flags=Be.flags&-65537|128;case 0:if(Be=Fe.payload,ue=typeof Be=="function"?Be.call(_t,je,ue):Be,ue==null)break e;je=y({},je,ue);break e;case 2:so=!0}}ue=U.callback,ue!==null&&(e.flags|=64,ge&&(e.flags|=8192),ge=f.callbacks,ge===null?f.callbacks=[ue]:ge.push(ue))}else ge={lane:ue,tag:U.tag,payload:U.payload,callback:U.callback,next:null},be===null?(ce=be=ge,Z=je):be=be.next=ge,E|=ue;if(U=U.next,U===null){if(U=f.shared.pending,U===null)break;ge=U,U=ge.next,ge.next=null,f.lastBaseUpdate=ge,f.shared.pending=null}}while(!0);be===null&&(Z=je),f.baseState=Z,f.firstBaseUpdate=ce,f.lastBaseUpdate=be,m===null&&(f.shared.lanes=0),po|=E,e.lanes=E,e.memoizedState=je}}function ng(e,i){if(typeof e!="function")throw Error(l(191,e));e.call(i)}function ig(e,i){var s=e.callbacks;if(s!==null)for(e.callbacks=null,e=0;em?m:8;var E=R.T,U={};R.T=U,ju(e,!1,i,s);try{var Z=f(),ce=R.S;if(ce!==null&&ce(U,Z),Z!==null&&typeof Z=="object"&&typeof Z.then=="function"){var be=NS(Z,a);Pr(e,i,be,In(e))}else Pr(e,i,a,In(e))}catch(je){Pr(e,i,{then:function(){},status:"rejected",reason:je},In())}finally{X.p=m,E!==null&&U.types!==null&&(E.types=U.types),R.T=E}}function WS(){}function Su(e,i,s,a){if(e.tag!==5)throw Error(l(476));var f=Ng(e).queue;Lg(e,f,i,B,s===null?WS:function(){return Bg(e),s(a)})}function Ng(e){var i=e.memoizedState;if(i!==null)return i;i={memoizedState:B,baseState:B,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Li,lastRenderedState:B},next:null};var s={};return i.next={memoizedState:s,baseState:s,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Li,lastRenderedState:s},next:null},e.memoizedState=i,e=e.alternate,e!==null&&(e.memoizedState=i),i}function Bg(e){var i=Ng(e);i.next===null&&(i=e.alternate.memoizedState),Pr(e,i.next.queue,{},In())}function wu(){return un(la)}function Og(){return Xt().memoizedState}function Ig(){return Xt().memoizedState}function US(e){for(var i=e.return;i!==null;){switch(i.tag){case 24:case 3:var s=In();e=ro(s);var a=ao(i,e,s);a!==null&&(En(a,i,s),Hr(a,i,s)),i={cache:Kd()},e.payload=i;return}i=i.return}}function qS(e,i,s){var a=In();s={lane:a,revertLane:0,gesture:null,action:s,hasEagerState:!1,eagerState:null,next:null},Ml(e)?Hg(i,s):(s=Hd(e,i,s,a),s!==null&&(En(s,e,a),Wg(s,i,a)))}function $g(e,i,s){var a=In();Pr(e,i,s,a)}function Pr(e,i,s,a){var f={lane:a,revertLane:0,gesture:null,action:s,hasEagerState:!1,eagerState:null,next:null};if(Ml(e))Hg(i,f);else{var m=e.alternate;if(e.lanes===0&&(m===null||m.lanes===0)&&(m=i.lastRenderedReducer,m!==null))try{var E=i.lastRenderedState,U=m(E,s);if(f.hasEagerState=!0,f.eagerState=U,Mn(U,E))return fl(e,i,f,0),Tt===null&&ul(),!1}catch{}finally{}if(s=Hd(e,i,f,a),s!==null)return En(s,e,a),Wg(s,i,a),!0}return!1}function ju(e,i,s,a){if(a={lane:2,revertLane:tf(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Ml(e)){if(i)throw Error(l(479))}else i=Hd(e,s,a,2),i!==null&&En(i,e,2)}function Ml(e){var i=e.alternate;return e===Ke||i!==null&&i===Ke}function Hg(e,i){Rs=_l=!0;var s=e.pending;s===null?i.next=i:(i.next=s.next,s.next=i),e.pending=i}function Wg(e,i,s){if((s&4194048)!==0){var a=i.lanes;a&=e.pendingLanes,s|=a,i.lanes=s,Kt(e,s)}}var Fr={readContext:un,use:zl,useCallback:Pt,useContext:Pt,useEffect:Pt,useImperativeHandle:Pt,useLayoutEffect:Pt,useInsertionEffect:Pt,useMemo:Pt,useReducer:Pt,useRef:Pt,useState:Pt,useDebugValue:Pt,useDeferredValue:Pt,useTransition:Pt,useSyncExternalStore:Pt,useId:Pt,useHostTransitionStatus:Pt,useFormState:Pt,useActionState:Pt,useOptimistic:Pt,useMemoCache:Pt,useCacheRefresh:Pt};Fr.useEffectEvent=Pt;var Ug={readContext:un,use:zl,useCallback:function(e,i){return vn().memoizedState=[e,i===void 0?null:i],e},useContext:un,useEffect:_g,useImperativeHandle:function(e,i,s){s=s!=null?s.concat([e]):null,Rl(4194308,4,Eg.bind(null,i,e),s)},useLayoutEffect:function(e,i){return Rl(4194308,4,e,i)},useInsertionEffect:function(e,i){Rl(4,2,e,i)},useMemo:function(e,i){var s=vn();i=i===void 0?null:i;var a=e();if(Go){Ze(!0);try{e()}finally{Ze(!1)}}return s.memoizedState=[a,i],a},useReducer:function(e,i,s){var a=vn();if(s!==void 0){var f=s(i);if(Go){Ze(!0);try{s(i)}finally{Ze(!1)}}}else f=i;return a.memoizedState=a.baseState=f,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:f},a.queue=e,e=e.dispatch=qS.bind(null,Ke,e),[a.memoizedState,e]},useRef:function(e){var i=vn();return e={current:e},i.memoizedState=e},useState:function(e){e=mu(e);var i=e.queue,s=$g.bind(null,Ke,i);return i.dispatch=s,[e.memoizedState,s]},useDebugValue:bu,useDeferredValue:function(e,i){var s=vn();return vu(s,e,i)},useTransition:function(){var e=mu(!1);return e=Lg.bind(null,Ke,e.queue,!0,!1),vn().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,i,s){var a=Ke,f=vn();if(ct){if(s===void 0)throw Error(l(407));s=s()}else{if(s=i(),Tt===null)throw Error(l(349));(st&127)!==0||cg(a,i,s)}f.memoizedState=s;var m={value:s,getSnapshot:i};return f.queue=m,_g(ug.bind(null,a,m,e),[e]),a.flags|=2048,Ms(9,{destroy:void 0},dg.bind(null,a,m,s,i),null),s},useId:function(){var e=vn(),i=Tt.identifierPrefix;if(ct){var s=mi,a=gi;s=(a&~(1<<32-ut(a)-1)).toString(32)+s,i="_"+i+"R_"+s,s=Cl++,0<\/script>",m=m.removeChild(m.firstChild);break;case"select":m=typeof a.is=="string"?E.createElement("select",{is:a.is}):E.createElement("select"),a.multiple?m.multiple=!0:a.size&&(m.size=a.size);break;default:m=typeof a.is=="string"?E.createElement(f,{is:a.is}):E.createElement(f)}}m[Rt]=i,m[an]=a;e:for(E=i.child;E!==null;){if(E.tag===5||E.tag===6)m.appendChild(E.stateNode);else if(E.tag!==4&&E.tag!==27&&E.child!==null){E.child.return=E,E=E.child;continue}if(E===i)break e;for(;E.sibling===null;){if(E.return===null||E.return===i)break e;E=E.return}E.sibling.return=E.return,E=E.sibling}i.stateNode=m;e:switch(pn(m,f,a),f){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Bi(i)}}return Lt(i),Ou(i,i.type,e===null?null:e.memoizedProps,i.pendingProps,s),null;case 6:if(e&&i.stateNode!=null)e.memoizedProps!==a&&Bi(i);else{if(typeof a!="string"&&i.stateNode===null)throw Error(l(166));if(e=J.current,js(i)){if(e=i.stateNode,s=i.memoizedProps,a=null,f=dn,f!==null)switch(f.tag){case 27:case 5:a=f.memoizedProps}e[Rt]=i,e=!!(e.nodeValue===s||a!==null&&a.suppressHydrationWarning===!0||ax(e.nodeValue,s)),e||io(i,!0)}else e=Ql(e).createTextNode(a),e[Rt]=i,i.stateNode=e}return Lt(i),null;case 31:if(s=i.memoizedState,e===null||e.memoizedState!==null){if(a=js(i),s!==null){if(e===null){if(!a)throw Error(l(318));if(e=i.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(l(557));e[Rt]=i}else Oo(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Lt(i),e=!1}else s=Yd(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),e=!0;if(!e)return i.flags&256?(Nn(i),i):(Nn(i),null);if((i.flags&128)!==0)throw Error(l(558))}return Lt(i),null;case 13:if(a=i.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(f=js(i),a!==null&&a.dehydrated!==null){if(e===null){if(!f)throw Error(l(318));if(f=i.memoizedState,f=f!==null?f.dehydrated:null,!f)throw Error(l(317));f[Rt]=i}else Oo(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Lt(i),f=!1}else f=Yd(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=f),f=!0;if(!f)return i.flags&256?(Nn(i),i):(Nn(i),null)}return Nn(i),(i.flags&128)!==0?(i.lanes=s,i):(s=a!==null,e=e!==null&&e.memoizedState!==null,s&&(a=i.child,f=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(f=a.alternate.memoizedState.cachePool.pool),m=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(m=a.memoizedState.cachePool.pool),m!==f&&(a.flags|=2048)),s!==e&&s&&(i.child.flags|=8192),Ol(i,i.updateQueue),Lt(i),null);case 4:return pe(),e===null&&rf(i.stateNode.containerInfo),Lt(i),null;case 10:return Mi(i.type),Lt(i),null;case 19:if(O(Vt),a=i.memoizedState,a===null)return Lt(i),null;if(f=(i.flags&128)!==0,m=a.rendering,m===null)if(f)Vr(a,!1);else{if(Ft!==0||e!==null&&(e.flags&128)!==0)for(e=i.child;e!==null;){if(m=kl(e),m!==null){for(i.flags|=128,Vr(a,!1),e=m.updateQueue,i.updateQueue=e,Ol(i,e),i.subtreeFlags=0,e=s,s=i.child;s!==null;)$h(s,e),s=s.sibling;return $(Vt,Vt.current&1|2),ct&&Ri(i,a.treeForkCount),i.child}e=e.sibling}a.tail!==null&&Oe()>Ul&&(i.flags|=128,f=!0,Vr(a,!1),i.lanes=4194304)}else{if(!f)if(e=kl(m),e!==null){if(i.flags|=128,f=!0,e=e.updateQueue,i.updateQueue=e,Ol(i,e),Vr(a,!0),a.tail===null&&a.tailMode==="hidden"&&!m.alternate&&!ct)return Lt(i),null}else 2*Oe()-a.renderingStartTime>Ul&&s!==536870912&&(i.flags|=128,f=!0,Vr(a,!1),i.lanes=4194304);a.isBackwards?(m.sibling=i.child,i.child=m):(e=a.last,e!==null?e.sibling=m:i.child=m,a.last=m)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=Oe(),e.sibling=null,s=Vt.current,$(Vt,f?s&1|2:s&1),ct&&Ri(i,a.treeForkCount),e):(Lt(i),null);case 22:case 23:return Nn(i),ru(),a=i.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(i.flags|=8192):a&&(i.flags|=8192),a?(s&536870912)!==0&&(i.flags&128)===0&&(Lt(i),i.subtreeFlags&6&&(i.flags|=8192)):Lt(i),s=i.updateQueue,s!==null&&Ol(i,s.retryQueue),s=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(s=e.memoizedState.cachePool.pool),a=null,i.memoizedState!==null&&i.memoizedState.cachePool!==null&&(a=i.memoizedState.cachePool.pool),a!==s&&(i.flags|=2048),e!==null&&O(Ho),null;case 24:return s=null,e!==null&&(s=e.memoizedState.cache),i.memoizedState.cache!==s&&(i.flags|=2048),Mi(Zt),Lt(i),null;case 25:return null;case 30:return null}throw Error(l(156,i.tag))}function VS(e,i){switch(Pd(i),i.tag){case 1:return e=i.flags,e&65536?(i.flags=e&-65537|128,i):null;case 3:return Mi(Zt),pe(),e=i.flags,(e&65536)!==0&&(e&128)===0?(i.flags=e&-65537|128,i):null;case 26:case 27:case 5:return we(i),null;case 31:if(i.memoizedState!==null){if(Nn(i),i.alternate===null)throw Error(l(340));Oo()}return e=i.flags,e&65536?(i.flags=e&-65537|128,i):null;case 13:if(Nn(i),e=i.memoizedState,e!==null&&e.dehydrated!==null){if(i.alternate===null)throw Error(l(340));Oo()}return e=i.flags,e&65536?(i.flags=e&-65537|128,i):null;case 19:return O(Vt),null;case 4:return pe(),null;case 10:return Mi(i.type),null;case 22:case 23:return Nn(i),ru(),e!==null&&O(Ho),e=i.flags,e&65536?(i.flags=e&-65537|128,i):null;case 24:return Mi(Zt),null;case 25:return null;default:return null}}function fm(e,i){switch(Pd(i),i.tag){case 3:Mi(Zt),pe();break;case 26:case 27:case 5:we(i);break;case 4:pe();break;case 31:i.memoizedState!==null&&Nn(i);break;case 13:Nn(i);break;case 19:O(Vt);break;case 10:Mi(i.type);break;case 22:case 23:Nn(i),ru(),e!==null&&O(Ho);break;case 24:Mi(Zt)}}function Xr(e,i){try{var s=i.updateQueue,a=s!==null?s.lastEffect:null;if(a!==null){var f=a.next;s=f;do{if((s.tag&e)===e){a=void 0;var m=s.create,E=s.inst;a=m(),E.destroy=a}s=s.next}while(s!==f)}}catch(U){vt(i,i.return,U)}}function uo(e,i,s){try{var a=i.updateQueue,f=a!==null?a.lastEffect:null;if(f!==null){var m=f.next;a=m;do{if((a.tag&e)===e){var E=a.inst,U=E.destroy;if(U!==void 0){E.destroy=void 0,f=i;var Z=s,ce=U;try{ce()}catch(be){vt(f,Z,be)}}}a=a.next}while(a!==m)}}catch(be){vt(i,i.return,be)}}function pm(e){var i=e.updateQueue;if(i!==null){var s=e.stateNode;try{ig(i,s)}catch(a){vt(e,e.return,a)}}}function hm(e,i,s){s.props=Po(e.type,e.memoizedProps),s.state=e.memoizedState;try{s.componentWillUnmount()}catch(a){vt(e,i,a)}}function Jr(e,i){try{var s=e.ref;if(s!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof s=="function"?e.refCleanup=s(a):s.current=a}}catch(f){vt(e,i,f)}}function xi(e,i){var s=e.ref,a=e.refCleanup;if(s!==null)if(typeof a=="function")try{a()}catch(f){vt(e,i,f)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof s=="function")try{s(null)}catch(f){vt(e,i,f)}else s.current=null}function gm(e){var i=e.type,s=e.memoizedProps,a=e.stateNode;try{e:switch(i){case"button":case"input":case"select":case"textarea":s.autoFocus&&a.focus();break e;case"img":s.src?a.src=s.src:s.srcSet&&(a.srcset=s.srcSet)}}catch(f){vt(e,e.return,f)}}function Iu(e,i,s){try{var a=e.stateNode;mw(a,e.type,s,i),a[an]=i}catch(f){vt(e,e.return,f)}}function mm(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&yo(e.type)||e.tag===4}function $u(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||mm(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&yo(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Hu(e,i,s){var a=e.tag;if(a===5||a===6)e=e.stateNode,i?(s.nodeType===9?s.body:s.nodeName==="HTML"?s.ownerDocument.body:s).insertBefore(e,i):(i=s.nodeType===9?s.body:s.nodeName==="HTML"?s.ownerDocument.body:s,i.appendChild(e),s=s._reactRootContainer,s!=null||i.onclick!==null||(i.onclick=Ti));else if(a!==4&&(a===27&&yo(e.type)&&(s=e.stateNode,i=null),e=e.child,e!==null))for(Hu(e,i,s),e=e.sibling;e!==null;)Hu(e,i,s),e=e.sibling}function Il(e,i,s){var a=e.tag;if(a===5||a===6)e=e.stateNode,i?s.insertBefore(e,i):s.appendChild(e);else if(a!==4&&(a===27&&yo(e.type)&&(s=e.stateNode),e=e.child,e!==null))for(Il(e,i,s),e=e.sibling;e!==null;)Il(e,i,s),e=e.sibling}function xm(e){var i=e.stateNode,s=e.memoizedProps;try{for(var a=e.type,f=i.attributes;f.length;)i.removeAttributeNode(f[0]);pn(i,a,s),i[Rt]=e,i[an]=s}catch(m){vt(e,e.return,m)}}var Oi=!1,nn=!1,Wu=!1,ym=typeof WeakSet=="function"?WeakSet:Set,ln=null;function XS(e,i){if(e=e.containerInfo,cf=sc,e=Rh(e),Ld(e)){if("selectionStart"in e)var s={start:e.selectionStart,end:e.selectionEnd};else e:{s=(s=e.ownerDocument)&&s.defaultView||window;var a=s.getSelection&&s.getSelection();if(a&&a.rangeCount!==0){s=a.anchorNode;var f=a.anchorOffset,m=a.focusNode;a=a.focusOffset;try{s.nodeType,m.nodeType}catch{s=null;break e}var E=0,U=-1,Z=-1,ce=0,be=0,je=e,ue=null;t:for(;;){for(var ge;je!==s||f!==0&&je.nodeType!==3||(U=E+f),je!==m||a!==0&&je.nodeType!==3||(Z=E+a),je.nodeType===3&&(E+=je.nodeValue.length),(ge=je.firstChild)!==null;)ue=je,je=ge;for(;;){if(je===e)break t;if(ue===s&&++ce===f&&(U=E),ue===m&&++be===a&&(Z=E),(ge=je.nextSibling)!==null)break;je=ue,ue=je.parentNode}je=ge}s=U===-1||Z===-1?null:{start:U,end:Z}}else s=null}s=s||{start:0,end:0}}else s=null;for(df={focusedElem:e,selectionRange:s},sc=!1,ln=i;ln!==null;)if(i=ln,e=i.child,(i.subtreeFlags&1028)!==0&&e!==null)e.return=i,ln=e;else for(;ln!==null;){switch(i=ln,m=i.alternate,e=i.flags,i.tag){case 0:if((e&4)!==0&&(e=i.updateQueue,e=e!==null?e.events:null,e!==null))for(s=0;s title"))),pn(m,a,s),m[Rt]=e,Bt(m),a=m;break e;case"link":var E=kx("link","href",f).get(a+(s.href||""));if(E){for(var U=0;U_t&&(E=_t,_t=Fe,Fe=E);var re=zh(U,Fe),ie=zh(U,_t);if(re&&ie&&(ge.rangeCount!==1||ge.anchorNode!==re.node||ge.anchorOffset!==re.offset||ge.focusNode!==ie.node||ge.focusOffset!==ie.offset)){var le=je.createRange();le.setStart(re.node,re.offset),ge.removeAllRanges(),Fe>_t?(ge.addRange(le),ge.extend(ie.node,ie.offset)):(le.setEnd(ie.node,ie.offset),ge.addRange(le))}}}}for(je=[],ge=U;ge=ge.parentNode;)ge.nodeType===1&&je.push({element:ge,left:ge.scrollLeft,top:ge.scrollTop});for(typeof U.focus=="function"&&U.focus(),U=0;Us?32:s,R.T=null,s=Vu,Vu=null;var m=go,E=Ui;if(sn=0,Os=go=null,Ui=0,(xt&6)!==0)throw Error(l(331));var U=xt;if(xt|=4,Em(m.current),Cm(m,m.current,E,s),xt=U,na(0,!1),He&&typeof He.onPostCommitFiberRoot=="function")try{He.onPostCommitFiberRoot(ae,m)}catch{}return!0}finally{X.p=f,R.T=a,Ym(e,i)}}function Xm(e,i,s){i=qn(s,i),i=Tu(e.stateNode,i,2),e=ao(e,i,2),e!==null&&(mt(e,2),yi(e))}function vt(e,i,s){if(e.tag===3)Xm(e,e,s);else for(;i!==null;){if(i.tag===3){Xm(i,e,s);break}else if(i.tag===1){var a=i.stateNode;if(typeof i.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(ho===null||!ho.has(a))){e=qn(s,e),s=Jg(2),a=ao(i,s,2),a!==null&&(Kg(s,a,i,e),mt(a,2),yi(a));break}}i=i.return}}function Qu(e,i,s){var a=e.pingCache;if(a===null){a=e.pingCache=new QS;var f=new Set;a.set(i,f)}else f=a.get(i),f===void 0&&(f=new Set,a.set(i,f));f.has(s)||(Gu=!0,f.add(s),e=iw.bind(null,e,i,s),i.then(e,e))}function iw(e,i,s){var a=e.pingCache;a!==null&&a.delete(i),e.pingedLanes|=e.suspendedLanes&s,e.warmLanes&=~s,Tt===e&&(st&s)===s&&(Ft===4||Ft===3&&(st&62914560)===st&&300>Oe()-Wl?(xt&2)===0&&Is(e,0):Pu|=s,Bs===st&&(Bs=0)),yi(e)}function Jm(e,i){i===0&&(i=Ne()),e=No(e,i),e!==null&&(mt(e,i),yi(e))}function ow(e){var i=e.memoizedState,s=0;i!==null&&(s=i.retryLane),Jm(e,s)}function sw(e,i){var s=0;switch(e.tag){case 31:case 13:var a=e.stateNode,f=e.memoizedState;f!==null&&(s=f.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(l(314))}a!==null&&a.delete(i),Jm(e,s)}function rw(e,i){return Ve(e,i)}var Vl=null,Hs=null,Zu=!1,Xl=!1,ef=!1,xo=0;function yi(e){e!==Hs&&e.next===null&&(Hs===null?Vl=Hs=e:Hs=Hs.next=e),Xl=!0,Zu||(Zu=!0,lw())}function na(e,i){if(!ef&&Xl){ef=!0;do for(var s=!1,a=Vl;a!==null;){if(e!==0){var f=a.pendingLanes;if(f===0)var m=0;else{var E=a.suspendedLanes,U=a.pingedLanes;m=(1<<31-ut(42|e)+1)-1,m&=f&~(E&~U),m=m&201326741?m&201326741|1:m?m|2:0}m!==0&&(s=!0,ex(a,m))}else m=st,m=Gt(a,a===Tt?m:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(m&3)===0||Ct(a,m)||(s=!0,ex(a,m));a=a.next}while(s);ef=!1}}function aw(){Km()}function Km(){Xl=Zu=!1;var e=0;xo!==0&&yw()&&(e=xo);for(var i=Oe(),s=null,a=Vl;a!==null;){var f=a.next,m=Qm(a,i);m===0?(a.next=null,s===null?Vl=f:s.next=f,f===null&&(Hs=s)):(s=a,(e!==0||(m&3)!==0)&&(Xl=!0)),a=f}sn!==0&&sn!==5||na(e),xo!==0&&(xo=0)}function Qm(e,i){for(var s=e.suspendedLanes,a=e.pingedLanes,f=e.expirationTimes,m=e.pendingLanes&-62914561;0U)break;var be=Z.transferSize,je=Z.initiatorType;be&&lx(je)&&(Z=Z.responseEnd,E+=be*(Z"u"?null:document;function vx(e,i,s){var a=Ws;if(a&&typeof i=="string"&&i){var f=At(i);f='link[rel="'+e+'"][href="'+f+'"]',typeof s=="string"&&(f+='[crossorigin="'+s+'"]'),bx.has(f)||(bx.add(f),e={rel:e,crossOrigin:s,href:i},a.querySelector(f)===null&&(i=a.createElement("link"),pn(i,"link",e),Bt(i),a.head.appendChild(i)))}}function Tw(e){qi.D(e),vx("dns-prefetch",e,null)}function zw(e,i){qi.C(e,i),vx("preconnect",e,i)}function Ew(e,i,s){qi.L(e,i,s);var a=Ws;if(a&&e&&i){var f='link[rel="preload"][as="'+At(i)+'"]';i==="image"&&s&&s.imageSrcSet?(f+='[imagesrcset="'+At(s.imageSrcSet)+'"]',typeof s.imageSizes=="string"&&(f+='[imagesizes="'+At(s.imageSizes)+'"]')):f+='[href="'+At(e)+'"]';var m=f;switch(i){case"style":m=Us(e);break;case"script":m=qs(e)}Xn.has(m)||(e=y({rel:"preload",href:i==="image"&&s&&s.imageSrcSet?void 0:e,as:i},s),Xn.set(m,e),a.querySelector(f)!==null||i==="style"&&a.querySelector(ra(m))||i==="script"&&a.querySelector(aa(m))||(i=a.createElement("link"),pn(i,"link",e),Bt(i),a.head.appendChild(i)))}}function Rw(e,i){qi.m(e,i);var s=Ws;if(s&&e){var a=i&&typeof i.as=="string"?i.as:"script",f='link[rel="modulepreload"][as="'+At(a)+'"][href="'+At(e)+'"]',m=f;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":m=qs(e)}if(!Xn.has(m)&&(e=y({rel:"modulepreload",href:e},i),Xn.set(m,e),s.querySelector(f)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(s.querySelector(aa(m)))return}a=s.createElement("link"),pn(a,"link",e),Bt(a),s.head.appendChild(a)}}}function Aw(e,i,s){qi.S(e,i,s);var a=Ws;if(a&&e){var f=pi(a).hoistableStyles,m=Us(e);i=i||"default";var E=f.get(m);if(!E){var U={loading:0,preload:null};if(E=a.querySelector(ra(m)))U.loading=5;else{e=y({rel:"stylesheet",href:e,"data-precedence":i},s),(s=Xn.get(m))&&xf(e,s);var Z=E=a.createElement("link");Bt(Z),pn(Z,"link",e),Z._p=new Promise(function(ce,be){Z.onload=ce,Z.onerror=be}),Z.addEventListener("load",function(){U.loading|=1}),Z.addEventListener("error",function(){U.loading|=2}),U.loading|=4,ec(E,i,a)}E={type:"stylesheet",instance:E,count:1,state:U},f.set(m,E)}}}function Mw(e,i){qi.X(e,i);var s=Ws;if(s&&e){var a=pi(s).hoistableScripts,f=qs(e),m=a.get(f);m||(m=s.querySelector(aa(f)),m||(e=y({src:e,async:!0},i),(i=Xn.get(f))&&yf(e,i),m=s.createElement("script"),Bt(m),pn(m,"link",e),s.head.appendChild(m)),m={type:"script",instance:m,count:1,state:null},a.set(f,m))}}function Dw(e,i){qi.M(e,i);var s=Ws;if(s&&e){var a=pi(s).hoistableScripts,f=qs(e),m=a.get(f);m||(m=s.querySelector(aa(f)),m||(e=y({src:e,async:!0,type:"module"},i),(i=Xn.get(f))&&yf(e,i),m=s.createElement("script"),Bt(m),pn(m,"link",e),s.head.appendChild(m)),m={type:"script",instance:m,count:1,state:null},a.set(f,m))}}function Sx(e,i,s,a){var f=(f=J.current)?Zl(f):null;if(!f)throw Error(l(446));switch(e){case"meta":case"title":return null;case"style":return typeof s.precedence=="string"&&typeof s.href=="string"?(i=Us(s.href),s=pi(f).hoistableStyles,a=s.get(i),a||(a={type:"style",instance:null,count:0,state:null},s.set(i,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(s.rel==="stylesheet"&&typeof s.href=="string"&&typeof s.precedence=="string"){e=Us(s.href);var m=pi(f).hoistableStyles,E=m.get(e);if(E||(f=f.ownerDocument||f,E={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},m.set(e,E),(m=f.querySelector(ra(e)))&&!m._p&&(E.instance=m,E.state.loading=5),Xn.has(e)||(s={rel:"preload",as:"style",href:s.href,crossOrigin:s.crossOrigin,integrity:s.integrity,media:s.media,hrefLang:s.hrefLang,referrerPolicy:s.referrerPolicy},Xn.set(e,s),m||Lw(f,e,s,E.state))),i&&a===null)throw Error(l(528,""));return E}if(i&&a!==null)throw Error(l(529,""));return null;case"script":return i=s.async,s=s.src,typeof s=="string"&&i&&typeof i!="function"&&typeof i!="symbol"?(i=qs(s),s=pi(f).hoistableScripts,a=s.get(i),a||(a={type:"script",instance:null,count:0,state:null},s.set(i,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(l(444,e))}}function Us(e){return'href="'+At(e)+'"'}function ra(e){return'link[rel="stylesheet"]['+e+"]"}function wx(e){return y({},e,{"data-precedence":e.precedence,precedence:null})}function Lw(e,i,s,a){e.querySelector('link[rel="preload"][as="style"]['+i+"]")?a.loading=1:(i=e.createElement("link"),a.preload=i,i.addEventListener("load",function(){return a.loading|=1}),i.addEventListener("error",function(){return a.loading|=2}),pn(i,"link",s),Bt(i),e.head.appendChild(i))}function qs(e){return'[src="'+At(e)+'"]'}function aa(e){return"script[async]"+e}function jx(e,i,s){if(i.count++,i.instance===null)switch(i.type){case"style":var a=e.querySelector('style[data-href~="'+At(s.href)+'"]');if(a)return i.instance=a,Bt(a),a;var f=y({},s,{"data-href":s.href,"data-precedence":s.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),Bt(a),pn(a,"style",f),ec(a,s.precedence,e),i.instance=a;case"stylesheet":f=Us(s.href);var m=e.querySelector(ra(f));if(m)return i.state.loading|=4,i.instance=m,Bt(m),m;a=wx(s),(f=Xn.get(f))&&xf(a,f),m=(e.ownerDocument||e).createElement("link"),Bt(m);var E=m;return E._p=new Promise(function(U,Z){E.onload=U,E.onerror=Z}),pn(m,"link",a),i.state.loading|=4,ec(m,s.precedence,e),i.instance=m;case"script":return m=qs(s.src),(f=e.querySelector(aa(m)))?(i.instance=f,Bt(f),f):(a=s,(f=Xn.get(m))&&(a=y({},s),yf(a,f)),e=e.ownerDocument||e,f=e.createElement("script"),Bt(f),pn(f,"link",a),e.head.appendChild(f),i.instance=f);case"void":return null;default:throw Error(l(443,i.type))}else i.type==="stylesheet"&&(i.state.loading&4)===0&&(a=i.instance,i.state.loading|=4,ec(a,s.precedence,e));return i.instance}function ec(e,i,s){for(var a=s.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),f=a.length?a[a.length-1]:null,m=f,E=0;E title"):null)}function Nw(e,i,s){if(s===1||i.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof i.precedence!="string"||typeof i.href!="string"||i.href==="")break;return!0;case"link":if(typeof i.rel!="string"||typeof i.href!="string"||i.href===""||i.onLoad||i.onError)break;switch(i.rel){case"stylesheet":return e=i.disabled,typeof i.precedence=="string"&&e==null;default:return!0}case"script":if(i.async&&typeof i.async!="function"&&typeof i.async!="symbol"&&!i.onLoad&&!i.onError&&i.src&&typeof i.src=="string")return!0}return!1}function Cx(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function Bw(e,i,s,a){if(s.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(s.state.loading&4)===0){if(s.instance===null){var f=Us(a.href),m=i.querySelector(ra(f));if(m){i=m._p,i!==null&&typeof i=="object"&&typeof i.then=="function"&&(e.count++,e=nc.bind(e),i.then(e,e)),s.state.loading|=4,s.instance=m,Bt(m);return}m=i.ownerDocument||i,a=wx(a),(f=Xn.get(f))&&xf(a,f),m=m.createElement("link"),Bt(m);var E=m;E._p=new Promise(function(U,Z){E.onload=U,E.onerror=Z}),pn(m,"link",a),s.instance=m}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(s,i),(i=s.state.preload)&&(s.state.loading&3)===0&&(e.count++,s=nc.bind(e),i.addEventListener("load",s),i.addEventListener("error",s))}}var bf=0;function Ow(e,i){return e.stylesheets&&e.count===0&&oc(e,e.stylesheets),0bf?50:800)+i);return e.unsuspend=s,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(f)}}:null}function nc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)oc(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var ic=null;function oc(e,i){e.stylesheets=null,e.unsuspend!==null&&(e.count++,ic=new Map,i.forEach(Iw,e),ic=null,nc.call(e))}function Iw(e,i){if(!(i.state.loading&4)){var s=ic.get(e);if(s)var a=s.get(null);else{s=new Map,ic.set(e,s);for(var f=e.querySelectorAll("link[data-precedence],style[data-precedence]"),m=0;m"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(o){console.error(o)}}return t(),zf.exports=e2(),zf.exports}var n2=t2();const ds="/api/v1";function i2(t,o,r=""){const l=`HTTP ${t}${r?" "+r:""}`;if(!o)return l;let c;try{c=JSON.parse(o)}catch{return`${l}: ${o.slice(0,200)}`}if(c&&typeof c=="object"){const d=c,u=d.detail;if(typeof u=="string")return u;if(Array.isArray(u)){const p=u.map(g=>{if(g&&typeof g=="object"){const h=g,v=Array.isArray(h.loc)?h.loc.filter(b=>b!=="body").join("."):"",y=typeof h.msg=="string"?h.msg:JSON.stringify(g);return v?`${v}: ${y}`:y}return String(g)}).filter(Boolean);if(p.length)return p.join("; ")}if(typeof d.message=="string")return d.message;if(typeof d.error=="string")return d.error}return`${l}: ${o.slice(0,200)}`}function ub(t,o,r,l,c){const d=i2(r,c,l),u=new Error(`${t} ${o} — ${d}`);return u.status=r,u.body=c,u}async function me(t,o,r,l){const c={method:t,headers:{"Content-Type":"application/json"},signal:l};r!==void 0&&(c.body=JSON.stringify(r));const d=await fetch(`${ds}${o}`,c);if(!d.ok){const u=await d.text().catch(()=>"");throw ub(t,o,d.status,d.statusText,u)}return d.json()}const o2={sequences:"#059669",freq_map:"#2563eb",profiles:"#7c3aed",clusters:"#d97706",number:"#dc2626",text:"#0d9488",json:"#4f46e5",any:"#64748b",claims:"#b45309",papers:"#0891b2"},s2=()=>me("GET","/experiment-graphs/catalog"),fb=()=>me("GET","/experiment-graphs"),Jx=t=>me("GET",`/experiment-graphs/${t}`),Mf=t=>me("POST","/experiment-graphs",t),r2=(t,o)=>me("PUT",`/experiment-graphs/${t}`,o),a2=t=>me("DELETE",`/experiment-graphs/${t}`),Na=()=>me("GET","/health"),l2=()=>me("GET","/status"),rd=()=>me("GET","/texts"),c2=t=>me("GET",`/texts/${t}`),d2=t=>me("POST","/texts",t),u2=(t,o)=>me("PUT",`/texts/${t}`,o),f2=t=>me("DELETE",`/texts/${t}`),p2=(t,o,r=!0)=>me("POST",`/texts/${t}/detect-direction`,{words:null,update_field:r}),Ba=()=>me("GET","/jobs"),Gc=t=>me("POST","/jobs",t),fp=t=>me("DELETE",`/jobs/${t}`),pp=(t=!1)=>me("DELETE",t?"/jobs?finished_only=true":"/jobs"),pb=t=>me("POST",`/jobs/${t}/pause`),hb=t=>me("POST",`/jobs/${t}/resume`),gb=()=>me("POST","/jobs/pause-all"),mb=()=>me("POST","/jobs/resume-all"),h2=()=>me("POST","/jobs/clear-cache");function g2(){localStorage.removeItem("geb_run_cache"),localStorage.removeItem("glossa_seq_run_queue"),localStorage.removeItem("glossa_dashboard_insight_v2")}const xb=t=>me("GET",`/jobs/${t}/results`),ad=()=>me("GET","/settings"),m2=(t,o)=>me("POST","/settings/verify-key",{key_name:t,key_value:null}),sr=t=>me("PUT","/settings",t),x2=()=>me("GET","/catalog"),yb=()=>me("GET","/catalog/pipelines"),y2=t=>me("GET",`/reports${t?`?project_id=${t}`:""}`),b2=t=>me("DELETE",`/reports/${t}`),Df=t=>`/api/v1/reports/${t}/download`,v2=()=>me("GET","/reports/templates"),S2=t=>me("POST","/reports/generate",{template_id:t}),w2=t=>me("POST",`/reports/${t}/open-folder`),j2=(t,o)=>me("POST",`/pipelines/${t}/duplicate`,{new_id:o}),k2=t=>me("DELETE",`/pipelines/${t}`),_2=t=>me("POST","/pipelines/import",{source_path:t}),Ip=()=>me("GET","/studies");async function*C2(t,o){if(!t.ok){const d=await t.text().catch(()=>"");throw ub("POST",new URL(t.url).pathname,t.status,t.statusText,d)}const r=t.body.getReader(),l=new TextDecoder;let c="";try{for(;!(o!=null&&o.aborted);){const{done:d,value:u}=await r.read();if(d)break;c+=l.decode(u,{stream:!0});const p=c.split(` -`);c=p.pop()??"";for(const g of p)if(g.startsWith("data: ")&&g.length>6)try{yield JSON.parse(g.slice(6))}catch{}}}finally{r.releaseLock()}}async function*hp(t,o={},r,l=!1){const c=await fetch(`${ds}/experiment-graphs/${t}/run`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({kwargs:o,notify:l}),signal:r});yield*C2(c,r)}const $p=()=>me("GET","/experiments"),Lc=t=>me("GET",`/texts/${t}/entropy`),T2=(t,o=2,r=50)=>me("GET",`/texts/${t}/ngrams?n=${o}&limit=${r}`),z2=(t,o,r=5)=>me("GET",`/texts/${t}/concordance?q=${encodeURIComponent(o)}&w=${r}`),Kx=(t,o)=>`/api/v1/texts/${t}/export?fmt=${o}`,E2=t=>me("GET",`/hypotheses${t?`?project_id=${t}`:""}`),Ta=t=>me("POST","/hypotheses",t),ja=(t,o)=>me("PUT",`/hypotheses/${t}`,o),R2=t=>me("DELETE",`/hypotheses/${t}`),A2=t=>me("GET",`/notebooks${t?`?project_id=${t}`:""}`),M2=t=>me("POST","/notebooks",t),D2=(t,o)=>me("PUT",`/notebooks/${t}`,o),L2=t=>me("DELETE",`/notebooks/${t}`),N2=()=>me("GET","/citations"),Qx=t=>me("POST","/citations",t),B2=(t,o)=>me("PUT",`/citations/${t}`,o),O2=t=>me("DELETE",`/citations/${t}`),gp=(t,o)=>me("POST","/ai/chat",t,o),bb=t=>me("POST","/ai/execute-action",t),I2=t=>me("POST","/ai/decipher",t),$2=t=>me("POST","/ai/draft-section",t),vb=t=>me("POST","/ai/hypotheses/generate",t),Sb=t=>me("POST","/ai/experiment-chain",t),H2=t=>me("POST","/ai/synthesize",t),wb=t=>me("POST","/ai/sign-reading",t),W2=()=>me("GET","/ai/research-context"),jb=t=>me("POST","/ai/report-synthesis",t),U2=()=>me("POST","/system/peaks/clear"),q2=()=>"/api/v1/system/metrics/stream",G2=()=>me("GET","/ollama/library"),P2=()=>me("GET","/ollama/recommend"),F2=t=>me("DELETE",`/ollama/models/${encodeURIComponent(t)}`),Y2="glossa_ollama_ctx",V2=()=>parseInt(localStorage.getItem(Y2)??"4096",10)||4096,X2=()=>me("GET","/report-templates"),J2=t=>me("POST","/report-templates",t),K2=t=>me("DELETE",`/report-templates/${t}`),Q2=t=>me("GET","/anchor-sets"),Z2=t=>me("POST","/anchor-sets",t),ej=t=>me("DELETE",`/anchor-sets/${t}`),tj=t=>{const r=new URLSearchParams().toString();return me("GET",`/corpus-catalogue${r?`?${r}`:""}`)},nj=t=>me("POST",`/corpus-catalogue/${t}/import`),kb=()=>me("GET","/env/status"),ij=()=>me("GET","/env/packages"),oj=()=>fetch(`${ds}/env/setup`,{method:"POST"}),sj=()=>fetch(`${ds}/env/rebuild`,{method:"POST"}),rj=()=>fetch(`${ds}/env/upgrade`,{method:"POST"}),aj=()=>"/api/v1/terminal/log/stream",lj=()=>me("POST","/terminal/log/purge"),cj=(t,o)=>fetch(`${ds}/terminal/run`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({command:t,cwd:o,use_venv:!0})});function dj(t){const o=new URLSearchParams;for(const[l,c]of Object.entries(t))c==null||c===""||o.set(l,String(c));const r=o.toString();return r?`?${r}`:""}const uj=(t={})=>me("GET",`/discovery/items${dj(t)}`),fj=(t,o,r)=>me("POST",`/discovery/items/${encodeURIComponent(t)}/status`,{status:o,notes:r}),_b=()=>me("GET","/discovery/topics"),Cb=()=>me("GET","/discovery/sources"),Lf=(t="status")=>me("GET",`/discovery/stats?group=${t}`),Pc=t=>me("POST","/discovery/fetch",t),Hp=t=>me("POST","/discovery/mine",t),pj=(t={})=>{const o=new URLSearchParams;t.days!==void 0&&o.set("days",String(t.days)),t.limit!==void 0&&o.set("limit",String(t.limit)),t.include_ai!==void 0&&o.set("include_ai",String(t.include_ai)),t.project_id&&o.set("project_id",t.project_id);const r=o.toString();return me("GET",`/dashboard/highlights${r?"?"+r:""}`)},hj=(t={})=>{const o=new URLSearchParams;t.days!==void 0&&o.set("days",String(t.days)),t.limit!==void 0&&o.set("limit",String(t.limit)),t.project_id&&o.set("project_id",t.project_id);const r=o.toString();return me("POST",`/dashboard/insight${r?"?"+r:""}`)},gj=()=>me("GET","/dashboard/decipherment"),mj=()=>me("GET","/dashboard/latest-insight"),xj=()=>me("GET","/notifications/recipients"),yj=t=>me("POST","/notifications/recipients",t),Zx=(t,o)=>me("PATCH",`/notifications/recipients/${encodeURIComponent(t)}`,o),bj=t=>me("DELETE",`/notifications/recipients/${encodeURIComponent(t)}`),Tb=()=>me("GET","/notifications/status"),vj=(t=100)=>me("GET",`/notifications/log?limit=${t}`),Sj=()=>me("POST","/notifications/test"),wj=()=>me("POST","/notifications/graph/start"),jj=t=>me("POST","/notifications/graph/poll",{session_id:t}),kj=()=>me("POST","/notifications/graph/disconnect"),zb=()=>me("GET","/discovery/scheduler/status"),Eb=()=>me("POST","/discovery/scheduler/start"),Rb=()=>me("POST","/discovery/scheduler/stop"),Ab=()=>me("GET","/projects"),_j=()=>me("GET","/projects/active"),fc=(t,o)=>me("PUT",`/projects/${t}`,o),Mb=t=>me("POST",`/projects/${t}/activate`),Cj=t=>me("DELETE",`/projects/${t}`),Tj=t=>me("GET",`/correspondences${t?`?project_id=${t}`:""}`),ey=t=>me("POST","/correspondences",t),ty=(t,o)=>me("PUT",`/correspondences/${t}`,o),zj=t=>me("DELETE",`/correspondences/${t}`),Ej=t=>me("POST","/correspondences/parse",t),Db=(t=!1,o)=>{const r=new URLSearchParams;t&&r.set("enabled_only","true");const l=r.toString();return me("GET",`/providers${l?`?${l}`:""}`)},Rj=t=>me("POST","/providers",t),ny=(t,o)=>me("PATCH",`/providers/${t}`,o),Aj=t=>me("DELETE",`/providers/${t}`),Mj=t=>me("POST",`/providers/${t}/test`),Dj=()=>me("GET","/providers/detect-ollama"),Lj=()=>me("GET","/providers/cloud-providers"),Nj=()=>me("GET","/model-assignments"),Bj=(t,o)=>me("PUT",`/model-assignments/${t}`,o),Oj=(t="mixed")=>me("POST",`/model-assignments/auto-configure?profile=${t}`),Lb=t=>me("GET","/model-intelligence/scores"),Nb=()=>me("POST","/model-intelligence/sync"),Ij=()=>me("POST","/model-intelligence/test-hf"),Nf=[{id:"outlook365_oauth",label:"Outlook 365 (Microsoft Graph OAuth) — recommended",category:"oauth",recommended:!0,notes:"Modern SSO via device-code flow. Works with personal and work/school accounts. No app password needed."},{id:"resend_api",label:"Resend (HTTPS API) — no SMTP, no mailbox, no domain",category:"api",recommended:!0,notes:"Sign up at resend.com, generate an API key, paste it here. Sends from onboarding@resend.dev (free, 100/day, 3000/month) without any DNS setup. Verify your own domain in Resend later for branded From: addresses."},{id:"microsoft365_smtp",label:"Microsoft 365 SMTP (legacy / basic auth)",category:"smtp",smtp_host:"smtp.office365.com",smtp_port:587,smtp_use_tls:!0,notes:"Only works if your tenant still allows SMTP AUTH. Most do not — use the OAuth option above instead."},{id:"outlook_com",label:"Outlook.com / Hotmail / Live",category:"smtp",smtp_host:"smtp-mail.outlook.com",smtp_port:587,smtp_use_tls:!0,notes:"Use your full email as username and an app password (account.live.com → Security → App passwords)."},{id:"gmail",label:"Gmail / Google Workspace",category:"smtp",smtp_host:"smtp.gmail.com",smtp_port:587,smtp_use_tls:!0,notes:"Requires an app password (myaccount.google.com → Security → 2-Step Verification → App passwords)."},{id:"yahoo",label:"Yahoo Mail",category:"smtp",smtp_host:"smtp.mail.yahoo.com",smtp_port:587,smtp_use_tls:!0,notes:"Requires an app password (login.yahoo.com → Account Security → Generate app password)."},{id:"icloud",label:"Apple iCloud Mail",category:"smtp",smtp_host:"smtp.mail.me.com",smtp_port:587,smtp_use_tls:!0,notes:"Requires an app-specific password (appleid.apple.com → Sign-In and Security → App-Specific Passwords)."},{id:"zoho",label:"Zoho Mail",category:"smtp",smtp_host:"smtp.zoho.com",smtp_port:587,smtp_use_tls:!0,notes:"For zoho.eu users use smtp.zoho.eu. Generate an app-specific password in your Zoho Mail account."},{id:"infomaniak",label:"Infomaniak (incl. swissmail.io)",category:"smtp",smtp_host:"mail.infomaniak.com",smtp_port:465,smtp_use_tls:!0,notes:"Common Swiss research provider. Port 465 = SSL on connect; some setups also allow 587 STARTTLS."},{id:"protonmail_bridge",label:"ProtonMail (Bridge)",category:"smtp",smtp_host:"127.0.0.1",smtp_port:1025,smtp_use_tls:!0,notes:"Run ProtonMail Bridge locally; it exposes a local SMTP relay on 127.0.0.1:1025."},{id:"sendgrid",label:"SendGrid",category:"smtp",smtp_host:"smtp.sendgrid.net",smtp_port:587,smtp_use_tls:!0,notes:"Use 'apikey' as the username and your SendGrid API key as the password."},{id:"mailgun",label:"Mailgun",category:"smtp",smtp_host:"smtp.mailgun.org",smtp_port:587,smtp_use_tls:!0,notes:"Use the SMTP credentials shown in your Mailgun domain dashboard."},{id:"university",label:"University / research-institution SMTP",category:"smtp",smtp_port:587,smtp_use_tls:!0,notes:"Most universities expose smtp..edu on port 587 STARTTLS. Check your IT pages — some require VPN or institutional MFA app passwords."},{id:"custom",label:"Custom SMTP",category:"smtp",smtp_port:587,smtp_use_tls:!0,notes:"Fill in your provider's host, port, and TLS settings manually."}],$j=(t={})=>{const o=new URLSearchParams;t.q&&o.set("q",t.q),t.status&&o.set("status",t.status),t.limit!==void 0&&o.set("limit",String(t.limit)),t.offset!==void 0&&o.set("offset",String(t.offset));const r=o.toString();return me("GET",`/indus-evidence/library${r?`?${r}`:""}`)},Hj=(t={})=>{const o=new URLSearchParams;Object.entries(t).forEach(([l,c])=>{c!==void 0&&c!==""&&o.set(l,String(c))});const r=o.toString();return me("GET",`/indus-evidence/claims${r?`?${r}`:""}`)},Wj=()=>me("GET","/indus-evidence/hypotheses"),Uj=()=>me("GET","/indus-evidence/sweep/config"),qj=t=>me("PUT","/indus-evidence/sweep/config",t),Gj=()=>me("POST","/indus-evidence/sweep/run"),Pj=()=>me("GET","/indus-evidence/sweep/candidates"),Bb=t=>me("POST","/indus-evidence/sweep/intake",t),Fj=t=>me("POST","/indus-evidence/import-url",t),Yj=()=>me("POST","/indus-evidence/intake/run"),Vj=t=>{const o=new FormData;return o.append("file",t),fetch(`${ds}/indus-evidence/upload`,{method:"POST",body:o})},Ob=x.createContext({toast:()=>{},notifications:[],unreadCount:0,markAllRead:()=>{},clearNotification:()=>{},clearAllNotifications:()=>{}});let Xj=0;function Jj({children:t}){const[o,r]=x.useState([]),[l,c]=x.useState([]),d=x.useRef(new Map),u=x.useCallback(S=>{r(_=>_.filter(T=>T.id!==S));const k=d.current.get(S);k&&(clearTimeout(k),d.current.delete(S))},[]),p=x.useCallback((S,k="info",_=3500)=>{const T=++Xj;r(C=>[...C.slice(-5),{id:T,message:S,type:k}]),c(C=>[{id:T,message:S,type:k,timestamp:Date.now(),read:!1},...C.slice(0,99)]);const w=setTimeout(()=>u(T),_);d.current.set(T,w)},[u]),g=x.useCallback(()=>c(S=>S.map(k=>({...k,read:!0}))),[]),h=x.useCallback(S=>c(k=>k.filter(_=>_.id!==S)),[]),v=x.useCallback(()=>c([]),[]),y=l.filter(S=>!S.read).length;x.useEffect(()=>()=>{d.current.forEach(clearTimeout)},[]);const b={success:"#16a34a",error:"#dc2626",info:"#2563eb",warning:"#d97706"};return n.jsxs(Ob.Provider,{value:{toast:p,notifications:l,unreadCount:y,markAllRead:g,clearNotification:h,clearAllNotifications:v},children:[t,n.jsx("div",{style:{position:"fixed",bottom:20,right:20,display:"flex",flexDirection:"column",gap:8,zIndex:9999,pointerEvents:"none"},children:o.map(S=>n.jsxs("div",{style:{background:b[S.type],color:"#fff",padding:"10px 16px",borderRadius:8,fontSize:13,fontWeight:500,boxShadow:"0 4px 16px rgba(0,0,0,0.18)",display:"flex",alignItems:"center",gap:10,pointerEvents:"auto",cursor:"pointer",animation:"slideIn 0.2s ease",maxWidth:360},onClick:()=>u(S.id),children:[n.jsx("span",{style:{flex:1},children:S.message}),n.jsx("span",{style:{opacity:.7,fontSize:16,flexShrink:0},children:"×"})]},S.id))}),n.jsx("style",{children:"@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}"})]})}function et(){return x.useContext(Ob)}const Kj=60;function Vo({value:t,max:o=100,label:r,sub:l="",color:c="#2563eb",peak:d}){const u=Math.min(100,t/o*100),p=d!==void 0?Math.min(100,d/o*100):void 0,g=u>80,v=u>95?"#dc2626":g?"#d97706":c;return n.jsxs("div",{style:{padding:"12px 14px",borderRadius:8,border:"1px solid #e5e7eb",background:"#fafafa",flex:1,minWidth:140},children:[n.jsx("div",{style:{fontSize:10,fontWeight:700,color:"#9ca3af",textTransform:"uppercase",letterSpacing:.5,marginBottom:6},children:r}),n.jsxs("div",{style:{fontSize:22,fontWeight:800,color:v,fontFamily:"monospace",marginBottom:4,lineHeight:1},children:[t.toFixed(t<10?1:0),n.jsx("span",{style:{fontSize:11,fontWeight:400,color:"#9ca3af",marginLeft:2},children:o===100?"%":""})]}),l&&n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginBottom:6},children:l}),n.jsxs("div",{style:{height:5,background:"#f3f4f6",borderRadius:3,overflow:"visible",position:"relative"},children:[n.jsx("div",{style:{height:"100%",width:`${u}%`,background:v,borderRadius:3,transition:"width 0.4s ease"}}),p!==void 0&&n.jsx("div",{style:{position:"absolute",top:-1,left:`${p}%`,width:2,height:7,background:"#9ca3af",borderRadius:1,transform:"translateX(-50%)"},title:`Peak: ${d==null?void 0:d.toFixed(1)}`})]}),p!==void 0&&n.jsxs("div",{style:{fontSize:10,color:"#9ca3af",marginTop:3},children:["Peak ",d==null?void 0:d.toFixed(1),o===100?"%":""]})]})}function Xo({values:t,color:o="#2563eb",height:r=32}){if(t.length<2)return n.jsx("div",{style:{height:r}});const l=Math.max(...t,1),c=200,d=c/(t.length-1),u=t.map((p,g)=>`${g*d},${r-p/l*(r-2)-1}`).join(" ");return n.jsxs("svg",{viewBox:`0 0 ${c} ${r}`,style:{width:"100%",height:r,display:"block"},children:[n.jsx("polyline",{points:u,fill:"none",stroke:o,strokeWidth:1.5,opacity:.8}),n.jsx("circle",{cx:(t.length-1)*d,cy:r-t[t.length-1]/l*(r-2)-1,r:2.5,fill:o})]})}function Ps({label:t,current:o,unit:r,peak:l,color:c="#6b7280"}){return n.jsxs("div",{style:{display:"flex",gap:8,padding:"4px 0",borderBottom:"1px solid #f3f4f6",alignItems:"center",fontSize:12},children:[n.jsx("span",{style:{color:"#9ca3af",width:120,flexShrink:0},children:t}),n.jsxs("span",{style:{fontFamily:"monospace",fontWeight:600,color:c},children:[o,n.jsx("span",{style:{color:"#9ca3af",marginLeft:2,fontSize:10},children:r})]}),l&&n.jsxs("span",{style:{marginLeft:"auto",fontSize:10,color:"#9ca3af"},children:["↑ ",l,r]})]})}function Qj({values:t}){return n.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:3,marginTop:8},children:t.map((o,r)=>{const l=o>80?"#dc2626":o>50?"#d97706":"#16a34a";return n.jsx("div",{title:`Core ${r}: ${o}%`,style:{width:20,height:20,borderRadius:3,background:l+"20",border:`1px solid ${l}40`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:7,fontWeight:700,color:l},children:Math.round(o)},r)})})}function Zj(){const{toast:t}=et(),[o,r]=x.useState(null),[l,c]=x.useState(null),[d,u]=x.useState(null),[p,g]=x.useState(null),[h,v]=x.useState(null),[y,b]=x.useState(null),[S,k]=x.useState(!1),_=x.useRef({cpu:[],ram:[],gpu:[],disk_read:[],disk_write:[],net_send:[],net_recv:[]}),T=x.useCallback((M,q)=>{const K=_.current[M]??[];K.push(q),K.length>Kj&&K.shift(),_.current[M]=K},[]);x.useEffect(()=>{const M=async()=>{try{const[K,D]=await Promise.all([Na(),l2()]);r(K),c(D),b(null),x2().then(u).catch(()=>{}),Ip().then(Y=>g(Y.length)).catch(()=>{})}catch(K){b(K instanceof Error?K.message:"Connection failed")}};M();const q=setInterval(M,8e3);return()=>clearInterval(q)},[]);const w=x.useRef(null),[C,j]=x.useState(!1),L=x.useCallback(()=>{if(w.current)return;const M=new EventSource(q2());w.current=M,j(!0),M.onmessage=q=>{var K;try{const D=JSON.parse(q.data);v(D),T("cpu",D.cpu.percent),T("ram",D.ram.percent),T("gpu",((K=D.gpu[0])==null?void 0:K.utilization_pct)??0),T("disk_read",D.disk.read_mbps),T("disk_write",D.disk.write_mbps),T("net_send",D.network.send_mbps*1e3),T("net_recv",D.network.recv_mbps*1e3)}catch{}},M.onerror=()=>{M.close(),w.current=null,j(!1),setTimeout(L,3e3)}},[T]);x.useEffect(()=>(L(),()=>{var M;(M=w.current)==null||M.close(),w.current=null}),[L]);const W=async()=>{k(!0);try{await U2(),t("Peaks cleared","success")}catch{t("Failed to clear peaks","error")}finally{k(!1)}},P=(o==null?void 0:o.status)==="healthy",z=h;return n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem"},children:[n.jsx("h2",{style:{margin:0},children:"System Status"}),n.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[C&&n.jsxs("span",{style:{fontSize:11,color:"#16a34a",display:"flex",alignItems:"center",gap:4},children:[n.jsx("span",{style:{width:7,height:7,borderRadius:"50%",background:"#16a34a",display:"inline-block",animation:"healthPulse 1.5s infinite"}}),"Live"]}),n.jsx("button",{onClick:W,disabled:S,style:{padding:"4px 12px",border:"1px solid #e5e7eb",borderRadius:4,background:"#f9fafb",cursor:"pointer",fontSize:12,color:"#6b7280"},children:S?"…":"Clear Peaks"})]})]}),n.jsx("div",{style:{padding:"12px 16px",borderRadius:8,border:`1px solid ${P?"#bbf7d0":"#fca5a5"}`,background:P?"#f0fdf4":"#fef2f2",marginBottom:"1.5rem"},children:n.jsxs("div",{style:{display:"flex",gap:12,alignItems:"center",flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:10,fontWeight:700,color:"#9ca3af",textTransform:"uppercase"},children:"Backend"}),n.jsx("span",{style:{fontWeight:700,color:P?"#16a34a":"#dc2626"},children:y?`Offline — ${y}`:(o==null?void 0:o.status)??"Loading…"}),o&&n.jsxs(n.Fragment,{children:[n.jsxs("span",{style:{fontSize:12,color:"#6b7280"},children:["v",o.version]}),n.jsxs("span",{style:{fontSize:12,color:"#6b7280"},children:["up ",Math.round(o.uptime_seconds),"s"]})]}),d&&n.jsx(n.Fragment,{children:Object.entries(d.counts).map(([M,q])=>n.jsxs("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:6,background:"#f3f4f6",color:"#374151"},children:[M,": ",q]},M))}),p!==null&&n.jsxs("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:6,background:"#f3f4f6",color:"#374151"},children:["studies: ",p]})]})}),!z&&n.jsxs("div",{style:{textAlign:"center",padding:"3rem",color:"#9ca3af"},children:[n.jsx("div",{style:{fontSize:28,marginBottom:8},children:"⚙️"}),n.jsx("div",{children:"Connecting to metrics stream…"})]}),z&&n.jsxs(n.Fragment,{children:[n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Fs,children:[n.jsx("span",{style:Ys,children:"CPU"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280"},children:[z.cpu.count_physical,"C / ",z.cpu.count_logical,"T",z.cpu.freq_mhz&&` · ${z.cpu.freq_mhz} MHz`,z.cpu.freq_max_mhz&&` (max ${z.cpu.freq_max_mhz} MHz)`]})]}),n.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:10},children:n.jsx(Vo,{value:z.cpu.percent,label:"Utilization",color:"#2563eb",peak:z.cpu.peak_pct,sub:`${z.cpu.count_logical} logical cores`})}),n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("div",{style:{fontSize:10,fontWeight:700,color:"#9ca3af",textTransform:"uppercase",letterSpacing:.5,marginBottom:4},children:"60s History"}),n.jsx(Xo,{values:_.current.cpu,color:"#2563eb",height:36})]}),n.jsx(Qj,{values:z.cpu.per_core_pct})]}),n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Fs,children:[n.jsx("span",{style:Ys,children:"Memory"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280"},children:[z.ram.total_gb," GB total"]})]}),n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:10},children:[n.jsx(Vo,{value:z.ram.percent,label:"RAM Usage",color:"#7c3aed",peak:z.ram.peak_pct,sub:`${z.ram.used_gb} / ${z.ram.total_gb} GB used`}),z.ram.swap_total_gb>0&&n.jsx(Vo,{value:z.ram.swap_used_gb/z.ram.swap_total_gb*100,label:"Swap",color:"#d97706",sub:`${z.ram.swap_used_gb.toFixed(1)} / ${z.ram.swap_total_gb} GB`})]}),n.jsx(Xo,{values:_.current.ram,color:"#7c3aed",height:36}),n.jsxs("div",{style:{marginTop:6},children:[n.jsx(Ps,{label:"Available",current:z.ram.available_gb.toString(),unit:" GB",color:"#16a34a"}),n.jsx(Ps,{label:"Used",current:z.ram.used_gb.toString(),unit:" GB"})]})]}),z.gpu.length>0&&n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Fs,children:[n.jsx("span",{style:Ys,children:"GPU"}),n.jsx("span",{style:{fontSize:11,color:"#6b7280"},children:z.gpu[0].name})]}),z.gpu.map((M,q)=>n.jsx("div",{style:{marginBottom:10},children:n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:10},children:[n.jsx(Vo,{value:M.utilization_pct,label:"GPU Util",color:"#16a34a",peak:z.gpu_peaks.utilization_pct,sub:`${M.temperature_c!==null?M.temperature_c+"°C":""}`}),n.jsx(Vo,{value:M.memory_utilization_pct,label:"VRAM %",color:"#d97706",peak:z.gpu_peaks.memory_utilization_pct,sub:`${M.memory_used_mb} / ${M.memory_total_mb} MB`}),n.jsx(Vo,{value:M.memory_used_mb/M.memory_total_mb*100,label:"VRAM Used",color:"#d97706",sub:`${(M.memory_used_mb/1024).toFixed(1)} / ${(M.memory_total_mb/1024).toFixed(1)} GB`})]})},q)),n.jsx(Xo,{values:_.current.gpu,color:"#16a34a",height:36})]}),z.gpu.length===0&&n.jsx("section",{style:{...Jo,padding:"12px 16px"},children:n.jsx("div",{style:{color:"#9ca3af",fontSize:13},children:"🎮 No NVIDIA GPU detected — nvidia-smi not available or no GPU present."})}),n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Fs,children:[n.jsx("span",{style:Ys,children:"Disk"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280"},children:[z.disk.total_gb," GB total · ",z.disk.free_gb," GB free"]})]}),n.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:10},children:n.jsx(Vo,{value:z.disk.percent,label:"Disk Used",color:"#dc2626",sub:`${z.disk.used_gb} / ${z.disk.total_gb} GB`})}),n.jsxs("div",{style:{display:"flex",gap:16,marginBottom:8},children:[n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:10,color:"#9ca3af",marginBottom:2},children:"Read MB/s"}),n.jsx(Xo,{values:_.current.disk_read,color:"#2563eb",height:28})]}),n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:10,color:"#9ca3af",marginBottom:2},children:"Write MB/s"}),n.jsx(Xo,{values:_.current.disk_write,color:"#dc2626",height:28})]})]}),n.jsxs("div",{children:[n.jsx(Ps,{label:"Read",current:z.disk.read_mbps.toFixed(2),unit:" MB/s",color:"#2563eb",peak:z.disk.peak_read_mbps.toFixed(2)}),n.jsx(Ps,{label:"Write",current:z.disk.write_mbps.toFixed(2),unit:" MB/s",color:"#dc2626",peak:z.disk.peak_write_mbps.toFixed(2)})]})]}),n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Fs,children:[n.jsx("span",{style:Ys,children:"Network"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280"},children:["↑ ",z.network.total_sent_gb.toFixed(2)," GB sent · ↓ ",z.network.total_recv_gb.toFixed(2)," GB recv"]})]}),n.jsxs("div",{style:{display:"flex",gap:16,marginBottom:8},children:[n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:10,color:"#9ca3af",marginBottom:2},children:"Upload KB/s"}),n.jsx(Xo,{values:_.current.net_send,color:"#7c3aed",height:28})]}),n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:10,color:"#9ca3af",marginBottom:2},children:"Download KB/s"}),n.jsx(Xo,{values:_.current.net_recv,color:"#16a34a",height:28})]})]}),n.jsxs("div",{children:[n.jsx(Ps,{label:"Upload",current:(z.network.send_mbps*1e3).toFixed(1),unit:" KB/s",color:"#7c3aed",peak:(z.network.peak_send_mbps*1e3).toFixed(1)}),n.jsx(Ps,{label:"Download",current:(z.network.recv_mbps*1e3).toFixed(1),unit:" KB/s",color:"#16a34a",peak:(z.network.peak_recv_mbps*1e3).toFixed(1)})]})]}),(l==null?void 0:l.pipelines)&&l.pipelines.length>0&&n.jsxs("section",{style:Jo,children:[n.jsx("div",{style:Fs,children:n.jsx("span",{style:Ys,children:"Registered Pipelines"})}),n.jsx("ul",{style:{columnCount:2,paddingLeft:"1.2rem",margin:0,fontSize:12},children:l.pipelines.map(M=>n.jsx("li",{style:{fontFamily:"monospace",marginBottom:2},children:M},M))})]})]}),n.jsx("style",{children:"@keyframes healthPulse { 0%,100%{opacity:1} 50%{opacity:0.3} }"})]})}const Jo={marginBottom:"1rem",padding:"14px 16px",border:"1px solid #e5e7eb",borderRadius:8},Fs={display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12},Ys={fontSize:12,fontWeight:700,color:"#374151",textTransform:"uppercase",letterSpacing:.5};function ek(){const[t,o]=x.useState(null),r=x.useCallback((c,d)=>{c.preventDefault(),c.stopPropagation();const u=Math.min(c.clientX,window.innerWidth-180),p=Math.min(c.clientY,window.innerHeight-d.length*34-8);o({x:u,y:p,items:d})},[]),l=x.useCallback(()=>o(null),[]);return x.useEffect(()=>{if(!t)return;const c=()=>o(null);return window.addEventListener("click",c,{once:!0}),window.addEventListener("keydown",d=>{d.key==="Escape"&&o(null)},{once:!0}),()=>window.removeEventListener("click",c)},[t]),{menu:t,show:r,close:l}}function tk({menu:t,onClose:o}){return t?n.jsx("div",{style:{position:"fixed",left:t.x,top:t.y,background:"#fff",border:"1px solid #e5e7eb",borderRadius:6,boxShadow:"0 8px 24px rgba(0,0,0,0.12)",zIndex:8e3,minWidth:160,padding:"4px 0",fontSize:13},onClick:r=>r.stopPropagation(),children:t.items.map((r,l)=>n.jsxs("div",{onClick:()=>{r.disabled||(r.action(),o())},style:{padding:"7px 14px",cursor:r.disabled?"not-allowed":"pointer",display:"flex",alignItems:"center",gap:8,color:r.disabled?"#9ca3af":"#111827",background:"transparent"},onMouseEnter:c=>{r.disabled||(c.currentTarget.style.background="#f3f4f6")},onMouseLeave:c=>{c.currentTarget.style.background="transparent"},children:[r.icon&&n.jsx("span",{style:{fontSize:14,width:16},children:r.icon}),r.label]},l))}):null}function nk(t,o="Copy"){return[{label:o,icon:"⎘",action:()=>navigator.clipboard.writeText(t).catch(()=>{})},{label:"Copy All (plain text)",icon:"📋",action:()=>navigator.clipboard.writeText(t).catch(()=>{})}]}const Ib=x.createContext({isOpen:!1,request:null,openChat:()=>{},closeChat:()=>{},toggleChat:()=>{},isDocked:!1,setDocked:()=>{}});function ik({children:t}){const[o,r]=x.useState(!1),[l,c]=x.useState(null),[d,u]=x.useState(!1),p=x.useCallback(v=>{v&&c(v),r(!0),window.dispatchEvent(new CustomEvent("glossa:open-ai-panel"))},[]),g=x.useCallback(()=>r(!1),[]),h=x.useCallback(()=>{r(v=>!v),o||c(null)},[o]);return n.jsx(Ib.Provider,{value:{isOpen:o,request:l,openChat:p,closeChat:g,toggleChat:h,isDocked:d,setDocked:u},children:t})}function us(){return x.useContext(Ib)}const $b=["linguistic","ancient","dna","code","random","other"],Hb=[{value:"unknown",label:"Unknown"},{value:"ltr",label:"LTR — Left to Right"},{value:"rtl",label:"RTL — Right to Left"}],iy={ltr:{label:"LTR",color:"#065f46",bg:"#d1fae5"},rtl:{label:"RTL",color:"#7c2d12",bg:"#fee2e2"},unknown:{label:"?",color:"#6b7280",bg:"#f3f4f6"}},Bf=200;function oy({data:t,xKey:o,yKey:r,color:l="#2563eb",height:c=100}){if(!t.length)return null;const d=t.map(g=>Number(g[r])||0),u=Math.max(...d,1),p=Math.max(8,Math.floor(560/t.length));return n.jsx("svg",{viewBox:`0 0 ${t.length*p} ${c}`,style:{width:"100%",height:c,overflow:"visible"},children:t.map((g,h)=>{const v=Number(g[r])||0,y=Math.max(1,v/u*(c-16));return n.jsxs("g",{children:[n.jsx("rect",{x:h*p+1,y:c-y-12,width:Math.max(2,p-2),height:y,fill:l,opacity:.8,rx:1}),t.length<=20&&n.jsx("text",{x:h*p+p/2,y:c-2,textAnchor:"middle",fontSize:Math.min(9,p-1),fill:"#6b7280",children:String(g[o]).slice(0,4)})]},h)})})}function ok({values:t,color:o="#2563eb"}){if(t.length<2)return null;const r=40,l=300,c=Math.max(...t,1),d=Math.min(...t,0),u=c-d||1,p=l/(t.length-1),g=t.map((h,v)=>`${v*p},${r-(h-d)/u*r}`).join(" ");return n.jsx("svg",{viewBox:`0 0 ${l} ${r}`,style:{width:"100%",height:r},children:n.jsx("polyline",{points:g,fill:"none",stroke:o,strokeWidth:1.5})})}function Vs({label:t,value:o,color:r="#374151"}){return n.jsxs("div",{style:{padding:"6px 12px",borderRadius:6,background:"#f9fafb",border:"1px solid #e5e7eb",textAlign:"center",minWidth:90},children:[n.jsx("div",{style:{fontSize:18,fontWeight:700,color:r,fontFamily:"monospace"},children:o}),n.jsx("div",{style:{fontSize:10,color:"#6b7280",textTransform:"uppercase",letterSpacing:.5},children:t})]})}function sk(t){let o=!1,r=!1,l=!1,c=!1;for(const u of t){const p=u.codePointAt(0)??0;if(p>=48&&p<=57){o=!0;continue}if(p>=65&&p<=90||p>=97&&p<=122){r=!0;continue}if(!(p===45||p===95||p===32)){if(p<128){c=!0;continue}l=!0}}return[o,r,l,c].filter(Boolean).length>1?"mixed":l?"ancient":r?"latin":c?"punctuation":"numeric"}const rk={numeric:{label:"Numeric codes",color:"#2563eb",bg:"#dbeafe",desc:"Tokens like 066 or 066-069 (sign codes)"},latin:{label:"Latin / ASCII",color:"#16a34a",bg:"#dcfce7",desc:"Latin letter tokens"},ancient:{label:"Non-Latin Unicode",color:"#7c3aed",bg:"#ede9fe",desc:"Ancient script glyphs (Geez, Hebrew, etc.)"},punctuation:{label:"Punctuation",color:"#d97706",bg:"#fef3c7",desc:"Punctuation-only tokens"},mixed:{label:"Mixed (⚠ noise)",color:"#dc2626",bg:"#fee2e2",desc:"Tokens mixing Latin + non-Latin + punctuation"}};function ak({tokens:t}){const o={numeric:0,latin:0,ancient:0,punctuation:0,mixed:0};for(const u of t)o[sk(u)]++;const r=t.length||1,l=o.mixed/r*100,c=l>5,d=Object.entries(o).filter(([,u])=>u>0);return n.jsxs("div",{style:{marginTop:16,padding:"10px 12px",border:"1px solid #e5e7eb",borderRadius:6,background:"#f9fafb"},children:[n.jsx("div",{style:{fontSize:10,fontWeight:700,color:"#7c3aed",textTransform:"uppercase",letterSpacing:.5,marginBottom:8},children:"Token-Type Breakdown"}),c&&n.jsxs("div",{style:{padding:"4px 8px",background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:4,fontSize:11,color:"#991b1b",marginBottom:8},children:["⚠ ",l.toFixed(1),"% mixed-category tokens detected. Consider using a ",n.jsx("strong",{children:"TokenFilter"})," node to sanitize this corpus before analysis."]}),n.jsx("div",{style:{display:"flex",flexDirection:"column",gap:5},children:d.map(([u,p])=>{const g=rk[u],h=p/r*100;return n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[n.jsx("div",{style:{width:130,fontSize:11,color:g.color,fontWeight:600,flexShrink:0},title:g.desc,children:g.label}),n.jsx("div",{style:{flex:1,background:"#e5e7eb",borderRadius:3,height:10,overflow:"hidden"},children:n.jsx("div",{style:{width:`${h}%`,background:g.color,height:"100%",borderRadius:3,opacity:.85}})}),n.jsxs("div",{style:{width:60,fontSize:11,color:"#6b7280",textAlign:"right",flexShrink:0},children:[p.toLocaleString()," (",h.toFixed(1),"%)"]})]},u)})})]})}function lk({text:t,onUpdated:o,onDeleted:r,allTexts:l}){const{toast:c}=et(),[d,u]=x.useState(!1),[p,g]=x.useState("browse"),[h,v]=x.useState(0),[y,b]=x.useState(""),[S,k]=x.useState(t.name),[_,T]=x.useState(t.corpus_type),[w,C]=x.useState(t.content.join(" ")),[j,L]=x.useState("space"),[W,P]=x.useState(t.reading_direction??"unknown"),[z,M]=x.useState(!1),[q,K]=x.useState(!1),[D,Y]=x.useState(2),[H,A]=x.useState(null),[G,R]=x.useState(!1),[X,B]=x.useState(""),[V,Q]=x.useState(null),[N,O]=x.useState(!1),[$,F]=x.useState(null),[I,J]=x.useState(!1),[ne,se]=x.useState("analyze"),[pe,_e]=x.useState(""),[we,ke]=x.useState(null),[te,de]=x.useState(null),[Ce,ze]=x.useState(!1),ve=x.useRef(null),{menu:De,show:Me,close:Ve}=ek(),{openChat:Le}=us(),Ae=y?t.content.filter(fe=>fe.toLowerCase().includes(y.toLowerCase())):t.content,Ue=Math.ceil(Ae.length/Bf),Oe=Ae.slice(h*Bf,(h+1)*Bf),dt=async()=>{K(!0);try{let fe;j==="line"?fe=w.split(` -`).map(Et=>Et.trim()).filter(Boolean):j==="char"?fe=w.replace(/\s/g,"").split(""):fe=w.trim().split(/\s+/).filter(Boolean);const ft=await u2(t.id,{name:S.trim(),corpus_type:_,content:fe,reading_direction:W});o(ft),c("Corpus updated","success")}catch(fe){c(fe instanceof Error?fe.message:"Save failed","error")}finally{K(!1)}},it=async()=>{M(!0);try{const fe=await p2(t.id);P(fe.inferred_direction);const ft=await c2(t.id);o(ft);const Et=fe.confidence==="high"?"high confidence":fe.confidence==="medium"?"medium confidence":"low confidence";c(`Detected: ${fe.inferred_direction.toUpperCase()} (${Et}, ${fe.n_words} words)`,"info")}catch(fe){c(fe instanceof Error?fe.message:"Detection failed","error")}finally{M(!1)}},[lt,Je]=x.useState(!1),yt=()=>{navigator.clipboard.writeText(t.content.join(" ")).then(()=>{Je(!0),setTimeout(()=>Je(!1),1400)})},Jt=fe=>{var qt;const ft=(qt=fe.target.files)==null?void 0:qt[0];if(!ft)return;const Et=new FileReader;Et.onload=Gt=>{var oe;const Ct=(oe=Gt.target)==null?void 0:oe.result;if(ft.name.endsWith(".json"))try{const Ne=JSON.parse(Ct);C(Array.isArray(Ne)?Ne.join(" "):(Ne.content??[]).join(" ")||Ct)}catch{C(Ct)}else C(Ct);g("edit")},Et.readAsText(ft),fe.target.value=""},rn=async()=>{R(!0);try{A(await T2(t.id,D))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{R(!1)}},zt=async()=>{if(X.trim()){O(!0);try{Q(await z2(t.id,X.trim()))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{O(!1)}}},ae=x.useCallback(async()=>{if(!$){J(!0);try{F(await Lc(t.id))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{J(!1)}}},[$,t.id,c]),He=()=>{const fe={analyze:`Please analyze the corpus "${t.name}" (${t.corpus_type}, ${t.content.length.toLocaleString()} tokens, alphabet ${t.alphabet_size}). Provide: summary, linguistic characteristics, Indus Script relevance, key insights, and suggested experiments.`,anomalies:`Please detect anomalies in the corpus "${t.name}" (${t.corpus_type}, ${t.content.length.toLocaleString()} tokens). Look for statistical anomalies, unusual patterns, structural breaks, and data quality issues.`,critique:`Please critique the corpus "${t.name}" (${t.corpus_type}, ${t.content.length.toLocaleString()} tokens, alphabet ${t.alphabet_size}) for research use. Evaluate coverage, bias, completeness, and suitability for Indus Script entropy analysis.`};Le({contextType:"corpus",contextId:t.id,contextLabel:t.name,initialPrompt:fe[ne]})},Ze=async()=>{if(pe){ze(!0);try{const[fe,ft]=await Promise.all([Lc(t.id),Lc(pe)]);de(fe),ke(ft)}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{ze(!1)}}};x.useEffect(()=>{d&&p==="stats"&&ae()},[d,p,ae]);const Ut={linguistic:"#2563eb",ancient:"#7c3aed",dna:"#16a34a",code:"#d97706",random:"#6b7280"}[t.corpus_type]??"#374151",Nt=[{id:"browse",label:"Browse"},{id:"edit",label:"Edit"},{id:"stats",label:"Stats"},{id:"ngrams",label:"N-grams"},{id:"concordance",label:"Concordance"},{id:"ai",label:"✨ AI"},{id:"compare",label:"Compare"}],yn=()=>{const fe=!d;u(fe),fe&&window.dispatchEvent(new CustomEvent("glossa:context",{detail:{type:"corpus",id:t.id,name:t.name}}))};return n.jsxs("div",{style:{border:"1px solid #e5e7eb",borderRadius:8,overflow:"hidden",marginBottom:8,boxShadow:"0 1px 3px rgba(0,0,0,0.04)"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px",background:"#fafafa",cursor:"pointer",borderBottom:d?"1px solid #e5e7eb":"none"},onClick:yn,children:[n.jsx("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:8,background:Ut+"20",color:Ut,fontWeight:700,whiteSpace:"nowrap"},children:t.corpus_type}),(()=>{const fe=t.reading_direction??"unknown";if(fe==="unknown")return null;const ft=iy[fe]??iy.ltr;return n.jsx("span",{title:`Reading direction: ${fe.toUpperCase()}`,style:{fontSize:10,padding:"1px 6px",borderRadius:8,background:ft.bg,color:ft.color,fontWeight:700,whiteSpace:"nowrap",border:`1px solid ${ft.color}33`},children:ft.label})})(),n.jsx("span",{style:{flex:1,fontWeight:600,fontSize:13,color:"#111827"},children:t.name}),n.jsxs("span",{style:{fontSize:11,color:"#9ca3af"},children:[t.content.length.toLocaleString()," tokens"]}),n.jsxs("span",{style:{fontSize:11,color:"#9ca3af"},children:["Σ ",t.alphabet_size]}),n.jsx("span",{style:{fontSize:11,color:"#9ca3af"},children:t.created_at.slice(0,10)}),n.jsxs("span",{onClick:fe=>fe.stopPropagation(),style:{display:"flex",gap:4},children:[n.jsx("button",{onClick:yt,title:"Copy",style:{...or,background:lt?"#dcfce7":void 0,color:lt?"#16a34a":void 0,transition:"background 0.2s"},children:lt?"✓":"⎘"}),n.jsx("a",{href:Kx(t.id,"txt"),download:!0,onClick:fe=>fe.stopPropagation(),style:{...or,textDecoration:"none"},children:"↓txt"}),n.jsx("a",{href:Kx(t.id,"csv"),download:!0,onClick:fe=>fe.stopPropagation(),style:{...or,textDecoration:"none"},children:"↓csv"}),n.jsx("button",{onClick:()=>{var fe;return(fe=ve.current)==null?void 0:fe.click()},title:"Import file",style:or,children:"↑ file"}),n.jsx("button",{onClick:async fe=>{if(fe.stopPropagation(),!!confirm(`Delete "${t.name}"?`))try{await f2(t.id),r(t.id),c("Deleted","info")}catch{c("Delete failed","error")}},style:{...or,color:"#dc2626",borderColor:"#fca5a5"},children:"🗑"})]}),n.jsx("input",{ref:ve,type:"file",accept:".txt,.csv,.json",style:{display:"none"},onChange:Jt}),n.jsx("span",{style:{fontSize:14,color:"#9ca3af",marginLeft:2},children:d?"▲":"▼"})]}),d&&n.jsxs("div",{children:[n.jsx("div",{style:{display:"flex",borderBottom:"1px solid #e5e7eb",background:"#f9fafb"},children:Nt.map(fe=>n.jsx("button",{onClick:ft=>{ft.stopPropagation(),g(fe.id)},style:{padding:"7px 14px",border:"none",borderBottom:p===fe.id?"2px solid #1e3a5f":"2px solid transparent",background:"none",cursor:"pointer",fontSize:12,fontWeight:p===fe.id?700:400,color:p===fe.id?"#1e3a5f":"#6b7280"},children:fe.label},fe.id))}),n.jsxs("div",{style:{padding:"14px 16px"},onClick:fe=>fe.stopPropagation(),children:[p==="browse"&&n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",gap:8,marginBottom:10,alignItems:"center"},children:[n.jsx("input",{placeholder:"Search tokens…",value:y,onChange:fe=>{b(fe.target.value),v(0)},style:{...hn,flex:1}}),n.jsxs("span",{style:{fontSize:11,color:"#9ca3af",whiteSpace:"nowrap"},children:[Ae.length.toLocaleString()," / ",t.content.length.toLocaleString()]})]}),n.jsx("pre",{style:{background:"#1e293b",color:"#e2e8f0",borderRadius:6,padding:"10px 14px",fontSize:11,overflowX:"auto",maxHeight:220,margin:0,lineHeight:1.8,cursor:"context-menu"},onContextMenu:fe=>Me(fe,[...nk(Oe.join(" "),"Copy page"),{label:"Copy all tokens",icon:"📄",action:()=>navigator.clipboard.writeText(t.content.join(" ")).catch(()=>{})}]),children:Oe.join(" ")}),n.jsx(tk,{menu:De,onClose:Ve}),Ue>1&&n.jsxs("div",{style:{display:"flex",gap:6,marginTop:8,alignItems:"center"},children:[n.jsx("button",{onClick:()=>v(fe=>Math.max(0,fe-1)),disabled:h===0,style:xn,children:"← Prev"}),n.jsxs("span",{style:{fontSize:12,color:"#6b7280"},children:["Page ",h+1," / ",Ue]}),n.jsx("button",{onClick:()=>v(fe=>Math.min(Ue-1,fe+1)),disabled:h>=Ue-1,style:xn,children:"Next →"})]})]}),p==="edit"&&n.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:10,maxWidth:560},children:[n.jsxs("div",{children:[n.jsx("label",{style:$n,children:"Name"}),n.jsx("input",{value:S,onChange:fe=>k(fe.target.value),style:hn})]}),n.jsxs("div",{children:[n.jsx("label",{style:$n,children:"Type"}),n.jsx("select",{value:_,onChange:fe=>T(fe.target.value),style:hn,children:$b.map(fe=>n.jsx("option",{children:fe},fe))})]}),n.jsxs("div",{children:[n.jsx("label",{style:$n,children:"Reading Direction"}),n.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[n.jsx("select",{value:W,onChange:fe=>P(fe.target.value),style:{...hn,flex:1},children:Hb.map(fe=>n.jsx("option",{value:fe.value,children:fe.label},fe.value))}),n.jsx("button",{onClick:it,disabled:z,style:{...Nc,whiteSpace:"nowrap"},title:"Auto-detect reading direction using Ashraf & Sinha (2018) positional entropy method",children:z?"Detecting…":"🔍 Auto-detect"})]}),n.jsx("div",{style:{fontSize:10,color:"#6b7280",marginTop:3},children:"Auto-detect applies the Ashraf & Sinha (2018) positional entropy method. Lower entropy at word-end indicates the reading direction."})]}),n.jsxs("div",{children:[n.jsx("label",{style:$n,children:"Tokenisation mode (for re-parsing)"}),n.jsxs("select",{value:j,onChange:fe=>L(fe.target.value),style:hn,children:[n.jsx("option",{value:"space",children:"Space-separated"}),n.jsx("option",{value:"line",children:"Line-per-token"}),n.jsx("option",{value:"char",children:"Character-level"})]})]}),n.jsxs("div",{children:[n.jsxs("label",{style:$n,children:["Content (",t.content.length.toLocaleString()," tokens)"]}),n.jsx("textarea",{value:w,onChange:fe=>C(fe.target.value),rows:8,style:{...hn,fontFamily:"monospace",resize:"vertical",fontSize:11}})]}),n.jsxs("div",{style:{display:"flex",gap:8},children:[n.jsx("button",{onClick:dt,disabled:q,style:es,children:q?"Saving…":"Save"}),n.jsx("button",{onClick:yt,style:Nc,children:"Copy All"}),n.jsx("button",{onClick:()=>{var fe;return(fe=ve.current)==null?void 0:fe.click()},style:Nc,children:"Import File"})]})]}),p==="stats"&&n.jsxs("div",{children:[I&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"Computing metrics…"}),$&&n.jsxs(n.Fragment,{children:[n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:14},children:[n.jsx(Vs,{label:"H1 (bits)",value:$.h1,color:"#2563eb"}),n.jsx(Vs,{label:"H2/H1",value:$.h2_h1_ratio??"—",color:"#7c3aed"}),n.jsx(Vs,{label:"Cond H",value:$.conditional_h,color:"#d97706"}),n.jsx(Vs,{label:"TTR",value:$.type_token_ratio.toFixed(3),color:"#16a34a"}),n.jsx(Vs,{label:"Zipf ρ",value:$.zipf_correlation.toFixed(3),color:"#6b7280"}),n.jsx(Vs,{label:"Hapax",value:$.hapax_count.toLocaleString()})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsxs("div",{style:sy,children:["Token frequency (top ",Math.min($.zipf_table.length,30),")"]}),n.jsx(oy,{data:$.zipf_table.slice(0,30),xKey:"token",yKey:"freq",height:90})]}),n.jsxs("div",{children:[n.jsx("div",{style:sy,children:"Zipf log-rank vs log-freq"}),n.jsx(ok,{values:$.zipf_table.map(fe=>fe.log_freq),color:"#7c3aed"})]})]}),n.jsx(ak,{tokens:t.content})]}),p==="ngrams"&&n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",gap:6,marginBottom:10,alignItems:"center"},children:[n.jsx("span",{style:{fontSize:12,color:"#374151"},children:"n ="}),[1,2,3,4].map(fe=>n.jsx("button",{onClick:()=>Y(fe),style:{...xn,background:D===fe?"#1e3a5f":"#f3f4f6",color:D===fe?"#fff":"#374151"},children:fe},fe)),n.jsx("button",{onClick:rn,disabled:G,style:es,children:G?"Loading…":"Load"})]}),H&&n.jsxs(n.Fragment,{children:[n.jsx(oy,{data:H.slice(0,30).map(fe=>({k:fe.ngram.slice(0,6),count:fe.count})),xKey:"k",yKey:"count",height:90,color:"#7c3aed"}),n.jsxs("table",{style:{borderCollapse:"collapse",width:"100%",marginTop:10,fontSize:12},children:[n.jsx("thead",{children:n.jsxs("tr",{children:[n.jsx("th",{style:Xs,children:"N-gram"}),n.jsx("th",{style:Xs,children:"Count"})]})}),n.jsx("tbody",{children:H.slice(0,50).map(fe=>n.jsxs("tr",{children:[n.jsx("td",{style:Js,children:n.jsx("code",{children:fe.ngram})}),n.jsx("td",{style:Js,children:fe.count.toLocaleString()})]},fe.ngram))})]})]})]}),p==="concordance"&&n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",gap:8,marginBottom:10},children:[n.jsx("input",{placeholder:"Token (exact match)…",value:X,onChange:fe=>B(fe.target.value),onKeyDown:fe=>{fe.key==="Enter"&&zt()},style:{...hn,flex:1}}),n.jsx("button",{onClick:zt,disabled:N,style:es,children:N?"…":"Search"})]}),V&&n.jsxs("div",{children:[n.jsxs("div",{style:{fontSize:12,color:"#6b7280",marginBottom:8},children:[V.total.toLocaleString()," occurrences of ",n.jsxs("code",{children:['"',V.query,'"']})]}),n.jsx("div",{style:{maxHeight:300,overflowY:"auto"},children:V.hits.slice(0,100).map((fe,ft)=>n.jsxs("div",{style:{display:"flex",gap:4,padding:"3px 0",borderBottom:"1px solid #f3f4f6",fontSize:12,fontFamily:"monospace"},children:[n.jsx("span",{style:{color:"#9ca3af",width:50,flexShrink:0,textAlign:"right",fontSize:10},children:fe.position}),n.jsx("span",{style:{color:"#6b7280"},children:fe.left.join(" ")}),n.jsx("span",{style:{background:"#fef3c7",padding:"0 2px",borderRadius:2,fontWeight:700,color:"#92400e"},children:fe.match}),n.jsx("span",{style:{color:"#6b7280"},children:fe.right.join(" ")})]},ft))})]})]}),p==="ai"&&n.jsx("div",{children:n.jsxs("div",{style:{display:"flex",gap:6,marginBottom:12,flexWrap:"wrap"},children:[["analyze","anomalies","critique"].map(fe=>n.jsx("button",{onClick:()=>se(fe),style:{...xn,background:ne===fe?"#7c3aed":"#f3f4f6",color:ne===fe?"#fff":"#374151"},children:fe==="analyze"?"Corpus Analysis":fe==="anomalies"?"Anomaly Detection":"Critique"},fe)),n.jsx("button",{onClick:He,style:{...es,background:"#7c3aed",marginLeft:"auto"},children:"✨ Ask AI"})]})}),p==="compare"&&n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",gap:8,marginBottom:12,alignItems:"center"},children:[n.jsx("label",{style:{fontSize:12,color:"#374151",whiteSpace:"nowrap"},children:"Compare with:"}),n.jsxs("select",{value:pe,onChange:fe=>_e(fe.target.value),style:{...hn,flex:1},children:[n.jsx("option",{value:"",children:"— select corpus —"}),l.filter(fe=>fe.id!==t.id).map(fe=>n.jsxs("option",{value:fe.id,children:[fe.name," (",fe.corpus_type,")"]},fe.id))]}),n.jsx("button",{onClick:Ze,disabled:!pe||Ce,style:es,children:Ce?"Loading…":"Compare"})]}),te&&we&&(()=>{const fe=l.find(Et=>Et.id===pe),ft=[["H1 (bits)","h1"],["H2/H1","h2_h1_ratio"],["Cond H","conditional_h"],["TTR","type_token_ratio"],["Zipf ρ","zipf_correlation"],["Tokens","token_count"],["Alphabet","type_count"],["Hapax","hapax_count"]];return n.jsxs("table",{style:{borderCollapse:"collapse",width:"100%",fontSize:12},children:[n.jsx("thead",{children:n.jsxs("tr",{children:[n.jsx("th",{style:Xs,children:"Metric"}),n.jsx("th",{style:Xs,children:t.name.slice(0,20)}),n.jsx("th",{style:Xs,children:(fe==null?void 0:fe.name.slice(0,20))??pe}),n.jsx("th",{style:Xs,children:"Δ"})]})}),n.jsx("tbody",{children:ft.map(([Et,qt])=>{const Gt=te[qt]??0,Ct=we[qt]??0,oe=typeof Gt=="number"&&typeof Ct=="number"?Gt-Ct:null,Ne=oe!==null&&Math.abs(oe)>.05*Math.max(Math.abs(Gt),Math.abs(Ct),.001);return n.jsxs("tr",{children:[n.jsx("td",{style:{...Js,fontWeight:600},children:Et}),n.jsx("td",{style:Js,children:typeof Gt=="number"?Number.isInteger(Gt)?Gt.toLocaleString():Gt.toFixed(3):"—"}),n.jsx("td",{style:Js,children:typeof Ct=="number"?Number.isInteger(Ct)?Ct.toLocaleString():Ct.toFixed(3):"—"}),n.jsx("td",{style:{...Js,color:Ne?oe>0?"#16a34a":"#dc2626":"#9ca3af",fontWeight:Ne?700:400},children:oe!==null?(oe>0?"+":"")+oe.toFixed(3):"—"})]},qt)})})]})})()]})]})]})]})}function ck({onCreated:t}){const{toast:o}=et(),[r,l]=x.useState(""),[c,d]=x.useState("linguistic"),[u,p]=x.useState("space"),[g,h]=x.useState("unknown"),[v,y]=x.useState(""),[b,S]=x.useState(!1),k=x.useRef(null),_=C=>u==="char"?C.replace(/\s+/g,"").split(""):u==="line"?C.split(` -`).map(j=>j.trim()).filter(Boolean):C.trim().split(/\s+/).filter(Boolean),T=async()=>{if(!r.trim()||!v.trim()){o("Name and content required","warning");return}const C=_(v);if(!C.length){o("Content cannot be empty","warning");return}S(!0);try{const j=await d2({name:r.trim(),corpus_type:c,content:C,reading_direction:g});t(j),l(""),y(""),h("unknown"),o("Corpus created","success")}catch(j){o(j instanceof Error?j.message:"Upload failed","error")}finally{S(!1)}},w=C=>{var W;const j=(W=C.target.files)==null?void 0:W[0];if(!j)return;r||l(j.name.replace(/\.[^.]+$/,""));const L=new FileReader;L.onload=P=>{var M;const z=(M=P.target)==null?void 0:M.result;if(j.name.endsWith(".json"))try{const q=JSON.parse(z);y(Array.isArray(q)?q.join(" "):(q.content??[]).join(" ")||z)}catch{y(z)}else y(z)},L.readAsText(j),C.target.value=""};return n.jsxs("details",{style:{marginBottom:"1.5rem"},children:[n.jsx("summary",{style:{cursor:"pointer",fontWeight:600,fontSize:13,padding:"8px 0"},children:"+ Upload / import corpus"}),n.jsxs("div",{style:{marginTop:10,padding:"1rem",border:"1px solid #e5e7eb",borderRadius:8,maxWidth:560},children:[n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:$n,children:"Name"}),n.jsx("input",{value:r,onChange:C=>l(C.target.value),placeholder:"e.g. Moby Dick",style:hn})]}),n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:$n,children:"Type"}),n.jsx("select",{value:c,onChange:C=>d(C.target.value),style:hn,children:$b.map(C=>n.jsx("option",{children:C},C))})]}),n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:$n,children:"Reading Direction"}),n.jsx("select",{value:g,onChange:C=>h(C.target.value),style:hn,children:Hb.map(C=>n.jsx("option",{value:C.value,children:C.label},C.value))})]}),n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:$n,children:"Tokenisation"}),n.jsxs("select",{value:u,onChange:C=>p(C.target.value),style:hn,children:[n.jsx("option",{value:"space",children:"Space-separated"}),n.jsx("option",{value:"line",children:"Line-per-token"}),n.jsx("option",{value:"char",children:"Character-level"})]})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsx("label",{style:$n,children:"Paste text content"}),n.jsx("textarea",{value:v,onChange:C=>y(C.target.value),rows:5,style:{...hn,fontFamily:"monospace",resize:"vertical",fontSize:11},placeholder:"Paste text here…"})]}),n.jsxs("div",{style:{display:"flex",gap:8},children:[n.jsx("button",{onClick:T,disabled:b,style:es,children:b?"Uploading…":"Upload"}),n.jsx("button",{onClick:()=>{var C;return(C=k.current)==null?void 0:C.click()},style:Nc,children:"↑ Import File (.txt/.csv/.json)"}),n.jsx("input",{ref:k,type:"file",accept:".txt,.csv,.json",style:{display:"none"},onChange:w})]})]})]})}function dk({onImported:t}){const{toast:o}=et(),[r,l]=x.useState([]),[c,d]=x.useState(!1),[u,p]=x.useState(null),[g,h]=x.useState(""),[v,y]=x.useState("all"),[b,S]=x.useState("all"),[k,_]=x.useState("all"),T=async()=>{d(!0);try{l(await tj())}catch(q){o(q instanceof Error?q.message:"Failed to load catalogue","error")}finally{d(!1)}},w=async q=>{var K;if(!q.local_module){o(`No bundled module for '${q.name}'. Download from the source URL and upload manually via + Upload / import corpus.`,"warning");return}p(q.id);try{const D=await nj(q.id);D.imported?(l(Y=>Y.map(H=>H.id===q.id?{...H,already_imported:!0}:H)),o(`Imported '${D.name}' (${(K=D.tokens)==null?void 0:K.toLocaleString()} tokens)`,"success"),t()):o(`'${D.name}' already in your corpora`,"info")}catch(D){o(D instanceof Error?D.message:"Import failed","error")}finally{p(null)}},C=Array.from(new Set(r.map(q=>q.script_type).filter(Boolean))).sort(),j=r.filter(q=>{const K=!g||q.name.toLowerCase().includes(g.toLowerCase())||q.language.toLowerCase().includes(g.toLowerCase())||q.language_family.toLowerCase().includes(g.toLowerCase()),D=v==="all"||(v==="undeciphered"?!!q.is_undeciphered:!q.is_undeciphered),Y=b==="all"||q.script_type===b,H=k==="all"||(k==="bundled"?!!q.local_module:!q.local_module);return K&&D&&Y&&H}),L={};for(const q of j){const K=q.language_family||"Other";(L[K]=L[K]||[]).push(q)}const W={abjad:"#7c3aed",syllabary:"#059669",logosyllabic:"#d97706",logographic:"#dc2626",alphabet:"#2563eb",unknown:"#6b7280"},P={abjad:"Abjad",syllabary:"Syllabary",logosyllabic:"Logo-syllabic",logographic:"Logographic",alphabet:"Alphabet",unknown:"Unknown"},z={ltr:{label:"LTR",color:"#065f46",bg:"#d1fae5",title:"Left to Right"},rtl:{label:"RTL",color:"#7c2d12",bg:"#fee2e2",title:"Right to Left"},bidi:{label:"BIDI",color:"#5b21b6",bg:"#ede9fe",title:"Boustrophedon (alternating)"},unknown:{label:"?",color:"#6b7280",bg:"#f3f4f6",title:"Reading direction unknown"}},M=q=>q>0?`~${q>=1e3?`${(q/1e3).toFixed(q>=1e4?0:1)}K`:q.toString()} tokens`:"—";return n.jsxs("details",{style:{marginBottom:"1.5rem"},children:[n.jsx("summary",{style:{cursor:"pointer",fontWeight:600,fontSize:13,padding:"8px 0",color:"#059669"},onClick:()=>r.length===0&&void T(),children:"🌍 Browse World Language Corpus Catalogue"}),n.jsxs("div",{style:{marginTop:10,padding:"1rem",border:"1px solid #d1fae5",borderRadius:8,background:"#f0fdf4"},children:[n.jsxs("div",{style:{display:"flex",gap:6,marginBottom:6,flexWrap:"wrap",alignItems:"center"},children:[n.jsx("input",{placeholder:"Search name, language, family…",value:g,onChange:q=>h(q.target.value),style:{...hn,width:220}}),["all","undeciphered","deciphered"].map(q=>n.jsx("button",{onClick:()=>y(q),style:{...xn,background:v===q?"#059669":void 0,color:v===q?"#fff":void 0},children:q==="all"?"All":q==="undeciphered"?"🔓 Undeciphered":"✓ Deciphered"},q)),n.jsx("div",{style:{display:"flex",gap:4},children:["all","bundled","manual"].map(q=>n.jsx("button",{onClick:()=>_(q),style:{...xn,background:k===q?"#2563eb":void 0,color:k===q?"#fff":void 0},title:q==="bundled"?"One-click import available":q==="manual"?"Manual upload required":"All",children:q==="all"?"⬇ Any":q==="bundled"?"⬇ 1-click":"✎ Manual"},q))}),n.jsx("button",{onClick:()=>void T(),style:xn,title:"Reload catalogue",children:"⟳"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280",marginLeft:"auto"},children:[j.length," entries"]})]}),C.length>0&&n.jsxs("div",{style:{display:"flex",gap:4,marginBottom:10,flexWrap:"wrap"},children:[n.jsx("button",{onClick:()=>S("all"),style:{...xn,padding:"2px 8px",background:b==="all"?"#374151":void 0,color:b==="all"?"#fff":void 0,fontSize:10},children:"All types"}),C.map(q=>{const K=W[q]??"#6b7280";return n.jsx("button",{onClick:()=>S(b===q?"all":q),style:{...xn,padding:"2px 8px",fontSize:10,background:b===q?K:K+"15",color:b===q?"#fff":K,border:`1px solid ${K}40`,fontWeight:b===q?700:400},children:P[q]??q},q)})]}),c&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"Loading catalogue…"}),Object.entries(L).sort(([q],[K])=>q.localeCompare(K)).map(([q,K])=>n.jsxs("div",{style:{marginBottom:10},children:[n.jsxs("div",{style:{fontSize:10,fontWeight:700,color:"#374151",textTransform:"uppercase",letterSpacing:.5,marginBottom:3,paddingBottom:2,borderBottom:"1px solid #d1fae5"},children:[q," ",n.jsxs("span",{style:{fontWeight:400,opacity:.6},children:["(",K.length,")"]})]}),K.map(D=>{const Y=W[D.script_type]??"#6b7280",H=!!D.local_module,A=M(D.tokens_approx);return n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"5px 0",borderBottom:"1px solid #ecfdf5"},children:[n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:5,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontWeight:600,fontSize:12,color:D.is_undeciphered?"#7c2d12":"#1e3a5f"},children:D.name}),n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:Y+"18",color:Y,fontWeight:700},children:P[D.script_type]??D.script_type}),(()=>{const G=D.reading_direction??"unknown",R=z[G]??z.unknown;return n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:R.bg,color:R.color,fontWeight:700,letterSpacing:.2},title:R.title,children:R.label})})(),D.is_undeciphered&&n.jsx("span",{style:{fontSize:9,color:"#dc2626",fontWeight:700},children:"🔓"}),H&&!D.already_imported&&n.jsx("span",{style:{fontSize:9,color:"#059669",fontWeight:600},children:"⬇ bundled"})]}),n.jsxs("div",{style:{fontSize:10,color:"#6b7280",marginTop:1},children:[D.language," · ",D.period," · ",A," · ",D.license]})]}),n.jsx("div",{style:{display:"flex",gap:4,flexShrink:0},children:D.already_imported?n.jsx("span",{style:{fontSize:10,color:"#059669",fontWeight:700},children:"✓ Imported"}):H?n.jsx("button",{onClick:()=>void w(D),disabled:u===D.id,style:{...xn,background:u===D.id?"#d1d5db":"#059669",color:"#fff",border:"none",fontSize:10},children:u===D.id?"⏳":"↓ Import"}):n.jsx("a",{href:D.source_url,target:"_blank",rel:"noopener noreferrer",style:{...xn,textDecoration:"none",fontSize:10,color:"#374151"},title:`Source: ${D.source_url}`,children:"Source ↗"})})]},D.id)})]},q)),!c&&j.length===0&&r.length>0&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"No entries match your filters."}),!c&&r.length===0&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"Click ⟳ to load the catalogue."})]})]})}function uk(){const{toast:t}=et(),[o,r]=x.useState([]),[l,c]=x.useState(!1),[d,u]=x.useState(!1),[p,g]=x.useState(""),[h,v]=x.useState(""),[y,b]=x.useState(""),S=async()=>{c(!0);try{r(await Q2())}catch(w){t(w instanceof Error?w.message:"Failed to load","error")}finally{c(!1)}},k=w=>w.split(` -`).map(C=>C.trim()).filter(Boolean).map(C=>{const[j,L,W,...P]=C.split(/\s+|\t/);return{cipher:j??"",target:L??"",confidence:W??"high",note:P.join(" ")}}).filter(C=>C.cipher&&C.target),_=async()=>{if(!p.trim()){t("Name required","warning");return}try{const w=await Z2({name:p.trim(),language:h.trim(),pairs:k(y)});r(C=>[w,...C]),u(!1),g(""),v(""),b(""),t("Anchor set created","success")}catch(w){t(w instanceof Error?w.message:"Create failed","error")}},T=async w=>{if(confirm("Delete this anchor set?"))try{await ej(w),r(C=>C.filter(j=>j.id!==w))}catch(C){t(C instanceof Error?C.message:"Delete failed","error")}};return x.useEffect(()=>{S()},[]),n.jsxs("details",{style:{marginBottom:"1.5rem"},children:[n.jsxs("summary",{style:{cursor:"pointer",fontWeight:600,fontSize:13,padding:"8px 0",color:"#7c3aed"},children:["⚓ Anchor Sets (",o.length,")"]}),n.jsxs("div",{style:{marginTop:10,padding:"1rem",border:"1px solid #ede9fe",borderRadius:8,background:"#faf5ff"},children:[n.jsxs("div",{style:{display:"flex",gap:8,marginBottom:10},children:[n.jsx("button",{onClick:()=>u(w=>!w),style:{...xn,background:"#7c3aed",color:"#fff",border:"none"},children:"+ New Set"}),n.jsx("button",{onClick:()=>void S(),style:xn,children:"⟳ Refresh"})]}),d&&n.jsxs("div",{style:{padding:12,border:"1px solid #a78bfa",borderRadius:6,marginBottom:12,background:"#fff"},children:[n.jsxs("div",{style:{display:"flex",gap:8,marginBottom:8},children:[n.jsxs("div",{style:{flex:2},children:[n.jsx("label",{style:$n,children:"Set Name"}),n.jsx("input",{value:p,onChange:w=>g(w.target.value),placeholder:"e.g. Fuls Ugaritic Anchors",style:hn})]}),n.jsxs("div",{style:{flex:1},children:[n.jsx("label",{style:$n,children:"Language (optional)"}),n.jsx("input",{value:h,onChange:w=>v(w.target.value),placeholder:"e.g. Ugaritic",style:hn})]})]}),n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:$n,children:"Anchor Pairs (one per line: cipher target confidence note)"}),n.jsx("textarea",{value:y,onChange:w=>b(w.target.value),rows:5,style:{...hn,fontFamily:"monospace",fontSize:11,resize:"vertical"},placeholder:`004 T high Fuls verified -066 m high Fuls verified -208 n high Fuls verified`}),n.jsx("div",{style:{fontSize:10,color:"#6b7280",marginTop:2},children:"Format: cipher_sign target confidence(high/medium/low) note"})]}),n.jsxs("div",{style:{display:"flex",gap:8},children:[n.jsx("button",{onClick:()=>void _(),style:{...xn,background:"#7c3aed",color:"#fff",border:"none"},children:"Create"}),n.jsx("button",{onClick:()=>u(!1),style:xn,children:"Cancel"})]})]}),l&&n.jsx("p",{style:{fontSize:13,color:"#6b7280"},children:"Loading…"}),o.length===0&&!l&&n.jsx("p",{style:{fontSize:13,color:"#6b7280"},children:"No anchor sets yet. Create one above."}),o.map(w=>n.jsxs("div",{style:{border:"1px solid #ede9fe",borderRadius:6,padding:"8px 12px",marginBottom:6,background:"#fff"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[n.jsxs("div",{style:{flex:1},children:[n.jsx("span",{style:{fontWeight:600,fontSize:12},children:w.name}),w.language&&n.jsx("span",{style:{fontSize:11,color:"#7c3aed",marginLeft:6},children:w.language}),n.jsxs("span",{style:{fontSize:11,color:"#9ca3af",marginLeft:6},children:[w.pairs.length," pairs"]})]}),n.jsx("button",{onClick:()=>T(w.id),style:{...or,color:"#dc2626",borderColor:"#fca5a5"},children:"Delete"})]}),w.pairs.length>0&&n.jsxs("div",{style:{marginTop:4,display:"flex",gap:4,flexWrap:"wrap"},children:[w.pairs.slice(0,8).map((C,j)=>n.jsxs("span",{style:{fontSize:10,padding:"1px 5px",borderRadius:4,background:C.confidence==="high"?"#d1fae5":C.confidence==="medium"?"#fef3c7":"#fee2e2",color:"#374151"},children:[C.cipher,"→",C.target]},j)),w.pairs.length>8&&n.jsxs("span",{style:{fontSize:10,color:"#9ca3af"},children:["+",w.pairs.length-8," more"]})]})]},w.id))]})]})}function fk({onSelect:t}){const[o,r]=x.useState([]),[l,c]=x.useState(!0),[d,u]=x.useState(null),p=async()=>{c(!0);try{r(await rd()),u(null)}catch(g){u(g instanceof Error?g.message:"Failed to load")}finally{c(!1)}};return x.useEffect(()=>{p()},[]),n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"0.75rem"},children:[n.jsx("h2",{style:{margin:0},children:"Corpora"}),n.jsx("button",{onClick:p,style:{...es,background:"#6b7280",padding:"4px 12px",fontSize:12},children:"⟳ Refresh"})]}),n.jsx(ck,{onCreated:g=>r(h=>[g,...h])}),n.jsx(dk,{onImported:()=>void p()}),n.jsx(uk,{}),l&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"Loading…"}),d&&n.jsx("p",{style:{color:"#dc2626",fontSize:13},children:d}),!l&&!d&&o.length===0&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"No corpora yet. Upload or import one above."}),!l&&o.length>0&&n.jsxs("div",{children:[n.jsxs("div",{style:{fontSize:12,color:"#9ca3af",marginBottom:8},children:[o.length," corpus entries — click any row to expand"]}),o.map(g=>n.jsx(lk,{text:g,allTexts:o,onUpdated:h=>r(v=>v.map(y=>y.id===h.id?h:y)),onDeleted:h=>r(v=>v.filter(y=>y.id!==h))},g.id))]}),t&&o.length>0&&n.jsxs("div",{style:{marginTop:12},children:[n.jsx("div",{style:{fontSize:12,color:"#6b7280",marginBottom:6},children:"Quick-select:"}),n.jsx("div",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:o.map(g=>n.jsx("button",{onClick:()=>t(g.id,g.name),style:xn,children:g.name},g.id))})]})]})}const sy={fontSize:10,fontWeight:700,color:"#7c3aed",textTransform:"uppercase",letterSpacing:.5,marginBottom:4},hn={width:"100%",padding:"5px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:13,boxSizing:"border-box",display:"block"},$n={display:"block",fontWeight:600,fontSize:12,color:"#374151",marginBottom:3},es={background:"#2563eb",color:"#fff",border:"none",borderRadius:4,padding:"6px 14px",fontSize:12,cursor:"pointer",fontWeight:600,whiteSpace:"nowrap"},Nc={background:"#fff",color:"#374151",border:"1px solid #d1d5db",borderRadius:4,padding:"6px 14px",fontSize:12,cursor:"pointer",whiteSpace:"nowrap"},xn={padding:"3px 10px",border:"1px solid #e5e7eb",borderRadius:4,cursor:"pointer",fontSize:11,background:"#f9fafb",color:"#374151"},or={padding:"2px 7px",border:"1px solid #e5e7eb",borderRadius:4,cursor:"pointer",fontSize:10,background:"#f9fafb",color:"#374151"},Xs={textAlign:"left",padding:"4px 10px 4px 0",borderBottom:"2px solid #e5e7eb",color:"#374151"},Js={padding:"3px 10px 3px 0",borderBottom:"1px solid #f3f4f6",verticalAlign:"top"};function pk(t){const o=typeof t=="string"?new Date(t):t;return isNaN(o.getTime())?String(t):o.toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit",timeZoneName:"short"})}function Fc(t){const o=typeof t=="string"?new Date(t):t;if(isNaN(o.getTime()))return String(t);const r=new Date,l=o.getFullYear()===r.getFullYear();return o.toLocaleString(void 0,{month:"short",day:"numeric",...l?{}:{year:"numeric"},hour:"numeric",minute:"2-digit"})}function za(t){const o=Math.max(0,Math.round(t)),r=Math.floor(o/3600),l=Math.floor(o%3600/60),c=o%60;return`${String(r).padStart(2,"0")}:${String(l).padStart(2,"0")}:${String(c).padStart(2,"0")}`}const hk=new Set(["node_count","nodes_done","stall_reason"]);function gk(t){return Object.fromEntries(Object.entries(t).filter(([o])=>!o.startsWith("_")&&!hk.has(o)))}function mk(t){return t.replace(/_/g," ").replace(/\b\w/g,o=>o.toUpperCase())}function xk(t){return t==null?"—":typeof t=="boolean"?t?"Yes":"No":typeof t=="object"?JSON.stringify(t):String(t)}function yk(t){if(!t)return null;try{const o=JSON.parse(t);return typeof o=="object"&&o!==null?o:null}catch{return null}}function bk(t){const o=t.toLowerCase();return o.includes("no module")||o.includes("import")||o.includes("attribute")?{label:"Code / Import Error",color:"#7c3aed"}:o.includes("timeout")||o.includes("unreachable")||o.includes("network")?{label:"Network / Timeout",color:"#d97706"}:o.includes("database")||o.includes("sqlite")||o.includes("sql")?{label:"Database Error",color:"#0369a1"}:o.includes("key")||o.includes("auth")||o.includes("permission")?{label:"Auth / Permission",color:"#b45309"}:o.includes("assertion")||o.includes("assert")?{label:"Assertion Failed",color:"#9f1239"}:{label:"Experiment Error",color:"#991b1b"}}function Wb({title:t,message:o,detail:r,params:l,job:c,onRetry:d,onClose:u}){const p=`${t} -${o}${r?` -`+r:""}`,[g,h]=x.useState(!1),[v,y]=x.useState(!1),b=()=>{navigator.clipboard.writeText(p).then(()=>{h(!0),setTimeout(()=>h(!1),1500)})},S=yk(o),k=S?S.error??S.message??JSON.stringify(S,null,2):o,_=bk(k||""),T=r??null;return n.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.55)",zIndex:12e3,display:"flex",alignItems:"center",justifyContent:"center",padding:20},onClick:u,children:n.jsxs("div",{style:{background:"#fff",borderRadius:12,maxWidth:720,width:"100%",maxHeight:"85vh",display:"flex",flexDirection:"column",boxShadow:"0 24px 64px rgba(0,0,0,0.4)"},onClick:w=>w.stopPropagation(),children:[n.jsxs("div",{style:{padding:"16px 20px",borderBottom:"1px solid #fee2e2",background:"#fef2f2",borderRadius:"12px 12px 0 0",display:"flex",alignItems:"center",gap:10},children:[n.jsx("span",{style:{fontSize:22},children:"⚠️"}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsx("div",{style:{fontWeight:700,fontSize:14,color:"#991b1b",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},title:t,children:t}),n.jsx("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:8,background:_.color+"20",color:_.color,fontWeight:600},children:_.label})]}),n.jsx("button",{onClick:b,style:{padding:"4px 10px",border:"1px solid #fca5a5",borderRadius:5,background:g?"#fee2e2":"#fff",cursor:"pointer",fontSize:11,color:g?"#16a34a":"#dc2626"},children:g?"✓ Copied":"📋 Copy"}),n.jsx("button",{onClick:u,style:{border:"none",background:"none",cursor:"pointer",fontSize:22,color:"#9ca3af",lineHeight:1,padding:"0 4px"},children:"×"})]}),n.jsxs("div",{style:{flex:1,overflowY:"auto"},children:[n.jsxs("div",{style:{padding:"14px 20px",borderBottom:"1px solid #f3f4f6"},children:[n.jsx("div",{style:{fontSize:12,fontWeight:600,color:"#374151",marginBottom:6,textTransform:"uppercase",letterSpacing:"0.05em"},children:"What went wrong"}),n.jsx("div",{style:{fontSize:13,color:"#111827",lineHeight:1.7,background:"#fef2f2",padding:"10px 14px",borderRadius:7,border:"1px solid #fecaca",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:k||"No error message available."})]}),l&&Object.keys(l).filter(w=>!w.startsWith("_")).length>0&&n.jsxs("div",{style:{padding:"12px 20px",borderBottom:"1px solid #f3f4f6"},children:[n.jsx("div",{style:{fontSize:12,fontWeight:600,color:"#374151",marginBottom:8,textTransform:"uppercase",letterSpacing:"0.05em"},children:"Job parameters"}),n.jsx("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:n.jsx("tbody",{children:Object.entries(l).filter(([w])=>!w.startsWith("_")&&w!=="traceback").map(([w,C])=>n.jsxs("tr",{style:{borderBottom:"1px solid #f3f4f6"},children:[n.jsx("td",{style:{padding:"4px 10px 4px 0",color:"#6b7280",fontWeight:500,whiteSpace:"nowrap",verticalAlign:"top",width:"35%"},children:mk(w)}),n.jsx("td",{style:{padding:"4px 0",color:"#111827",wordBreak:"break-all",fontFamily:typeof C=="string"?"inherit":"monospace"},children:xk(C)})]},w))})})]}),T&&n.jsxs("div",{style:{padding:"12px 20px"},children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:6},children:[n.jsx("div",{style:{fontSize:12,fontWeight:600,color:"#374151",textTransform:"uppercase",letterSpacing:"0.05em"},children:"Stack trace"}),n.jsx("button",{onClick:()=>y(!v),style:{fontSize:11,border:"1px solid #e5e7eb",background:"#f9fafb",borderRadius:4,cursor:"pointer",padding:"2px 8px",color:"#6b7280"},children:v?"Hide":"Show"})]}),v&&n.jsx("pre",{style:{fontFamily:"monospace",fontSize:11,color:"#374151",background:"#f8fafc",padding:"10px 14px",borderRadius:7,border:"1px solid #e5e7eb",lineHeight:1.6,whiteSpace:"pre-wrap",wordBreak:"break-word",margin:0,maxHeight:260,overflowY:"auto"},children:T})]})]}),n.jsxs("div",{style:{padding:"12px 20px",borderTop:"1px solid #f3f4f6",display:"flex",justifyContent:"space-between",alignItems:"center",gap:8},children:[c&&n.jsxs("div",{style:{fontSize:10,color:"#9ca3af",fontFamily:"monospace"},children:["Job ID: ",c.id.slice(0,12),"… · ",c.pipeline]}),n.jsxs("div",{style:{display:"flex",gap:8,marginLeft:"auto"},children:[d&&n.jsx("button",{onClick:()=>{d(),u()},style:{padding:"6px 16px",border:"none",borderRadius:6,background:"#2563eb",color:"#fff",cursor:"pointer",fontSize:13,fontWeight:600},title:"Re-submit this job with the same parameters",children:"↻ Retry"}),n.jsx("button",{onClick:u,style:{padding:"6px 18px",border:"1px solid #d1d5db",borderRadius:6,background:"#fff",cursor:"pointer",fontSize:13},children:"Close"})]})]})]})})}function vk(){const[t,o]=x.useState([]),[r,l]=x.useState(!0),[c,d]=x.useState(!1),[u,p]=x.useState(null),[g,h]=x.useState(null),[v,y]=x.useState([]),[b,S]=x.useState(!1),[k,_]=x.useState(new Set),T=x.useRef(new Map),[w,C]=x.useState(""),[j,L]=x.useState("block_entropy"),[W,P]=x.useState('{"text_id": ""}'),[z,M]=x.useState(!1),[q,K]=x.useState(null),[D,Y]=x.useState(null),H=x.useCallback(async(I=!1)=>{I&&d(!0);try{const J=await Ba();o(J.sort((ne,se)=>se.created_at.localeCompare(ne.created_at))),p(new Date),h(null)}catch(J){h(J instanceof Error?J.message:"Failed to load jobs")}finally{l(!1),I&&d(!1)}},[]);x.useEffect(()=>{H();const I=setInterval(H,3e3);return yb().then(y).catch(()=>{}),()=>clearInterval(I)},[H]);const A=x.useCallback(I=>async()=>{try{await Gc({name:`${I.name} (retry)`,pipeline:I.pipeline,params:gk(I.params??{})}),await H()}catch(J){alert(J instanceof Error?J.message:"Retry failed")}},[H]),G=async()=>{if(confirm("Delete all jobs and results?")){S(!0);try{await pp(),await H()}finally{S(!1)}}},R=async()=>{if(!w.trim()){K("Job name is required");return}let I;try{I=JSON.parse(W)}catch{K("Params must be valid JSON");return}try{M(!0),K(null),await Gc({name:w.trim(),pipeline:j,params:I}),C(""),await H()}catch(J){K(J instanceof Error?J.message:"Submit failed")}finally{M(!1)}},X=async I=>{var pe,_e;const J=((pe=I.params)==null?void 0:pe.exp_id)??"",ne=((_e=I.params)==null?void 0:_e.result_file)??"",se=J?`${J}.json`:ne;if(I.status==="failed"){const we={};for(const[ke,te]of Object.entries(I.params??{}))!ke.startsWith("_")&&ke!=="traceback"&&(we[ke]=te);try{const te=await xb(I.id),de=te.error??te.message??te.detail??JSON.stringify(te).slice(0,300),Ce=te.traceback??null;Y({title:I.name,message:de||"Unknown error — see stack trace below.",detail:Ce??void 0,params:Object.keys(we).length?we:null,job:I,onRetry:A(I)})}catch{Y({title:I.name,message:"Job failed — no error details stored in the database.",detail:void 0,params:Object.keys(we).length?we:null,job:I,onRetry:A(I)})}return}window.dispatchEvent(new CustomEvent("glossa:navigate",{detail:{view:"reports"}})),se&&setTimeout(()=>{window.dispatchEvent(new CustomEvent("glossa:reports_highlight",{detail:{tab:"data",search:se}}))},120)},B=async I=>{try{await fp(I),await H()}catch(J){alert(J instanceof Error?J.message:"Cancel failed")}},V=async I=>{_(J=>new Set([...J,I]));try{await pb(I),await H()}catch(J){alert(J instanceof Error?J.message:"Pause failed")}finally{_(J=>{const ne=new Set(J);return ne.delete(I),ne})}},Q=async I=>{_(J=>new Set([...J,I]));try{await hb(I),await H()}catch(J){alert(J instanceof Error?J.message:"Resume failed")}finally{_(J=>{const ne=new Set(J);return ne.delete(I),ne})}},N=async()=>{try{await gb(),await H()}catch(I){alert(I instanceof Error?I.message:"Pause all failed")}},O=async()=>{try{await mb(),await H()}catch(I){alert(I instanceof Error?I.message:"Resume all failed")}},$=I=>I==="completed"?"#16a34a":I==="failed"?"#dc2626":I==="running"?"#2563eb":I==="pending"?"#d97706":I==="paused"?"#92400e":"#6b7280",F=I=>I==="completed"?"#dcfce7":I==="failed"?"#fee2e2":I==="running"?"#dbeafe":I==="pending"||I==="paused"?"#fef3c7":"#f3f4f6";return n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:4},children:[n.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:10},children:[n.jsx("h2",{style:{margin:0},children:"Jobs"}),u&&n.jsxs("span",{style:{fontSize:11,color:"#9ca3af"},children:["updated ",pk(u)]})]}),n.jsxs("div",{style:{display:"flex",gap:6},children:[n.jsx("button",{onClick:()=>H(!0),disabled:c,style:{...bi,background:"#f3f4f6",color:"#374151",fontSize:12,padding:"4px 12px"},title:"Manually refresh the job list",children:c?"Refreshing…":"⟳ Refresh"}),n.jsx("button",{onClick:N,disabled:t.filter(I=>I.status==="pending"||I.status==="running").length===0,style:{...bi,background:"#d97706",fontSize:12,padding:"4px 12px"},title:"Pause all pending and running jobs",children:"⏸ Pause All"}),n.jsx("button",{onClick:O,disabled:t.filter(I=>I.status==="paused").length===0,style:{...bi,background:"#059669",fontSize:12,padding:"4px 12px"},title:"Resume all paused jobs",children:"▶ Resume All"}),n.jsx("button",{onClick:G,disabled:b||t.length===0,style:{...bi,background:"#6b7280",fontSize:12,padding:"4px 12px"},children:b?"Clearing…":"Delete All"})]})]}),n.jsxs("details",{style:{marginBottom:"1.5rem"},children:[n.jsx("summary",{style:{cursor:"pointer",fontWeight:600},children:"+ Submit new job"}),n.jsxs("div",{style:{marginTop:"0.75rem",padding:"1rem",border:"1px solid #e5e7eb",borderRadius:6,maxWidth:560},children:[n.jsx(Of,{label:"Job name",children:n.jsx("input",{value:w,onChange:I=>C(I.target.value),placeholder:"e.g. Entropy analysis — English",style:If})}),n.jsx(Of,{label:"Pipeline",children:n.jsx("select",{value:j,onChange:I=>{L(I.target.value);const J=v.find(ne=>ne.id===I.target.value);P(J?JSON.stringify(J.default_params,null,2):'{"text_id": ""}')},style:If,children:(v.length>0?v.map(I=>I.id):[j]).map(I=>n.jsx("option",{value:I,children:I},I))})}),n.jsx(Of,{label:"Parameters (JSON)",children:n.jsx("textarea",{value:W,onChange:I=>P(I.target.value),rows:4,style:{...If,fontFamily:"monospace",resize:"vertical"}})}),q&&n.jsx("p",{style:{color:"#dc2626",margin:"4px 0"},children:q}),n.jsx("button",{onClick:R,disabled:z,style:bi,children:z?"Submitting…":"Submit"})]})]}),r&&n.jsx("p",{children:"Loading…"}),g&&n.jsx("p",{style:{color:"#dc2626"},children:g}),!r&&t.length===0&&n.jsxs("div",{style:{padding:"1.25rem 1.5rem",background:"#f8fafc",border:"1px solid #e2e8f0",borderRadius:8,maxWidth:560},children:[n.jsx("p",{style:{margin:"0 0 8px",fontWeight:600,color:"#374151",fontSize:13},children:"No pipeline jobs yet"}),n.jsxs("p",{style:{margin:"0 0 6px",fontSize:12,color:"#6b7280",lineHeight:1.6},children:["This tab tracks analysis pipelines submitted through the",n.jsx("strong",{children:" Submit new job"})," panel above. Pipeline jobs run corpus analysis (block entropy, NWSP, hypothesis engine, etc.) on corpora you upload to the Corpora tab."]}),n.jsxs("p",{style:{margin:0,fontSize:12,color:"#6b7280",lineHeight:1.6},children:[n.jsx("strong",{children:"Note:"})," background scripts like OCR run separately and do not appear here — check the ",n.jsx("strong",{children:"Experiments"})," tab to run or stream those."]})]}),t.length>0&&n.jsxs("table",{style:{borderCollapse:"collapse",width:"100%"},children:[n.jsx("thead",{children:n.jsx("tr",{children:["Name","Pipeline","Device","Status","Created","Actions"].map(I=>n.jsx(Sk,{children:I},I))})}),n.jsx("tbody",{children:t.map(I=>{var Oe,dt,it,lt,Je,yt,Jt;const J=((Oe=I.params)==null?void 0:Oe.compute_device)??"",ne=((dt=I.params)==null?void 0:dt.compute_device_label)??"",se=J==="gpu",pe=((it=I.params)==null?void 0:it.source)==="cli",_e=((lt=I.params)==null?void 0:lt.source)==="ai_action",we=J?{bg:se?"#dbeafe":"#f3f4f6",color:se?"#1e40af":"#374151",text:se?`⚡ ${ne||"GPU"}`:`⚙️ ${ne||"CPU"}`}:null,ke=((Je=I.params)==null?void 0:Je.node_count)??0,te=((yt=I.params)==null?void 0:yt.nodes_done)??0,de=ke>0?Math.round(te/ke*100):null,Ce=I.pipeline==="exp_run",ze=((Jt=I.params)==null?void 0:Jt.resource_wait)??null,ve=I.status==="running"?Math.round((Date.now()-new Date(I.created_at).getTime())/1e3):null,De=(()=>{const rn=t.filter(ae=>ae.status==="completed"&&ae.pipeline===I.pipeline&&ae.id!==I.id&&ae.updated_at);if(rn.length===0)return null;const zt=rn.map(ae=>(new Date(ae.updated_at).getTime()-new Date(ae.created_at).getTime())/1e3).filter(ae=>ae>0);return zt.length>0?zt.reduce((ae,He)=>ae+He,0)/zt.length:null})(),Me=ve!==null&&de!==null?de>=15?Math.round(ve/de*(100-de)):De!==null?Math.max(0,Math.round(De-ve)):null:null,Ve=Date.now(),Le=T.current.get(I.id);(!Le||Le.done!==te)&&T.current.set(I.id,{done:te,since:Ve});const Ae=Le&&Le.done===te?Ve-Le.since:0,Ue=Ce&&I.status==="running"&&ke>0&&Ae>18e4&&Me!==null&&ve!==null&&Me>ve*1.5?`node ${te+1}/${ke} computing…`:null;return n.jsxs("tr",{children:[n.jsxs(Ks,{children:[n.jsx("div",{style:{fontWeight:500},children:I.name}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",fontFamily:"monospace"},children:[I.id.slice(0,8),"…"]}),I.status==="pending"&&ze&&n.jsxs("div",{style:{marginTop:4,fontSize:10,color:"#92400e",background:"#fef3c7",border:"1px solid #fcd34d",borderRadius:4,padding:"2px 7px",display:"flex",alignItems:"center",gap:4},children:[n.jsx("span",{children:"⏳"}),n.jsx("span",{children:ze})]}),I.status==="running"&&Ce&&ke>0&&n.jsxs("div",{style:{marginTop:4,display:"flex",alignItems:"center",gap:6},children:[n.jsx("div",{style:{flex:1,height:4,background:"#e5e7eb",borderRadius:2,overflow:"hidden"},children:n.jsx("div",{style:{height:"100%",width:`${de??0}%`,background:"#2563eb",borderRadius:2,transition:"width 0.5s"}})}),n.jsxs("span",{style:{fontSize:10,color:"#6b7280",whiteSpace:"nowrap"},children:[te,"/",ke," nodes",de!==null?` (${de}%)`:"",ve!==null&&` · ${za(ve)}`,Ue?` · ${Ue}`:Me!==null?` · ~${za(Me)} left`:""]})]})]}),n.jsx(Ks,{children:n.jsx("code",{style:{fontSize:12},children:I.pipeline})}),n.jsx(Ks,{children:n.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:3},children:[we&&n.jsx("span",{style:{fontSize:11,padding:"2px 7px",borderRadius:6,background:we.bg,color:we.color,fontWeight:600,whiteSpace:"nowrap"},children:we.text}),pe&&n.jsx("span",{style:{fontSize:11,padding:"2px 7px",borderRadius:6,background:"#f0fdf4",color:"#15803d",fontWeight:600,whiteSpace:"nowrap"},title:"Run from CLI (terminal/script)",children:"💻 CLI"}),_e&&n.jsx("span",{style:{fontSize:11,padding:"2px 7px",borderRadius:6,background:"#fdf4ff",color:"#7e22ce",fontWeight:600,whiteSpace:"nowrap"},title:"Triggered by AI assistant",children:"✨ AI"}),!we&&!pe&&!_e&&n.jsx("span",{style:{fontSize:11,color:"#9ca3af"},children:"—"})]})}),n.jsxs(Ks,{children:[n.jsx("span",{style:{display:"inline-block",padding:"1px 7px",borderRadius:10,background:F(I.status),color:$(I.status),fontWeight:700,fontSize:11},children:I.status}),I.status==="running"&&ve!==null&&!Ce&&n.jsxs("div",{style:{fontSize:10,color:"#9ca3af"},children:[za(ve??0)," elapsed"]})]}),n.jsx(Ks,{children:Fc(I.created_at)}),n.jsx(Ks,{children:n.jsxs("span",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:[I.status==="completed"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#059669"},onClick:()=>X(I),title:"Open result in Reports → Data tab",children:"📂 View in Reports"}),I.status==="failed"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#dc2626"},onClick:()=>X(I),title:"View error details",children:"⚠ Error Details"}),I.status==="cancelled"&&n.jsx("span",{style:{fontSize:11,color:"#6b7280",fontStyle:"italic"},children:"cancelled"}),(I.status==="pending"||I.status==="running")&&n.jsxs(n.Fragment,{children:[n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#d97706"},onClick:()=>V(I.id),disabled:k.has(I.id),title:"Pause this job",children:k.has(I.id)?"…":"⏸ Pause"}),n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:I.status==="running"?"#ea580c":"#6b7280"},onClick:()=>B(I.id),title:I.status==="running"?"Abort this running job":"Cancel this queued job",children:I.status==="running"?"❌ Abort":"⏸ Cancel"})]}),I.status==="paused"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#059669"},onClick:()=>Q(I.id),disabled:k.has(I.id),title:"Resume this paused job",children:k.has(I.id)?"…":"▶ Resume"})]})})]},I.id)})})]}),D&&n.jsx(Wb,{title:D.title,message:D.message,detail:D.detail,params:D.params,job:D.job,onRetry:D.onRetry,onClose:()=>Y(null)})]})}function Of({label:t,children:o}){return n.jsxs("div",{style:{marginBottom:"0.6rem"},children:[n.jsx("label",{style:{display:"block",fontWeight:500,marginBottom:2,fontSize:13},children:t}),o]})}function Sk({children:t}){return n.jsx("th",{style:{textAlign:"left",padding:"4px 12px 4px 0",borderBottom:"2px solid #e5e7eb",fontSize:13,color:"#374151",whiteSpace:"nowrap"},children:t})}function Ks({children:t}){return n.jsx("td",{style:{padding:"5px 12px 5px 0",borderBottom:"1px solid #f3f4f6",fontSize:13,verticalAlign:"top"},children:t})}const If={width:"100%",padding:"5px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:13,boxSizing:"border-box"},bi={background:"#2563eb",color:"#fff",border:"none",borderRadius:4,padding:"6px 16px",fontSize:13,cursor:"pointer"},wk=[{id:"block_entropy",label:"Block Entropy",group:"Statistical (no LM)",description:"Computes H_n (normalized) for n = 1..max_n. Sub-linear growth is the hallmark of natural language (Rao 2009). Used to confirm Indus H1 = 0.739.",inputs:"text_id, max_n (default 6)",outputs:"block_entropies[], normalized values, linguistic classification",defaultParams:'{"text_id": "", "max_n": 6}',needsLM:!1},{id:"char_freq",label:"Character Frequency",group:"Statistical (no LM)",description:"Sign frequency distribution with Zipf exponent fit. Yadav (2010) found Indus follows Zipf-Mandelbrot with α≈1.00; we measured 1.555 from Fuls catalog.",inputs:"text_id",outputs:"frequencies, rank_frequency[], zipf_exponent",defaultParams:'{"text_id": ""}',needsLM:!1},{id:"positional",label:"Positional Analysis",group:"Statistical (no LM)",description:"For each sign: initial_rate, medial_rate, terminal_rate. Identifies dominant positional preferences. Validated against known TMK/INITIAL signs in Fuls catalog.",inputs:"text_id",outputs:"profiles[] per sign with dominant_position",defaultParams:'{"text_id": ""}',needsLM:!1},{id:"nwsp",label:"NWSP — Fuls Method",group:"Statistical (no LM)",description:"Exact implementation of Fuls (2013) Normalized Weighted Sign Position. NWP(p,L) = (p-1)/(L-1)*9+1, weight=L. Classifies signs as ITM/TMK/INITIAL/NUM/CON/MED. Maps to Fuls' ICIT function codes.",inputs:"text_id, min_occurrences (default 4)",outputs:"signs[] with histogram, classification, ICIT code mapping",defaultParams:'{"text_id": "", "min_occurrences": 4}',needsLM:!1},{id:"sign_polyvalence",label:"Sign Polyvalence",group:"Statistical (no LM)",description:"Detects signs with bimodal positional histograms — the hallmark of polyvalent signs serving dual functions. Reproduces Fuls' sign 550 analysis. 74% of Indus signs show bimodal patterns (logo-syllabic expected).",inputs:"text_id, min_freq (default 5)",outputs:"candidates[] sorted by bimodality_score",defaultParams:'{"text_id": "", "min_freq": 5}',needsLM:!1},{id:"sign_cluster",label:"Sign Clustering",group:"Statistical (no LM)",description:"Distributional clustering: groups signs by similar co-occurrence contexts. Signs appearing before/after the same other signs cluster together.",inputs:"text_id, min_freq, top_n",outputs:"clusters[] with member signs",defaultParams:'{"text_id": "", "min_freq": 3, "top_n": 20}',needsLM:!1},{id:"cooccurrence",label:"Co-occurrence Network",group:"Statistical (no LM)",description:"Builds a sign co-occurrence graph and detects communities using the Louvain algorithm. Community structure reveals semantic groupings.",inputs:"text_id, window (default 2), min_freq, min_edge_weight",outputs:"node_count, edge_count, community_count, communities[]",defaultParams:'{"text_id": "", "window": 2, "min_freq": 3, "min_edge_weight": 2}',needsLM:!1},{id:"paradigm",label:"Paradigm Detection",group:"Statistical (no LM)",description:"Finds paradigmatic alternations: same stem, different suffix. High paradigm count indicates rich morphological system. Indus: 102 paradigms vs Ugaritic: 2.",inputs:"text_id, min_stem_freq, min_variants",outputs:"paradigm_count, paradigms[]",defaultParams:'{"text_id": "", "min_stem_freq": 2, "min_variants": 2}',needsLM:!1},{id:"structural_fingerprint",label:"Structural Fingerprint",group:"Statistical (no LM)",description:"10-dimensional fingerprint: H1, H2/H1, Zipf-α, V/N, hapax%, mean positional entropy, polyvalence%, inscription length, boundary-bias variance, paradigmatic rate. GPU-accelerated comparison against database of 9 known writing systems.",inputs:"text_id, compare_to_db (default true)",outputs:"vector[10], dimensions{}, nearest_scripts[], notes[]",defaultParams:'{"text_id": "", "compare_to_db": true}',needsLM:!1},{id:"sign_function_estimator",label:"Sign Function Estimator",group:"Statistical (no LM)",description:"Probabilistic classifier: P(numeral), P(determinative), P(logogram), P(phonetic), P(boundary_marker) per sign. Uses 9 distributional features. Calibration note: undercalibrated for short-inscription corpora.",inputs:"text_id, min_freq (default 3)",outputs:"signs[] with probabilities, system_summary, interpretation",defaultParams:'{"text_id": "", "min_freq": 3}',needsLM:!1},{id:"numerals",label:"Numeral Detection",group:"Statistical (no LM)",description:"Identifies likely numeral signs by positional context and frequency patterns. Numerals appear before commodity signs at consistent positions.",inputs:"text_id",outputs:"numeral_candidates[], numeral_patterns[]",defaultParams:'{"text_id": ""}',needsLM:!1},{id:"word_structure_hypothesis",label:"Word-Structure Typology",group:"Statistical (no LM)",description:"Tests inscription length distribution against 6 language family profiles. No phoneme assumptions. Result: Proto-Dravidian ranks first for Indus (KL=0.444 vs Sumerian 0.742). Validated on Ugaritic, Linear B, Sumerian.",inputs:"text_id",outputs:"ranked_hypotheses[], winner, margin",defaultParams:'{"text_id": ""}',needsLM:!1},{id:"distributional_decipherment",label:"Distributional Decipherment",group:"Statistical (no LM)",description:"Jensen-Shannon divergence clustering and Ventris grid method without language assumptions. Groups signs by vowel class (similar left context) and consonant class (similar right context). GPU-backed N×N cosine similarity matrix.",inputs:"text_id, target_language",outputs:"vowel_clusters[], consonant_clusters[], sign_classification{}",defaultParams:'{"text_id": "", "target_language": "generic"}',needsLM:!1},{id:"logosyllabic",label:"Logosyllabic Analysis (Ventris)",group:"Statistical (no LM)",description:"Full Ventris-style analysis: sign classification (logogram/syllabogram/determinative) + affinity clustering (GPU cosine, complete-linkage) + candidate CV readings + vocabulary matching.",inputs:"text_id, target_language (sumerian|linear_b|generic)",outputs:"sign_classification{}, affinity{}, proposed_readings{}, candidate_words[]",defaultParams:'{"text_id": "", "target_language": "generic"}',needsLM:!1},{id:"kandles",label:"Kandles Fingerprint",group:"Language Model Required",description:"phonetic distribution (US ) phonological colour fingerprint. Maps signs to 8 colour groups by initial sound. Compares grid distributions via cosine similarity. Language-specific bias profiles for Luwian, Hurrian, Semitic, Dravidian.",inputs:"text_id, mode (color_code|grid|compare), profile",outputs:"color_distribution{}, similarity score",defaultParams:'{"text_id": "", "mode": "grid"}',needsLM:!0},{id:"decipher",label:"Decipher (SA + Structural Constraints)",group:"Language Model Required",description:"Simulated-annealing substitution cipher solver with Semitic structural constraints and cognate anchors. Constraints: use_word_bigrams, ocp_weight, root_prior_weight (root co-occurrence prior), positional_weight. anchors: dict of locked cipher→target sign correspondences (e.g. pan-Semitic cognates). Validated: Tier 1b 100%, Tier 2B 66.7%, Tier 1a 6.7% mean (best 20% at 25 restarts). See also: beam_decipher_benchmark for systematic search.",inputs:"text_id, target_text_id, max_iterations, restarts, use_word_bigrams, ocp_weight, root_prior_weight, positional_weight, anchors",outputs:"proposed_mapping{}, kandles_confidence, score",defaultParams:'{"text_id": "", "target_text_id": "", "max_iterations": 12000, "restarts": 8, "use_word_bigrams": false, "ocp_weight": 0.0, "positional_weight": 0.005}',needsLM:!0},{id:"hypothesis",label:"Hypothesis Engine",group:"Language Model Required",description:"Iterative hypothesize-test-score-learn loop over multiple language family hypotheses. Tests Dravidian vs Sanskrit vs Luwian vs Semitic. Includes Kandles bias profiles per language family.",inputs:"text_id, max_iterations",outputs:"results[] with scores per hypothesis, suggested_next[]",defaultParams:'{"text_id": "", "max_iterations": 5000}',needsLM:!0}],Ub={"Statistical (no LM)":"#16a34a","Language Model Required":"#dc2626"};function jk(){const[t,o]=x.useState("all"),[r,l]=x.useState(null),[c,d]=x.useState(wk),[u,p]=x.useState([]),[g,h]=x.useState(""),[v,y]=x.useState(!1),[b,S]=x.useState(null),[k,_]=x.useState(!1),T=W=>d(P=>P.filter(z=>z.id!==W)),w=async()=>{if(g.trim()){y(!0),S(null);try{const W=await _2(g.trim());S({ok:!0,text:`Imported: ${W.file??g}`}),h(""),C()}catch(W){S({ok:!1,text:W instanceof Error?W.message:String(W)})}finally{y(!1)}}},C=()=>{yb().then(W=>d(W.map(P=>({...P,needsLM:P.needs_lm,defaultParams:JSON.stringify(P.default_params,null,2),custom:!P.registered})))).catch(()=>{})};x.useEffect(()=>{C(),rd().then(p).catch(()=>{})},[]);const j=["all",...Array.from(new Set(c.map(W=>W.group)))],L=t==="all"?c:c.filter(W=>W.group===t);return n.jsxs("div",{children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"baseline",marginBottom:"0.25rem"},children:[n.jsx("h2",{style:{marginTop:0},children:"Pipelines"}),n.jsx("button",{onClick:()=>{_(W=>!W),S(null)},style:{padding:"5px 12px",border:"1px solid #d1d5db",borderRadius:5,cursor:"pointer",fontSize:12,background:k?"#f3f4f6":"#fff",color:"#374151"},children:k?"× Cancel":"+ Import"})]}),k&&n.jsxs("div",{style:{background:"#f8fafc",border:"1px solid #e5e7eb",borderRadius:8,padding:"12px 16px",marginBottom:"1rem"},children:[n.jsxs("p",{style:{margin:"0 0 8px",fontSize:13,color:"#374151"},children:["Enter the absolute path of a Python file that defines a class inheriting from ",n.jsx("code",{children:"PipelineBase"}),". It will be copied into the pipelines directory."]}),n.jsxs("div",{style:{display:"flex",gap:8},children:[n.jsx("input",{value:g,onChange:W=>h(W.target.value),onKeyDown:W=>{W.key==="Enter"&&w()},placeholder:"C:\\path\\to\\my_pipeline.py",style:{flex:1,padding:"7px 10px",border:"1px solid #d1d5db",borderRadius:5,fontSize:12,outline:"none",fontFamily:"monospace"}}),n.jsx("button",{onClick:()=>void w(),disabled:v||!g.trim(),style:{padding:"7px 16px",border:"none",borderRadius:5,cursor:"pointer",fontSize:12,fontWeight:600,background:"#1e3a5f",color:"#fff"},children:v?"Importing…":"Import"})]}),b&&n.jsx("div",{style:{marginTop:8,fontSize:12,padding:"6px 10px",borderRadius:5,background:b.ok?"#f0fdf4":"#fef2f2",color:b.ok?"#16a34a":"#b91c1c",border:`1px solid ${b.ok?"#86efac":"#fca5a5"}`},children:b.text})]}),n.jsxs("p",{style:{fontSize:13,color:"#6b7280",marginTop:0,marginBottom:"1.25rem"},children:[c.length," registered analysis pipelines. Statistical pipelines require no language model — all results are vocabulary-free and circularity-free. Select a pipeline to launch a job from the Jobs tab."]}),n.jsx("nav",{style:{display:"flex",gap:6,marginBottom:"1.5rem",flexWrap:"wrap"},children:j.map(W=>{const P=Ub[W]??"#1e3a5f";return n.jsx("button",{onClick:()=>o(W),style:{padding:"4px 14px",border:"1px solid",borderRadius:20,cursor:"pointer",fontSize:12,fontWeight:t===W?600:400,background:t===W?P:"#fff",borderColor:t===W?P:"#d1d5db",color:t===W?"#fff":"#374151"},children:W==="all"?`All (${c.length})`:`${W} (${c.filter(z=>z.group===W).length})`},W)})}),n.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(320px, 1fr))",gap:"0.75rem"},children:L.map(W=>n.jsx(kk,{pipeline:W,expanded:r===W.id,onToggle:()=>l(r===W.id?null:W.id),onDeleted:T,onDuplicated:C,corpora:u},W.id))}),n.jsxs("div",{style:{marginTop:"1.5rem",padding:"12px 16px",background:"#f9fafb",borderRadius:8,fontSize:12,color:"#6b7280"},children:[n.jsx("strong",{style:{color:"#374151"},children:"Scientific note:"}),' All 14 statistical pipelines are safe to run on any corpus without language assumptions. The 3 pipelines marked "Language Model Required" use bigram statistics from a target language — these must use separate training/test corpora to avoid circularity (Fuls 2013; Snyder 2010 protocol).']})]})}function kk({pipeline:t,expanded:o,onToggle:r,onDeleted:l,onDuplicated:c,corpora:d}){const u=Ub[t.group]??"#6b7280",[p,g]=x.useState(!1),[h,v]=x.useState(!1),[y,b]=x.useState(!1),[S,k]=x.useState(null),[_,T]=x.useState(!1),[w,C]=x.useState(""),[j,L]=x.useState(""),[W,P]=x.useState(""),[z,M]=x.useState(!1),[q,K]=x.useState(null),D=async A=>{var G;if(A.stopPropagation(),!w&&!W.trim()){K({ok:!1,text:"Select a corpus or enter a job name"});return}M(!0),K(null);try{const R={...JSON.parse(t.defaultParams||"{}")};w&&(R.text_id=w),j&&(R.target_text_id=j);const X=await Gc({name:W.trim()||`${t.label} — ${((G=d.find(B=>B.id===w))==null?void 0:G.name)??(w||"quick run")}`,pipeline:t.id,params:R});K({ok:!0,text:`Job submitted: ${X.id.slice(0,8)}… — check Jobs panel`}),window.dispatchEvent(new CustomEvent("glossa:running",{detail:{builder:"study",running:!0}}))}catch(R){K({ok:!1,text:R instanceof Error?R.message:"Submit failed"})}finally{M(!1)}},Y=async A=>{A.stopPropagation(),g(!0);try{await j2(t.id),c()}catch(G){k(G instanceof Error?G.message:String(G))}finally{g(!1)}},H=async A=>{if(A.stopPropagation(),!y){b(!0);return}v(!0);try{await k2(t.id),l(t.id)}catch(G){k(G instanceof Error?G.message:String(G)),v(!1),b(!1)}};return n.jsxs("div",{style:{border:`1px solid ${o?u:"#e5e7eb"}`,borderRadius:8,overflow:"hidden",transition:"border-color 0.15s"},children:[n.jsxs("div",{style:{padding:"12px 14px",background:o?u+"08":"#fff",cursor:"pointer"},onClick:r,children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:4},children:[n.jsx("code",{style:{fontSize:13,fontWeight:700,color:"#1e3a5f"},children:t.id}),n.jsxs("div",{style:{display:"flex",gap:4,alignItems:"center"},children:[t.custom&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:6,background:"#f3f4f6",color:"#6b7280",fontWeight:600},children:"custom"}),n.jsx("span",{style:{fontSize:10,padding:"1px 6px",borderRadius:8,background:u+"20",color:u,fontWeight:600,whiteSpace:"nowrap"},children:t.needsLM?"LM":"No LM"}),n.jsx("button",{onClick:Y,disabled:p,title:"Duplicate pipeline",style:ry,children:p?"…":"⎘"}),t.custom&&n.jsx("button",{onClick:H,disabled:h,title:y?"Click again to confirm":"Delete pipeline",style:{...ry,background:y?"#fef2f2":void 0,color:y?"#b91c1c":void 0},children:h?"…":y?"Confirm?":"🗑"})]})]}),n.jsx("div",{style:{fontSize:13,fontWeight:600,color:"#111827",marginBottom:4},children:t.label}),n.jsx("p",{style:{margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},children:o?t.description:t.description.slice(0,100)+(t.description.length>100?"…":"")})]}),S&&n.jsx("div",{style:{padding:"6px 14px",fontSize:12,color:"#b91c1c",background:"#fef2f2"},children:S}),o&&n.jsxs("div",{style:{padding:"0 14px 14px",borderTop:`1px solid ${u}30`,marginTop:8},children:[n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("span",{style:Qs,children:"Inputs:"}),n.jsx("code",{style:_k,children:t.inputs})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsx("span",{style:Qs,children:"Outputs:"}),n.jsx("span",{style:{fontSize:12,color:"#374151"},children:t.outputs})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsx("span",{style:Qs,children:"Default params:"}),n.jsx("pre",{style:{background:"#1e293b",color:"#e2e8f0",padding:"6px 10px",borderRadius:4,fontSize:11,fontFamily:"monospace",margin:"4px 0 0",overflowX:"auto"},children:t.defaultParams})]}),t.module&&n.jsxs("div",{style:{fontSize:11,color:"#9ca3af",marginBottom:8},children:["Module: ",n.jsx("code",{children:t.module})]}),n.jsxs("div",{style:{marginTop:10,paddingTop:10,borderTop:`1px solid ${u}20`},children:[n.jsx("button",{onClick:A=>{A.stopPropagation(),T(G=>!G),K(null)},style:{padding:"4px 12px",border:"none",borderRadius:5,cursor:"pointer",background:_?"#f3f4f6":u,color:_?"#374151":"#fff",fontSize:12,fontWeight:600},children:_?"× Cancel":"▶ Quick Run"}),_&&n.jsxs("div",{style:{marginTop:8,display:"flex",flexDirection:"column",gap:6},onClick:A=>A.stopPropagation(),children:[n.jsxs("div",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:[n.jsxs("div",{style:{flex:2,minWidth:160},children:[n.jsx("div",{style:Qs,children:"Corpus (text_id)"}),n.jsxs("select",{value:w,onChange:A=>C(A.target.value),style:{width:"100%",padding:"4px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:12},children:[n.jsx("option",{value:"",children:"— select corpus —"}),d.map(A=>n.jsxs("option",{value:A.id,children:[A.name," (",A.corpus_type,", ",A.content.length.toLocaleString()," tokens)"]},A.id))]})]}),t.needsLM&&n.jsxs("div",{style:{flex:2,minWidth:160},children:[n.jsx("div",{style:Qs,children:"Target corpus (target_text_id)"}),n.jsxs("select",{value:j,onChange:A=>L(A.target.value),style:{width:"100%",padding:"4px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:12},children:[n.jsx("option",{value:"",children:"— select target LM corpus —"}),d.map(A=>n.jsx("option",{value:A.id,children:A.name},A.id))]})]})]}),n.jsxs("div",{children:[n.jsx("div",{style:Qs,children:"Job name (optional)"}),n.jsx("input",{value:W,onChange:A=>P(A.target.value),placeholder:`${t.label} run…`,style:{width:"100%",padding:"4px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:12,boxSizing:"border-box"}})]}),n.jsx("button",{onClick:A=>void D(A),disabled:z||!w&&!W.trim(),style:{alignSelf:"flex-start",padding:"5px 16px",border:"none",borderRadius:5,background:z?"#6b7280":u,color:"#fff",cursor:z?"not-allowed":"pointer",fontSize:12,fontWeight:700},children:z?"⏳ Submitting…":"▶ Submit Job"}),q&&n.jsx("div",{style:{fontSize:11,padding:"4px 8px",borderRadius:4,background:q.ok?"#f0fdf4":"#fef2f2",color:q.ok?"#16a34a":"#b91c1c"},children:q.text})]})]})]})]})}const Qs={fontSize:11,fontWeight:600,color:"#6b7280",display:"block",marginBottom:2,textTransform:"uppercase",letterSpacing:"0.05em"},_k={fontSize:11,color:"#374151",fontFamily:"monospace"},ry={padding:"2px 7px",border:"1px solid #e5e7eb",borderRadius:4,cursor:"pointer",fontSize:11,fontWeight:600,background:"#fff",color:"#374151"},ay="glossa_email_provider_preset",$f="onboarding@resend.dev",Ck="onboarding@resend.dev";function Tk(){const{toast:t}=et(),[o,r]=x.useState(null),[l,c]=x.useState([]),[d,u]=x.useState([]),[p,g]=x.useState(null),[h,v]=x.useState(!0),[y,b]=x.useState(!1),[S,k]=x.useState(""),[_,T]=x.useState(""),[w,C]=x.useState(()=>localStorage.getItem(ay)??"outlook365_oauth"),j=x.useMemo(()=>Nf.find(ae=>ae.id===w)??Nf[0],[w]),[L,W]=x.useState(""),[P,z]=x.useState(587),[M,q]=x.useState(""),[K,D]=x.useState(""),[Y,H]=x.useState(""),[A,G]=x.useState(!0),[R,X]=x.useState(""),[B,V]=x.useState($f),[Q,N]=x.useState(!0),[O,$]=x.useState(null),[F,I]=x.useState(!1),[J,ne]=x.useState(""),[se,pe]=x.useState(""),[_e,we]=x.useState("common"),ke=x.useRef(!1),te=x.useCallback(async()=>{v(!0);try{const[ae,He,Ze,ut,Ut]=await Promise.all([Tb(),xj(),vj(20),zb().catch(()=>null),ad().catch(()=>null)]);r(ae),c(He.recipients),u(Ze.entries),g(ut),W(ae.host||""),z(ae.port||587),H(ae.from||""),G(ae.use_tls??!0),we(ae.graph_tenant||"common"),Ut&&!ae.graph_client_id_set&&pe(""),V(ae.resend_from||$f),N(ae.resend_configured!==void 0)}catch(ae){t(ae instanceof Error?ae.message:"Failed to load notifications","error")}finally{v(!1)}},[t]);x.useEffect(()=>{te()},[te]),x.useEffect(()=>{localStorage.setItem(ay,j.id),j.category==="smtp"&&(j.smtp_host!==void 0&&W(j.smtp_host),j.smtp_port!==void 0&&z(j.smtp_port),j.smtp_use_tls!==void 0&&G(j.smtp_use_tls))},[j.id]);const de=async()=>{const ae=S.trim();if(ae){b(!0);try{await yj({email:ae,label:_.trim(),active:!0}),k(""),T(""),t("Recipient added","success"),await te()}catch(He){t(He instanceof Error?He.message:"Could not add recipient","error")}finally{b(!1)}}},Ce=async ae=>{try{await Zx(ae.id,{active:!ae.active}),await te()}catch(He){t(He instanceof Error?He.message:"Update failed","error")}},ze=async ae=>{const He=window.prompt("Label:",ae.label);if(He!==null)try{await Zx(ae.id,{label:He}),await te()}catch(Ze){t(Ze instanceof Error?Ze.message:"Update failed","error")}},ve=async ae=>{if(window.confirm(`Remove ${ae.email} from notifications?`))try{await bj(ae.id),t("Recipient removed","info"),await te()}catch(He){t(He instanceof Error?He.message:"Delete failed","error")}},De=async()=>{b(!0);try{const ae=await Sj();t(`Test sent: ${ae.sent} ok / ${ae.failed} failed`,ae.failed?"warning":"success"),await te()}catch(ae){t(ae instanceof Error?ae.message:"Test failed","error")}finally{b(!1)}},Me=async()=>{const ae=R.trim(),He=B.trim(),Ze=((o==null?void 0:o.resend_from)||"").trim(),ut=He.length>0&&He!==Ze,Ut=!!(o!=null&&o.resend_configured);if(!ae&&!ut){Ut?t("Nothing to save — edit the From address or paste a new key","info"):t("Paste your Resend API key first","warning");return}if(!ae&&!Ut){t("Paste your Resend API key first","warning");return}b(!0);try{const Nt={};ae&&(Nt.resend_api_key=ae),ut&&(Nt.resend_from=He);const yn=await sr(Nt),ft=Object.keys(Nt).filter(qt=>!yn.updated.includes(qt));if(ft.length>0){t(`Backend ignored ${ft.join(", ")} — it's likely running an older build. Restart the backend (setup-os.cmd restart) and try again.`,"error");return}const Et=[];ae&&Et.push("API key updated"),ut&&Et.push(`From set to ${He}`),t(`Resend: ${Et.join(" · ")}`,"success"),X(""),await te()}catch(Nt){t(Nt instanceof Error?Nt.message:"Save failed","error")}finally{b(!1)}},Ve=async()=>{if(window.confirm("Clear the Resend API key? Email will fall back to SMTP/Outlook if configured, otherwise no transport.")){b(!0);try{await sr({resend_api_key:""}),t("Resend API key cleared","info"),await te()}catch(ae){t(ae instanceof Error?ae.message:"Clear failed","error")}finally{b(!1)}}},Le=async()=>{b(!0);try{const ae={smtp_host:L.trim(),smtp_port:String(P||587),smtp_from:Y.trim(),smtp_use_tls:A?"1":"0"};M.trim()&&(ae.smtp_username=M.trim()),K&&(ae.smtp_password=K),await sr(ae),t("SMTP settings saved","success"),D(""),await te()}catch(ae){t(ae instanceof Error?ae.message:"Save failed","error")}finally{b(!1)}},Ae=async()=>{b(!0);try{const ae={ms_graph_tenant_id:_e.trim()||"common"};se.trim()&&(ae.ms_graph_client_id=se.trim()),await sr(ae),t("Outlook 365 client config saved","success"),pe(""),await te()}catch(ae){t(ae instanceof Error?ae.message:"Save failed","error")}finally{b(!1)}},Ue=async()=>{ne(""),b(!0);try{const ae=await wj();$(ae),ke.current=!1,Oe(ae)}catch(ae){ne(ae instanceof Error?ae.message:"Could not start device flow"),t("Outlook connect failed — check ms_graph_client_id","error")}finally{b(!1)}},Oe=async ae=>{I(!0);const He=Math.max(2e3,ae.interval*1e3);for(;!ke.current&&(await new Promise(Ze=>setTimeout(Ze,He)),!ke.current);)try{const Ze=await jj(ae.session_id);if(Ze.status==="success"){t("Outlook 365 connected","success"),$(null),I(!1),await te();return}if(Ze.status==="failed"||Ze.status==="expired"){ne(Ze.error||Ze.status),I(!1);return}}catch(Ze){ne(Ze instanceof Error?Ze.message:"poll failed"),I(!1);return}I(!1)},dt=()=>{ke.current=!0,$(null),I(!1)},it=async()=>{if(window.confirm("Disconnect Outlook 365? You can reconnect anytime.")){b(!0);try{await kj(),t("Outlook 365 disconnected","info"),await te()}catch(ae){t(ae instanceof Error?ae.message:"Disconnect failed","error")}finally{b(!1)}}},lt=async ae=>{b(!0);try{const He=ae?await Eb():await Rb();g(He),t(ae?`Auto-start ON — fetch + mine + digest will run every ${Math.round(He.interval_seconds/3600)}h`:"Auto-start OFF","info")}catch(He){t(He instanceof Error?He.message:"Toggle failed","error")}finally{b(!1)}},Je=(o==null?void 0:o.configured)??!1,yt=(o==null?void 0:o.recipients_active)??0,Jt=(o==null?void 0:o.recipients_total)??0,rn=j.category==="oauth",zt=j.category==="api";return n.jsxs("section",{style:Ek,children:[n.jsx("h3",{style:Rk,children:"📬 Email & Notifications"}),n.jsx("p",{style:ly,children:"Pick a mail provider, fill in the credentials it needs, then add recipients. Outlook 365 uses Microsoft's modern OAuth (no app password) — recommended for anyone with a Microsoft 365 / school / work account."}),n.jsxs("div",{style:{marginTop:10,padding:"10px 14px",borderRadius:7,border:`1px solid ${Je?"#86efac":"#fcd34d"}`,background:Je?"#f0fdf4":"#fffbeb",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:16},children:Je?"✅":"⚠️"}),n.jsxs("div",{style:{flex:1,minWidth:220},children:[n.jsx("div",{style:{fontSize:13,fontWeight:600,color:Je?"#15803d":"#92400e"},children:Je?(o==null?void 0:o.transport)==="graph"?"Outlook 365 (Microsoft Graph) configured":(o==null?void 0:o.transport)==="resend"?"Resend (HTTPS API) configured":"SMTP configured":"Email not configured"}),n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:Je?(o==null?void 0:o.transport)==="graph"?`Tenant ${o==null?void 0:o.graph_tenant} · ${yt}/${Jt} active recipients`:(o==null?void 0:o.transport)==="resend"?`From ${(o==null?void 0:o.resend_from)||"onboarding@resend.dev"} · ${yt}/${Jt} active recipients`:`Host ${o==null?void 0:o.host}:${o==null?void 0:o.port} · From ${(o==null?void 0:o.from)||"(unset)"} · ${yt}/${Jt} active`:"Choose a provider below and complete its setup."})]}),n.jsx("button",{onClick:()=>void De(),disabled:y||!Je||yt===0,title:yt===0?"Add an active recipient first":"Send a deliverability test email",style:{...pc,opacity:y||!Je||yt===0?.5:1,cursor:y||!Je||yt===0?"not-allowed":"pointer"},children:y?"Sending…":"✉ Send Test"}),n.jsx("button",{onClick:()=>void te(),title:"Reload",style:cy,children:"⟳"})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:Wf,children:"1 · Mail provider"}),n.jsx("select",{value:w,onChange:ae=>C(ae.target.value),style:{...Jn,fontSize:13},children:Nf.map(ae=>n.jsxs("option",{value:ae.id,children:[ae.label,ae.recommended?" ⭐":""]},ae.id))}),n.jsx("p",{style:{...ly,marginTop:6},children:j.notes})]}),rn&&n.jsxs("div",{style:{marginTop:14,padding:"12px 14px",borderRadius:7,border:"1px solid #c7d2fe",background:"#eef2ff"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:16},children:"🪪"}),n.jsxs("div",{style:{flex:1,minWidth:240},children:[n.jsx("div",{style:{fontSize:13,fontWeight:700,color:"#3730a3"},children:"Outlook 365 (Microsoft Graph)"}),n.jsx("div",{style:{fontSize:11,color:"#4338ca",marginTop:2},children:o!=null&&o.graph_configured?`Connected. Tenant: ${o==null?void 0:o.graph_tenant}. Mail.Send delegated.`:o!=null&&o.graph_client_id_set?"Client ID set, but not yet authorised. Click Connect to start.":"Set the Application (client) ID below, then click Connect."})]}),o!=null&&o.graph_configured?n.jsx("button",{onClick:()=>void it(),disabled:y,style:ha,children:"Disconnect"}):n.jsx("button",{onClick:()=>void Ue(),disabled:y||!(o!=null&&o.graph_client_id_set)||F,title:o!=null&&o.graph_client_id_set?"Start the device-code OAuth flow":"Set the Application (client) ID first",style:{...pc,background:"#4338ca",cursor:y||!(o!=null&&o.graph_client_id_set)?"not-allowed":"pointer",opacity:y||!(o!=null&&o.graph_client_id_set)?.5:1},children:"🔗 Connect Outlook 365"})]}),!(o!=null&&o.graph_configured)&&n.jsxs("div",{style:{marginTop:10,display:"grid",gap:6},children:[n.jsx("input",{value:se,placeholder:o!=null&&o.graph_client_id_set?"●●●●●●●● (paste new Application (client) ID to replace)":"Application (client) ID (Azure AD app registration)",onChange:ae=>pe(ae.target.value),style:Jn}),n.jsx("input",{value:_e,placeholder:'Tenant ID (default "common" works for both work and personal accounts)',onChange:ae=>we(ae.target.value),style:Jn}),n.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center"},children:[n.jsx("button",{onClick:()=>void Ae(),disabled:y,style:ha,children:"Save client config"}),n.jsx("span",{style:{fontSize:10,color:"#6b7280"},children:"Need help registering an app? entra.microsoft.com → App registrations → New → public client → Mail.Send delegated permission."})]})]}),O&&n.jsxs("div",{style:{marginTop:10,padding:"10px 12px",borderRadius:6,background:"#fff",border:"1px solid #c7d2fe"},children:[n.jsxs("div",{style:{fontSize:12,color:"#374151"},children:["1. Open ",n.jsx("a",{href:O.verification_uri,target:"_blank",rel:"noopener noreferrer",style:{color:"#4338ca"},children:O.verification_uri})]}),n.jsx("div",{style:{fontSize:12,color:"#374151",marginTop:4},children:"2. Paste this code:"}),n.jsx("div",{style:{marginTop:6,fontSize:22,fontWeight:800,fontFamily:"monospace",color:"#4338ca",letterSpacing:2,padding:"6px 10px",border:"2px dashed #c7d2fe",borderRadius:6,display:"inline-block"},children:O.user_code}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:6},children:[F?"Waiting for approval…":"Polling stopped"," ","· Code expires in ",Math.round(O.expires_in/60)," min.",n.jsx("button",{onClick:dt,style:{...cy,marginLeft:8},children:"Cancel"})]})]}),J&&n.jsxs("div",{style:{marginTop:8,fontSize:11,color:"#b91c1c"},children:["⚠ ",J]})]}),zt&&n.jsxs("div",{style:{marginTop:14,padding:"12px 14px",borderRadius:7,border:"1px solid #bbf7d0",background:"#f0fdf4"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:16},children:"⚡"}),n.jsxs("div",{style:{flex:1,minWidth:240},children:[n.jsx("div",{style:{fontSize:13,fontWeight:700,color:"#15803d"},children:"Resend (HTTPS API)"}),n.jsx("div",{style:{fontSize:11,color:"#166534",marginTop:2},children:o!=null&&o.resend_configured?`Connected. Sends from ${(o==null?void 0:o.resend_from)||$f}.`:"Paste your Resend API key (starts with re_). No SMTP, no mailbox, no domain needed."})]}),(o==null?void 0:o.resend_configured)&&n.jsx("button",{onClick:()=>void Ve(),disabled:y,style:{...ha,color:"#15803d",borderColor:"#bbf7d0"},children:"Clear key"})]}),!Q&&n.jsxs("div",{style:{marginTop:10,padding:"8px 12px",borderRadius:6,border:"1px solid #fcd34d",background:"#fffbeb",fontSize:11,color:"#92400e"},children:["⚠ The running backend doesn’t expose Resend yet — saving the key here will be silently ignored. Restart the backend (",n.jsx("code",{children:"setup-os.cmd restart"}),") so the new transport loads, then come back to this screen."]}),Q&&(o==null?void 0:o.resend_configured)&&(o==null?void 0:o.transport)!=="resend"&&n.jsxs("div",{style:{marginTop:10,padding:"8px 12px",borderRadius:6,border:"1px solid #fcd34d",background:"#fffbeb",fontSize:11,color:"#92400e"},children:["⚠ Resend is configured but the active transport is",n.jsxs("b",{children:[" ",o==null?void 0:o.transport]}),". Microsoft Graph (Outlook OAuth) outranks Resend; if you don’t want that, click",n.jsx("b",{children:" Disconnect Outlook 365"})," above. Plain SMTP cannot outrank Resend, so if you see ",n.jsx("i",{children:"smtp"})," here despite Resend being configured, the backend hasn’t reloaded yet — restart it."]}),(()=>{var Ze;return(((Ze=B.match(/<([^>]+)>/))==null?void 0:Ze[1])??B).trim().toLowerCase()===Ck&&n.jsxs("div",{style:{marginTop:10,padding:"8px 12px",borderRadius:6,border:"1px solid #fde68a",background:"#fffbeb",fontSize:11,color:"#92400e"},children:["ℹ You’re using Resend’s free shared sender (",n.jsx("code",{children:"onboarding@resend.dev"}),"). Resend will only deliver to the email you signed up to Resend with. Recipients other than that one address get a 403. Verify your own domain at"," ",n.jsx("a",{href:"https://resend.com/domains",target:"_blank",rel:"noopener noreferrer",style:{color:"#92400e",textDecoration:"underline"},children:"resend.com/domains"})," ","and switch From to ",n.jsx("code",{children:"noreply@"}),"to send to anyone."]})})(),n.jsxs("div",{style:{display:"grid",gap:8,marginTop:10},children:[n.jsxs("label",{style:{fontSize:11,fontWeight:600,color:"#166534",display:"flex",flexDirection:"column",gap:4},children:["API key",n.jsx("input",{value:R,onChange:ae=>X(ae.target.value),placeholder:o!=null&&o.resend_configured?"●●●●●●●● (leave blank to keep current key)":"Resend API key (re_xxx…)",type:"password",autoComplete:"off",style:Jn})]}),n.jsxs("label",{style:{fontSize:11,fontWeight:600,color:"#166534",display:"flex",flexDirection:"column",gap:4},children:["From address (always editable)",n.jsx("input",{value:B,onChange:ae=>V(ae.target.value),placeholder:'"noreply@yourdomain.com" or "Glossa Lab " once a domain is verified at resend.com/domains.',style:Jn}),n.jsxs("span",{style:{fontSize:10,fontWeight:400,color:"#6b7280"},children:["Currently saved: ",n.jsx("code",{children:(o==null?void 0:o.resend_from)||"(unset)"})]})]}),(()=>{const ae=R.trim(),He=B.trim(),Ze=((o==null?void 0:o.resend_from)||"").trim(),ut=He.length>0&&He!==Ze,Ut=!!ae||!!(o!=null&&o.resend_configured)&&ut,Nt=y?"Saving…":o!=null&&o.resend_configured?ae&&ut?"Save key + From":ae?"Replace key":ut?"Save From address":"Save Resend settings":"Save Resend key";return n.jsxs("div",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:[n.jsx("button",{onClick:()=>void Me(),disabled:y||!Ut,style:{...pc,opacity:y||!Ut?.5:1,cursor:y||!Ut?"not-allowed":"pointer"},children:Nt}),n.jsx("button",{onClick:()=>void De(),disabled:y||!Je||yt===0,style:{...ha,cursor:y||!Je||yt===0?"not-allowed":"pointer",opacity:y||!Je||yt===0?.5:1},children:"✉ Send test"}),n.jsx("a",{href:"https://resend.com/api-keys",target:"_blank",rel:"noopener noreferrer",style:{marginLeft:"auto",fontSize:11,color:"#15803d",alignSelf:"center"},children:"Get an API key →"})]})})()]})]}),!rn&&!zt&&n.jsxs("div",{style:{marginTop:14,padding:"12px 14px",borderRadius:7,border:"1px solid #e5e7eb",background:"#fafafa"},children:[n.jsx("div",{style:{...Wf,color:"#374151",margin:"0 0 8px"},children:"2 · SMTP credentials"}),n.jsxs("div",{style:{display:"grid",gridTemplateColumns:"2fr 1fr",gap:8},children:[n.jsx("input",{value:L,placeholder:"SMTP host (e.g. smtp.gmail.com)",onChange:ae=>W(ae.target.value),style:Jn}),n.jsx("input",{value:P||"",type:"number",placeholder:"Port (587)",onChange:ae=>z(parseInt(ae.target.value||"0",10)||587),style:Jn})]}),n.jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8,marginTop:8},children:[n.jsx("input",{value:M,placeholder:"Username (usually your full email address)",onChange:ae=>q(ae.target.value),style:Jn,autoComplete:"off"}),n.jsx("input",{value:K,type:"password",placeholder:o!=null&&o.password_set?"●●●●●●●● (paste new app password)":"App password / SMTP password",onChange:ae=>D(ae.target.value),style:Jn,autoComplete:"off"})]}),n.jsx("input",{value:Y,placeholder:'From address (e.g. "Glossa Lab " or just an email)',onChange:ae=>H(ae.target.value),style:{...Jn,marginTop:8}}),n.jsxs("label",{style:{display:"flex",alignItems:"center",gap:6,marginTop:8,fontSize:12,color:"#374151"},children:[n.jsx("input",{type:"checkbox",checked:A,onChange:ae=>G(ae.target.checked)}),"Use STARTTLS (recommended)"]}),n.jsxs("div",{style:{display:"flex",gap:6,marginTop:10,flexWrap:"wrap"},children:[n.jsx("button",{onClick:()=>void Le(),disabled:y,style:pc,children:y?"Saving…":"Save SMTP settings"}),n.jsx("button",{onClick:()=>void De(),disabled:y||!Je||yt===0,style:{...ha,cursor:y||!Je||yt===0?"not-allowed":"pointer",opacity:y||!Je||yt===0?.5:1},children:"✉ Send test"})]})]}),n.jsxs("div",{style:{marginTop:14,padding:"12px 14px",borderRadius:7,border:`1px solid ${p!=null&&p.running?"#86efac":"#e5e7eb"}`,background:p!=null&&p.running?"#f0fdf4":"#fafafa",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:16},children:p!=null&&p.running?"⏱️":"💤"}),n.jsxs("div",{style:{flex:1,minWidth:240},children:[n.jsxs("div",{style:{fontSize:13,fontWeight:600,color:p!=null&&p.running?"#15803d":"#374151"},children:["Auto-start discovery ",p!=null&&p.running?"— RUNNING":"— OFF"]}),n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:p?`Fetch + mine + digest every ${Math.round(p.interval_seconds/3600)}h. ${p.enabled?"Persisted; resumes on next backend boot.":"Not persisted."}`:"Loading scheduler status…"})]}),n.jsx("div",{onClick:()=>!y&&void lt(!(p!=null&&p.running)),title:p!=null&&p.running?"Stop scheduler + persist OFF":"Start scheduler + persist ON",style:{width:44,height:24,borderRadius:12,cursor:y?"not-allowed":"pointer",flexShrink:0,position:"relative",background:p!=null&&p.running?"#22c55e":"#d1d5db",opacity:y?.5:1,transition:"background 0.2s"},children:n.jsx("div",{style:{position:"absolute",top:3,left:p!=null&&p.running?23:3,width:18,height:18,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 3px rgba(0,0,0,0.25)",transition:"left 0.2s"}})})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsxs("div",{style:Wf,children:["3 · Recipients (",l.length,")"]}),h?n.jsx("div",{style:{fontSize:12,color:"#6b7280"},children:"Loading…"}):l.length===0?n.jsx("div",{style:{fontSize:12,color:"#9ca3af",fontStyle:"italic"},children:"No recipients yet. Add at least one address below to start receiving emails."}):n.jsx("div",{style:{border:"1px solid #e5e7eb",borderRadius:6,overflow:"hidden"},children:l.map(ae=>n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"7px 12px",borderBottom:"1px solid #f1f5f9",background:ae.active?"#fff":"#fafafa"},children:[n.jsx("span",{title:ae.active?"Active":"Paused",style:{width:8,height:8,borderRadius:"50%",background:ae.active?"#22c55e":"#cbd5e1",flexShrink:0}}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsx("div",{style:{fontSize:13,fontWeight:500,color:"#111827",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:ae.email}),ae.label&&n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginTop:1},children:ae.label})]}),n.jsx("button",{onClick:()=>void Ce(ae),title:ae.active?"Pause notifications":"Resume notifications",style:Hf(ae.active?"#f59e0b":"#22c55e"),children:ae.active?"⏸":"▶"}),n.jsx("button",{onClick:()=>void ze(ae),title:"Edit label",style:Hf("#6b7280"),children:"✎"}),n.jsx("button",{onClick:()=>void ve(ae),title:"Remove",style:Hf("#dc2626"),children:"🗑"})]},ae.id))}),n.jsxs("div",{style:{display:"flex",gap:6,marginTop:8,flexWrap:"wrap"},children:[n.jsx("input",{value:S,onChange:ae=>k(ae.target.value),onKeyDown:ae=>{ae.key==="Enter"&&S.trim()&&de()},placeholder:"recipient@example.com",style:{...Jn,flex:2,minWidth:200}}),n.jsx("input",{value:_,onChange:ae=>T(ae.target.value),onKeyDown:ae=>{ae.key==="Enter"&&S.trim()&&de()},placeholder:"Label (optional, e.g. PI, lab)",style:{...Jn,flex:1,minWidth:140}}),n.jsx("button",{onClick:()=>void de(),disabled:y||!S.trim(),style:{...Ak,cursor:y||!S.trim()?"not-allowed":"pointer",opacity:y||!S.trim()?.5:1},children:"+ Add"})]})]}),n.jsxs("details",{style:{marginTop:16},children:[n.jsxs("summary",{style:{cursor:"pointer",fontWeight:600,fontSize:13,color:"#374151"},children:["📜 Recent send log (",d.length,")"]}),n.jsx("div",{style:{marginTop:8,maxHeight:220,overflowY:"auto",border:"1px solid #e5e7eb",borderRadius:6},children:d.length===0?n.jsx("div",{style:{fontSize:12,color:"#9ca3af",padding:"10px 14px",fontStyle:"italic"},children:"No emails sent yet."}):d.map(ae=>{const He=ae.status==="sent"?"#22c55e":ae.status==="failed"?"#dc2626":"#9ca3af";return n.jsxs("div",{style:{display:"flex",gap:8,padding:"6px 12px",borderBottom:"1px solid #f1f5f9",alignItems:"center"},children:[n.jsx("span",{style:{fontSize:9,fontWeight:700,color:He,background:He+"20",padding:"1px 6px",borderRadius:4,textTransform:"uppercase",flexShrink:0},children:ae.status}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsx("div",{style:{fontSize:12,color:"#111827",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:ae.subject}),n.jsxs("div",{style:{fontSize:10,color:"#6b7280",marginTop:1},children:["to ",ae.recipient," · ",ae.kind," · ",zk(ae.sent_at),ae.item_count>0&&` · ${ae.item_count} items`]}),ae.error&&n.jsx("div",{style:{fontSize:10,color:"#dc2626",marginTop:1},children:ae.error})]})]},ae.id)})})]})]})}function Hf(t){return{border:"1px solid "+t+"40",borderRadius:4,background:"none",color:t,cursor:"pointer",fontSize:11,padding:"2px 7px"}}function zk(t){if(!t)return"";const o=new Date(t);return Number.isNaN(o.getTime())?t:o.toLocaleString()}const Ek={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #e5e7eb",borderRadius:8},Rk={margin:"0 0 0.5rem 0",fontSize:15,fontWeight:600,color:"#111827"},ly={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},Wf={fontSize:11,fontWeight:700,color:"#7c3aed",textTransform:"uppercase",letterSpacing:.5,marginBottom:6},Jn={padding:"6px 10px",border:"1px solid #d1d5db",borderRadius:5,fontSize:13,width:"100%",boxSizing:"border-box",outline:"none"},pc={padding:"5px 12px",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},Ak={padding:"6px 16px",border:"none",borderRadius:5,background:"#7c3aed",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},cy={padding:"5px 9px",border:"1px solid #d1d5db",borderRadius:5,background:"#fff",cursor:"pointer",fontSize:12},ha={padding:"5px 12px",border:"1px solid #c7d2fe",borderRadius:6,background:"#fff",color:"#4338ca",fontSize:12,fontWeight:600,cursor:"pointer"},Mk=[{id:"news_api_key",label:"NewsAPI",href:"https://newsapi.org/account",hint:"Global news articles. Free tier: 100 req/day."},{id:"serp_api_key",label:"SerpAPI",href:"https://serpapi.com/manage-api-key",hint:"Google search results. Free tier: 100 searches/month."},{id:"brave_search_api_key",label:"Brave Search",href:"https://api-dashboard.search.brave.com/",hint:"Web search. Free tier: 2,000 queries/month."},{id:"uspto_api_key",label:"USPTO (ODP)",href:"https://developer.uspto.gov/",hint:"US patent search via the Open Data Portal. Free key."}],Dk=[{id:"semantic_scholar_api_key",label:"Semantic Scholar",href:"https://www.semanticscholar.org/product/api#api-key-form",hint:"Removes the 100 req/5 min cap. Strongly recommended."},{id:"openalex_email",label:"OpenAlex (email)",href:"https://docs.openalex.org/how-to-use-the-api/rate-limits-and-authentication",hint:"Enter your email for priority access. Not a key — just an email."}];function Lk(){const{toast:t}=et(),[o,r]=x.useState(null),[l,c]=x.useState([]),[d,u]=x.useState([]),[p,g]=x.useState(null),[h,v]=x.useState(null),[y,b]=x.useState({}),[S,k]=x.useState({}),[_,T]=x.useState(!1),[w,C]=x.useState(!1),[j,L]=x.useState(!1),W=x.useCallback(async()=>{try{const[H,A,G,R,X]=await Promise.all([ad(),Cb(),_b(),zb().catch(()=>null),Tb().catch(()=>null)]);r(H),c(A.sources),u(G.topics),g(R),v(X)}catch(H){t(H instanceof Error?H.message:"Failed to load discovery state","error")}},[t]);x.useEffect(()=>{W()},[W]);const P=async H=>{const A=(y[H]??"").trim();if(!A){t("Paste a value first","warning");return}T(!0);try{await sr({[H]:A}),b(G=>({...G,[H]:""})),t(`${H} saved`,"success"),await W()}catch(G){t(G instanceof Error?G.message:"Save failed","error")}finally{T(!1)}},z=async H=>{k(A=>({...A,[H]:"loading"}));try{const A=await m2(H);k(G=>({...G,[H]:A}))}catch(A){k(G=>({...G,[H]:{valid:!1,provider:H,message:A instanceof Error?A.message:"verify failed"}}))}},M=async H=>{T(!0);try{const A=H?await Eb():await Rb();g(A),t(H?`Auto-start ON · every ${Math.round(A.interval_seconds/3600)}h`:"Auto-start OFF","info")}catch(A){t(A instanceof Error?A.message:"Toggle failed","error")}finally{T(!1)}},q=async()=>{C(!0);try{const H=await Pc({});t(`Fetch started · job ${H.job_id.slice(0,8)}`,"info")}catch(H){t(H instanceof Error?H.message:"Fetch failed to start","error")}finally{C(!1)}},K=async()=>{L(!0);try{const H=await Hp({limit:50});t(`Mine started · job ${H.job_id.slice(0,8)} · limit 50`,"info")}catch(H){t(H instanceof Error?H.message:"Mine failed to start","error")}finally{L(!1)}},D=l.filter(H=>H.configured).length,Y=l.length;return n.jsxs("section",{style:Nk,children:[n.jsx("h3",{style:Bk,children:"🔭 Auto Discovery"}),n.jsx("p",{style:ga,children:"The continuous-discovery loop fetches new findings from external sources, classifies + de-duplicates them via your AI provider, and surfaces them in the Discovery view + Dashboard. Configure the sources, toggle the schedule, and trigger manual runs from this panel."}),n.jsxs("div",{style:{marginTop:10,padding:"10px 14px",borderRadius:7,border:`1px solid ${p!=null&&p.running?"#86efac":"#fcd34d"}`,background:p!=null&&p.running?"#f0fdf4":"#fffbeb",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:16},children:p!=null&&p.running?"⏱️":"💤"}),n.jsxs("div",{style:{flex:1,minWidth:220},children:[n.jsx("div",{style:{fontSize:13,fontWeight:600,color:p!=null&&p.running?"#15803d":"#92400e"},children:p!=null&&p.running?"Auto-discovery running":"Auto-discovery off"}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:[D,"/",Y," sources configured",p?` · interval ${Math.round(p.interval_seconds/3600)}h`:"",p!=null&&p.enabled?" · persisted":p?" · not persisted":"",d.length>0?` · ${d.length} topic(s)`:""]})]}),n.jsx("div",{onClick:()=>!_&&void M(!(p!=null&&p.running)),title:p!=null&&p.running?"Stop scheduler":"Start scheduler + persist",style:{width:44,height:24,borderRadius:12,cursor:_?"not-allowed":"pointer",flexShrink:0,position:"relative",background:p!=null&&p.running?"#22c55e":"#d1d5db",opacity:_?.5:1,transition:"background 0.2s"},children:n.jsx("div",{style:{position:"absolute",top:3,left:p!=null&&p.running?23:3,width:18,height:18,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 3px rgba(0,0,0,0.25)",transition:"left 0.2s"}})})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:hc,children:"1 · Manual run"}),n.jsx("p",{style:{...ga,marginTop:4},children:"Trigger a fetch (pulls new items from every configured source for every topic) and/or a mine (LLM-classifies un-mined items in the queue). Both run as background jobs you can watch in the Jobs panel."}),n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[n.jsx("button",{onClick:()=>void q(),disabled:w,style:{...Ik,opacity:w?.5:1,cursor:w?"not-allowed":"pointer"},children:w?"⏳ Fetching…":"▶ Fetch now"}),n.jsx("button",{onClick:()=>void K(),disabled:j,style:{...$k,opacity:j?.5:1,cursor:j?"not-allowed":"pointer"},children:j?"⏳ Mining…":"✨ Mine now (50)"}),n.jsx("span",{style:{flex:1}}),n.jsx("a",{href:"#",onClick:H=>{H.preventDefault(),window.dispatchEvent(new CustomEvent("glossa:navigate",{detail:{view:"discovery"}}))},style:{alignSelf:"center",fontSize:11,color:"#2563eb",textDecoration:"underline"},children:"Open Discovery view →"})]}),n.jsxs("p",{style:{...ga,marginTop:8,fontSize:11},children:["Or from a shell: ",n.jsx("code",{children:"python -m glossa_lab.discovery fetch"})," / ",n.jsx("code",{children:"mine --limit 50"})," / ",n.jsx("code",{children:"daily --notify"})]})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:hc,children:"2 · API keys"}),n.jsx("p",{style:{...ga,marginTop:4},children:"Sources that need a key are listed below. Keyless sources (arXiv, Crossref, OpenAlex, PubMed, Europe PMC, DOAJ, GDELT, PPUBS, RSS, Academia) are always on."}),n.jsx("div",{style:{marginTop:10,marginBottom:4},children:n.jsx("span",{style:uy,children:"🔑 Required — source won’t fetch without these"})}),n.jsx("div",{style:{display:"grid",gap:8},children:Mk.map(H=>n.jsx(dy,{k:H,settings:o,pendingKeys:y,setPendingKeys:b,verify:S,onSaveKey:P,onVerifyKey:z,busy:_},H.id))}),n.jsx("div",{style:{marginTop:14,marginBottom:4},children:n.jsx("span",{style:uy,children:"⚡ Optional upgrades — source works without, key removes rate limits"})}),n.jsx("div",{style:{display:"grid",gap:8},children:Dk.map(H=>n.jsx(dy,{k:H,settings:o,pendingKeys:y,setPendingKeys:b,verify:S,onSaveKey:P,onVerifyKey:z,busy:_},H.id))})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:hc,children:"3 · Email digest on run"}),n.jsx("p",{style:{...ga,marginTop:4},children:"When notifications are configured (any active recipient + a working transport), every scheduled fetch+mine cycle sends a digest of new findings."}),n.jsxs("div",{style:{padding:10,borderRadius:7,border:`1px solid ${h!=null&&h.configured?"#86efac":"#fcd34d"}`,background:h!=null&&h.configured?"#f0fdf4":"#fffbeb",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:14},children:h!=null&&h.configured?"✉":"⚠"}),n.jsxs("div",{style:{flex:1,minWidth:220},children:[n.jsx("div",{style:{fontSize:12,fontWeight:600,color:h!=null&&h.configured?"#15803d":"#92400e"},children:h!=null&&h.configured?`Transport: ${h==null?void 0:h.transport} · ${h==null?void 0:h.recipients_active}/${h==null?void 0:h.recipients_total} active recipient(s)`:"Email transport not configured"}),n.jsx("div",{style:{fontSize:10,color:"#6b7280",marginTop:2},children:h!=null&&h.configured?"Manage recipients + send a test in the Email & Notifications section below.":"Configure Resend, Outlook 365 OAuth, or SMTP in the Email & Notifications section below."})]})]})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:hc,children:"4 · Sources detected by the backend"}),n.jsx("div",{style:{display:"flex",gap:6,flexWrap:"wrap",marginTop:6},children:l.map(H=>{const A=H,G=A.rate_limit,R=G==null?void 0:G.rate_limited,X=Number((G==null?void 0:G.errors_429)??0),B=Number((G==null?void 0:G.requests)??0),V=A.upgrade_hint,Q=A.upgrade_url,N=R?"#fef2f2":H.configured?"#f0fdf4":"#fafafa",O=R?"#fca5a5":H.configured?"#86efac":"#e5e7eb",$=R?"#b91c1c":H.configured?"#15803d":"#9ca3af";return n.jsxs("span",{title:R?`⚠ Rate limited (${X}/${B} requests returned 429)${V?`. ${V}`:""}`:B>0?`${B} requests, ${X} rate-limited`:H.disabled_reason||`${H.source} ready`,style:{padding:"3px 9px",borderRadius:12,border:"1px solid",background:N,borderColor:O,color:$,fontSize:11,fontWeight:500,cursor:Q?"pointer":"default"},onClick:()=>Q&&window.open(Q,"_blank"),children:[R?"⚠ ":H.configured?"✓ ":"✗ ",H.source,B>0&&n.jsxs("span",{style:{fontSize:9,marginLeft:4,opacity:.7},children:[B,"req",X>0?` · ${X}×429`:""]})]},H.source)})})]})]})}function dy({k:t,settings:o,pendingKeys:r,setPendingKeys:l,verify:c,onSaveKey:d,onVerifyKey:u,busy:p}){var y,b,S,k,_;const g=((y=o==null?void 0:o.keys[t.id])==null?void 0:y.set)??!1,h=((b=o==null?void 0:o.keys[t.id])==null?void 0:b.source)??null,v=c[t.id];return n.jsxs("div",{style:{padding:"8px 10px",border:"1px solid #e5e7eb",borderRadius:7,background:"#fff",display:"flex",flexDirection:"column",gap:5},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:13,fontWeight:600,color:"#111827"},children:t.label}),g?n.jsxs("span",{style:{fontSize:10,padding:"1px 7px",borderRadius:9,background:"#dcfce7",color:"#15803d",fontWeight:700},children:["SET (",h,")"]}):n.jsx("span",{style:{fontSize:10,padding:"1px 7px",borderRadius:9,background:"#fee2e2",color:"#b91c1c",fontWeight:700},children:"MISSING"}),t.hint&&n.jsxs("span",{style:{fontSize:10,color:"#6b7280"},children:["— ",t.hint]}),n.jsx("a",{href:t.href,target:"_blank",rel:"noopener noreferrer",style:{fontSize:11,color:"#2563eb",marginLeft:"auto"},children:"Get key →"})]}),n.jsxs("div",{style:{display:"flex",gap:6},children:[n.jsx("input",{value:r[t.id]??"",onChange:T=>l(w=>({...w,[t.id]:T.target.value})),placeholder:g?"●●●●●●●● (paste new value)":`Paste ${t.label} key`,type:"password",autoComplete:"off",style:Ok}),n.jsx("button",{onClick:()=>void d(t.id),disabled:p||!((S=r[t.id])!=null&&S.trim()),style:{...Wk,opacity:p||!((k=r[t.id])!=null&&k.trim())?.5:1,cursor:p||!((_=r[t.id])!=null&&_.trim())?"not-allowed":"pointer"},children:"Save"}),n.jsx("button",{onClick:()=>void u(t.id),disabled:!g||v==="loading",style:{...Hk,opacity:!g||v==="loading"?.5:1,cursor:!g||v==="loading"?"not-allowed":"pointer"},children:v==="loading"?"…":"Verify"})]}),v&&v!=="loading"&&n.jsxs("div",{style:{fontSize:11,color:v.valid?"#15803d":"#b91c1c"},children:[v.valid?"✓":"✗"," ",v.message]})]})}const Nk={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #e5e7eb",borderRadius:8},Bk={margin:"0 0 0.5rem 0",fontSize:15,fontWeight:600,color:"#111827"},ga={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},hc={fontSize:11,fontWeight:700,color:"#7c3aed",textTransform:"uppercase",letterSpacing:.5,marginBottom:6},uy={fontSize:11,fontWeight:600,color:"#374151"},Ok={flex:1,padding:"6px 10px",border:"1px solid #d1d5db",borderRadius:5,fontSize:13,boxSizing:"border-box",outline:"none"},Ik={padding:"6px 14px",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},$k={padding:"6px 14px",border:"1px solid #7c3aed",borderRadius:6,background:"#7c3aed",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},Hk={padding:"5px 10px",border:"1px solid #d1d5db",borderRadius:5,background:"#fff",cursor:"pointer",fontSize:12},Wk={padding:"5px 12px",border:"1px solid #c7d2fe",borderRadius:6,background:"#fff",color:"#4338ca",fontSize:12,fontWeight:600,cursor:"pointer"},Uk={cloud:"☁️",ollama:"🦙",byoe:"🔌",huggingface:"🤗"},fy={reachable:"#16a34a",unreachable:"#dc2626",untested:"#9ca3af"};function qk(){const{toast:t}=et(),[o,r]=x.useState([]),[l,c]=x.useState([]),[d,u]=x.useState(!0),[p,g]=x.useState({}),[h,v]=x.useState(!1),[y,b]=x.useState(null),[S,k]=x.useState({}),[_,T]=x.useState({}),[w,C]=x.useState("cloud"),[j,L]=x.useState(""),[W,P]=x.useState(""),[z,M]=x.useState(""),[q,K]=x.useState(""),[D,Y]=x.useState(!1),H=async()=>{u(!0);try{const O=await Db();r(O.providers)}catch{}finally{u(!1)}};x.useEffect(()=>{H(),Lj().then(O=>c(O.providers)).catch(()=>{})},[]);const A=async O=>{var F;const $=((F=o.find(I=>I.id===O))==null?void 0:F.name)??"provider";g(I=>({...I,[O]:!0})),t(`Testing '${$}'...`,"info");try{const I=await Mj(O);t(I.message,I.valid?"success":"error"),await H()}catch(I){t(I instanceof Error?I.message:"Test failed","error")}g(I=>({...I,[O]:!1}))},G=async(O,$)=>{if(window.confirm(`Delete provider "${$}"?`))try{await Aj(O),t(`${$} deleted`,"success"),b(null),await H()}catch(F){t(F instanceof Error?F.message:"Delete failed","error")}},R=async(O,$)=>{try{await ny(O,{enabled:$?1:0}),await H()}catch{}},X=async(O,$,F)=>{if($==="name"&&!F.trim()){t("Provider name cannot be empty","error");return}T(I=>({...I,[`${O}_${$}`]:!0}));try{await ny(O,{[$]:F}),t(`${$} updated`,"success"),k(I=>{const J={...I};return delete J[`${O}_${$}`],J}),await H()}catch(I){t(I instanceof Error?I.message:"Save failed","error")}T(I=>({...I,[`${O}_${$}`]:!1}))},B=async()=>{if(!W.trim()){t("Name is required","error");return}Y(!0);try{const O=l.find($=>$.id===j);await Rj({name:W,provider_type:w,provider_id:w==="cloud"?j:w,base_url:z||((O==null?void 0:O.base_url)??""),api_key:q}),t(`${W} added`,"success"),v(!1),P(""),M(""),K(""),L(""),await H()}catch(O){t(O instanceof Error?O.message:"Add failed","error")}Y(!1)},V=async()=>{t("Scanning for Ollama...","info");try{const O=await Dj();if(O.detected.length===0){t("No Ollama instances found","error");return}const $=O.detected[0];C("ollama"),P("Ollama"),M($.url),v(!0),t(`Found Ollama at ${$.url} with ${$.models.length} model(s)`,"success")}catch{t("Detection failed","error")}},Q=(O,$,F,I="text",J="")=>{const ne=`${O.id}_${$}`,se=ne in S,pe=S[ne]??"",_e=_[ne],we=$==="api_key"?"":O[$]||"",ke=se?pe:$==="api_key"?"":we,te=$==="name"&&se&&!pe.trim();return n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:{fontSize:10,fontWeight:600,color:"#6b7280",display:"block",marginBottom:2},children:F}),n.jsxs("div",{style:{display:"flex",gap:4},children:[n.jsx("input",{type:I,value:ke,onChange:de=>k(Ce=>({...Ce,[ne]:de.target.value})),placeholder:$==="api_key"?O.api_key_set?"•••••••• (paste new to replace)":"Paste API key...":J||we,style:{flex:1,padding:"4px 8px",fontSize:12,borderRadius:4,border:`1px solid ${te?"#f87171":"#d1d5db"}`,fontFamily:I==="password"?"monospace":void 0}}),se&&n.jsx("button",{onClick:()=>X(O.id,$,pe),disabled:_e||te,style:{padding:"4px 10px",fontSize:11,border:"none",borderRadius:4,background:te?"#9ca3af":"#2563eb",color:"#fff",cursor:te?"not-allowed":"pointer",fontWeight:600},children:_e?"...":"Save"})]}),te&&n.jsx("div",{style:{fontSize:10,color:"#ef4444",marginTop:2},children:"Name cannot be empty"})]})},N={border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"};return n.jsxs("section",{style:N,children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12},children:[n.jsx("h3",{style:{margin:0,fontSize:15,fontWeight:700},children:"🔗 Provider Registry"}),n.jsxs("div",{style:{display:"flex",gap:6},children:[n.jsx("button",{onClick:V,style:{padding:"4px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:"#fff"},children:"🦙 Detect Ollama"}),n.jsx("button",{onClick:()=>v(!0),style:{padding:"4px 10px",fontSize:11,border:"none",borderRadius:4,cursor:"pointer",background:"#2563eb",color:"#fff",fontWeight:600},children:"+ Add Provider"})]})]}),d&&n.jsx("div",{style:{color:"#9ca3af",fontSize:12},children:"Loading..."}),n.jsxs("div",{style:{display:"grid",gap:8},children:[o.map(O=>{const $=y===O.id;return n.jsxs("div",{style:{border:"1px solid #e5e7eb",borderRadius:6,overflow:"hidden",background:O.enabled?"#f0fdf4":"#fafafa"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"8px 12px",cursor:"pointer"},onClick:()=>b($?null:O.id),children:[n.jsx("span",{style:{fontSize:16},children:Uk[O.provider_type]||"🔗"}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center"},children:[n.jsx("span",{style:{fontWeight:600,fontSize:13},children:O.name}),n.jsx("span",{style:{fontSize:10,padding:"1px 5px",borderRadius:3,background:`${fy[O.status]||"#9ca3af"}20`,color:fy[O.status]||"#9ca3af",fontWeight:700},children:O.status}),O.api_key_set&&n.jsx("span",{style:{fontSize:9,padding:"1px 4px",borderRadius:3,background:"#dcfce7",color:"#166534"},children:"key set"}),O.available_models.length>0&&n.jsxs("span",{style:{fontSize:10,color:"#6b7280"},children:[O.available_models.length," model(s)"]})]}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:1},children:[(()=>{var J;const F=O.provider_type==="cloud"?((J=l.find(ne=>ne.id===O.provider_id))==null?void 0:J.label)??O.provider_id:O.provider_id,I=F&&F!==O.provider_type;return n.jsxs(n.Fragment,{children:[O.provider_type,I?` · ${F}`:""]})})(),O.base_url&&n.jsxs("span",{children:[" · ",O.base_url.replace(/https?:\/\//,"").slice(0,40)]})]})]}),n.jsx("input",{type:"checkbox",checked:!!O.enabled,onChange:F=>{F.stopPropagation(),R(O.id,F.target.checked)},style:{width:14,height:14,cursor:"pointer"}}),n.jsx("button",{onClick:F=>{F.stopPropagation(),A(O.id)},disabled:p[O.id],style:{padding:"3px 8px",fontSize:10,border:"1px solid #d1d5db",borderRadius:3,cursor:"pointer",background:"#fff"},children:p[O.id]?"...":"Test"}),n.jsx("span",{style:{fontSize:10,color:"#9ca3af",transform:$?"rotate(90deg)":"rotate(0deg)",transition:"transform 0.15s"},children:"▶"})]}),$&&n.jsxs("div",{style:{padding:"8px 12px 12px",borderTop:"1px solid #e5e7eb",background:"#f8fafc"},children:[Q(O,"name","Name","text","Provider name"),Q(O,"base_url","Base URL","text","https://api.openai.com/v1"),Q(O,"api_key","API Key","password","sk-..."),O.available_models.length>0&&n.jsxs("div",{style:{marginBottom:8},children:[n.jsx("label",{style:{fontSize:10,fontWeight:600,color:"#6b7280",display:"block",marginBottom:4},children:"Available Models"}),n.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:[O.available_models.slice(0,20).map(F=>n.jsx("span",{style:{fontSize:10,padding:"2px 6px",background:"#e0f2fe",color:"#0369a1",borderRadius:3,fontFamily:"monospace"},children:F},F)),O.available_models.length>20&&n.jsxs("span",{style:{fontSize:10,color:"#9ca3af"},children:["+",O.available_models.length-20," more"]})]})]}),n.jsxs("div",{style:{display:"flex",gap:6,marginTop:8},children:[n.jsx("button",{onClick:()=>A(O.id),disabled:p[O.id],style:{padding:"4px 12px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:"#fff"},children:p[O.id]?"Testing...":"↻ Refresh Models"}),n.jsx("button",{onClick:()=>G(O.id,O.name),style:{padding:"4px 12px",fontSize:11,border:"1px solid #fca5a5",borderRadius:4,cursor:"pointer",background:"#fef2f2",color:"#dc2626",marginLeft:"auto"},children:"Delete Provider"})]})]})]},O.id)}),!d&&o.length===0&&n.jsx("div",{style:{textAlign:"center",padding:20,color:"#9ca3af",fontSize:12},children:'No providers configured. Click "Add Provider" to get started.'})]}),h&&n.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.3)",zIndex:1e3,display:"flex",alignItems:"center",justifyContent:"center"},onClick:()=>v(!1),children:n.jsxs("div",{style:{background:"#fff",borderRadius:10,padding:24,width:440,maxHeight:"80vh",overflow:"auto"},onClick:O=>O.stopPropagation(),children:[n.jsx("h4",{style:{margin:"0 0 12px"},children:"Add Provider"}),n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"Type"}),n.jsxs("select",{value:w,onChange:O=>{C(O.target.value),L(""),M("")},style:{width:"100%",padding:"6px 8px",borderRadius:4,border:"1px solid #d1d5db",marginBottom:10,fontSize:13},children:[n.jsx("option",{value:"cloud",children:"☁️ Cloud (OpenAI, Anthropic, Mistral, ...)"}),n.jsx("option",{value:"ollama",children:"🦙 Ollama (local)"}),n.jsx("option",{value:"byoe",children:"🔌 BYOE (vLLM, LM Studio, custom endpoint)"}),n.jsx("option",{value:"huggingface",children:"🤗 HuggingFace Inference"})]}),w==="cloud"&&n.jsxs(n.Fragment,{children:[n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"Provider"}),n.jsxs("select",{value:j,onChange:O=>{const $=O.target.value;L($);const F=l.find(I=>I.id===$);F&&(P(F.label),M(F.base_url))},style:{width:"100%",padding:"6px 8px",borderRadius:4,border:"1px solid #d1d5db",marginBottom:10,fontSize:13},children:[n.jsx("option",{value:"",children:"Select..."}),l.map(O=>n.jsx("option",{value:O.id,children:O.label},O.id))]})]}),n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"Name"}),n.jsx("input",{value:W,onChange:O=>P(O.target.value),placeholder:"My vLLM server",style:{width:"100%",padding:"6px 8px",borderRadius:4,border:"1px solid #d1d5db",marginBottom:10,fontSize:13}}),n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"Base URL"}),n.jsx("input",{value:z,onChange:O=>M(O.target.value),placeholder:w==="ollama"?"http://localhost:11434":"http://BitConcepts:8000/v1",style:{width:"100%",padding:"6px 8px",borderRadius:4,border:"1px solid #d1d5db",marginBottom:10,fontSize:13}}),n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"API Key (optional)"}),n.jsx("input",{value:q,onChange:O=>K(O.target.value),type:"password",placeholder:"sk-...",style:{width:"100%",padding:"6px 8px",borderRadius:4,border:"1px solid #d1d5db",marginBottom:16,fontSize:13}}),n.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end"},children:[n.jsx("button",{onClick:()=>v(!1),style:{padding:"6px 14px",borderRadius:4,border:"1px solid #d1d5db",cursor:"pointer",background:"#fff",fontSize:12},children:"Cancel"}),n.jsx("button",{onClick:B,disabled:D,style:{padding:"6px 14px",borderRadius:4,border:"none",cursor:"pointer",background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600},children:D?"Saving...":"Add Provider"})]})]})})]})}const py={ollama:{icon:"🦙",label:"Ollama",bg:"#fef3c7",color:"#92400e"},cloud:{icon:"☁️",label:"Cloud",bg:"#dbeafe",color:"#1e40af"},byoe:{icon:"⚡",label:"vLLM/Custom",bg:"#f3e8ff",color:"#6b21a8"},huggingface:{icon:"🤗",label:"HuggingFace",bg:"#fce7f3",color:"#9d174d"}};function Gk(t,o){return t==="ollama"?"ollama":t==="huggingface"?"huggingface":o!=null&&o.includes(":11434")||o!=null&&o.toLowerCase().includes("ollama")?"ollama":t==="byoe"?"byoe":t}const Pk={reasoning:{label:"Reasoning",icon:"🧠",desc:"Decipher, hypotheses, experiment planning, discovery classification"},conversational:{label:"Conversational",icon:"💬",desc:"Chat, synthesis, general Q&A"},longform:{label:"Long-form",icon:"📝",desc:"Paper drafting, report generation"},global:{label:"Global Default",icon:"🌐",desc:"Used when no bucket-specific assignment exists"}};function Gi(t){return t?`${t.provider_registry_id}|${t.model}`:""}function Fk(){const{toast:t}=et(),[o,r]=x.useState([]),[l,c]=x.useState([]),[d,u]=x.useState([]),[p,g]=x.useState(!0),[h,v]=x.useState(!1),[y,b]=x.useState(!1),[S,k]=x.useState(!1),[_,T]=x.useState(!1),[w,C]=x.useState(!1),[j,L]=x.useState(()=>localStorage.getItem("glossa_assignment_filter")||"mixed"),W=F=>{L(F),localStorage.setItem("glossa_assignment_filter",F)},[P,z]=x.useState({}),M=[];for(const F of o)for(const I of F.available_models||[])M.push({providerId:F.id,providerName:F.name,model:I,providerType:Gk(F.provider_type,F.base_url),baseUrl:F.base_url});const q=M.filter(F=>j==="cloud"?F.providerType==="cloud":j==="local"?F.providerType==="ollama"||F.providerType==="byoe":!0),K=F=>{const I={};for(const J of F)I[`${J.bucket}_primary`]=Gi(J.primary),I[`${J.bucket}_fallback`]=Gi(J.fallback);return I},D=async()=>{g(!0);try{const[F,I,J]=await Promise.all([Db(!0),Nj(),Lb()]);r(F.providers),c(I.assignments),u(J.scores),z(K(I.assignments))}catch{}g(!1)};x.useEffect(()=>{D()},[]);const Y=(F,I)=>{const J=l.find(ne=>ne.bucket===F);return I==="primary"?J==null?void 0:J.primary:J==null?void 0:J.fallback},H=F=>{const I=[F];if(F.includes("/")&&I.push(F.split("/").slice(1).join("/")),F.includes(":")){const J=F.split(":")[0],ne=F.split(":")[1];I.push(`${J}-${ne}`),I.push(J)}I.push(F.replace(/\./g,"-").replace(/:/,"-")),I.push(F.replace(/\./g,"").replace(/:/,"-"));for(const J of I){const ne=d.find(se=>se.model_name===J||J.toLowerCase().includes(se.model_name.toLowerCase())||se.model_name.toLowerCase().includes(J.toLowerCase()));if(ne)return ne}},A=(()=>{for(const F of l){const I=`${F.bucket}_primary`,J=`${F.bucket}_fallback`;if(P[I]!==Gi(F.primary)||P[J]!==Gi(F.fallback))return!0}for(const F of Object.keys(P))if(P[F]){const[I,J]=F.split("_"),ne=l.find(pe=>pe.bucket===I),se=Gi(J==="primary"?ne==null?void 0:ne.primary:ne==null?void 0:ne.fallback);if(P[F]!==se)return!0}return!1})(),G=(F,I,J)=>{z(ne=>({...ne,[`${F}_${I}`]:J}))},R=async()=>{v(!0);const F=["reasoning","conversational","longform","global"];let I=!1;for(const J of F){const ne=P[`${J}_primary`]??"",se=P[`${J}_fallback`]??"",[pe,..._e]=ne.split("|"),we=_e.join("|"),[ke,...te]=se.split("|"),de=te.join("|"),Ce=l.find(De=>De.bucket===J),ze=Gi(Ce==null?void 0:Ce.primary),ve=Gi(Ce==null?void 0:Ce.fallback);if(!(ne===ze&&se===ve))try{await Bj(J,{primary_provider_id:pe||"",primary_model:we||"",fallback_provider_id:ke||"",fallback_model:de||""})}catch(De){t(`${J}: ${De instanceof Error?De.message:"Save failed"}`,"error"),I=!0}}await D(),I||t("Model assignments saved","success"),v(!1)},X=()=>{z(K(l)),t("Changes reverted","info")},B=async()=>{T(!0);try{const F=await Oj(j);F.configured?(t(`Auto-configured (${j}) model assignments`,"success"),await D()):t(F.message||"No models available","error")}catch(F){t(F instanceof Error?F.message:"Auto-configure failed","error")}T(!1)},V=F=>{const I=`${F}_primary`,J=`${F}_fallback`,ne=P[I]??"",se=P[J]??"";!ne&&!se||(z(pe=>({...pe,[I]:se,[J]:ne})),t(`${F} primary ↔ fallback swapped (not saved yet)`,"info"))},Q=async()=>{b(!0),t("🔄 Syncing model scores from HuggingFace...","info");try{const F=await Nb();t(F.message,F.message.includes("unreachable")||F.message.includes("static")?"info":"success"),await D()}catch(F){t(F instanceof Error?F.message:"Sync failed","error")}b(!1)},N=async()=>{k(!0);try{const F=await Ij();t(F.message,F.valid?"success":"error")}catch(F){t(F instanceof Error?F.message:"HF test failed","error")}k(!1)},O={section:{border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"}},$=(F,I)=>{const J=P[`${F}_${I}`]??"",ne=Gi(Y(F,I)),se=J!==ne,pe=h;return n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:6},children:[n.jsxs("span",{style:{fontSize:10,fontWeight:600,color:I==="primary"?"#2563eb":"#9ca3af",width:55,flexShrink:0},children:[I==="primary"?"⚡ Primary":"⚠️ Fallback",se&&n.jsx("span",{style:{color:"#f59e0b",marginLeft:2},children:"●"})]}),n.jsxs("select",{value:J,onChange:_e=>G(F,I,_e.target.value),disabled:pe,style:{flex:1,minWidth:0,fontSize:12,padding:"4px 6px",borderRadius:4,border:"1px solid #d1d5db",background:pe?"#f3f4f6":"#fff",textOverflow:"ellipsis"},children:[n.jsx("option",{value:"",children:"— not set —"}),q.map(_e=>{const we=H(_e.model),te=we?we[F==="conversational"?"conversational_score":F==="longform"?"longform_score":"reasoning_score"]??0:0;return{..._e,scoreVal:te,hasScore:!!we}}).filter(_e=>!w||_e.hasScore).sort((_e,we)=>we.scoreVal-_e.scoreVal).map(_e=>{var we;return n.jsxs("option",{value:`${_e.providerId}|${_e.model}`,children:[((we=py[_e.providerType])==null?void 0:we.icon)??"🔌"," ",_e.scoreVal>0?`★${_e.scoreVal.toFixed(0)} `:_e.hasScore?"☆0 ":"",_e.providerName," · ",_e.model]},`${_e.providerId}|${_e.model}`)})]})]})};return n.jsxs("section",{style:O.section,children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12},children:[n.jsx("h3",{style:{margin:0,fontSize:15,fontWeight:700},children:"🎯 Model Assignments"}),n.jsxs("div",{style:{display:"flex",gap:6},children:[n.jsx("button",{onClick:N,disabled:S,style:{padding:"4px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:"#fff"},children:S?"Testing...":"🤗 Test HF"}),n.jsx("button",{onClick:Q,disabled:y,style:{padding:"4px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:"#fff"},children:y?"Syncing...":"🔄 Sync Scores"}),n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:2},children:[n.jsx("span",{style:{fontSize:10,color:"#9ca3af",flexShrink:0},children:"Filter:"}),n.jsxs("select",{value:j,onChange:F=>W(F.target.value),style:{fontSize:11,padding:"3px 4px",borderRadius:4,border:"1px solid #d1d5db",background:"#fff"},children:[n.jsx("option",{value:"mixed",children:"🔀 All"}),n.jsx("option",{value:"cloud",children:"☁️ Cloud only"}),n.jsx("option",{value:"local",children:"🖥️ Local only"})]})]}),n.jsx("button",{onClick:B,disabled:_,style:{padding:"4px 10px",fontSize:11,border:"none",borderRadius:4,cursor:"pointer",background:"#7c3aed",color:"#fff",fontWeight:600},children:_?"Configuring...":"✨ Auto-Configure"})]})]}),p&&n.jsx("div",{style:{color:"#9ca3af",fontSize:12},children:"Loading..."}),M.length===0&&!p&&n.jsx("div",{style:{textAlign:"center",padding:16,color:"#9ca3af",fontSize:12,background:"#f9fafb",borderRadius:6},children:'No models available. Add providers above and click "Test" to fetch model lists.'}),n.jsx("div",{style:{display:"grid",gap:10,gridTemplateColumns:"1fr 1fr",minWidth:0},children:["reasoning","conversational","longform","global"].map(F=>{const I=Pk[F],J=!!(P[`${F}_primary`]||Y(F,"primary"))&&!!(P[`${F}_fallback`]||Y(F,"fallback"));return n.jsxs("div",{style:{border:"1px solid #e5e7eb",borderRadius:6,padding:12,background:"#fafafa",minWidth:0,overflow:"hidden"},children:[n.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center",marginBottom:8},children:[n.jsx("span",{style:{fontSize:16},children:I.icon}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsx("div",{style:{fontWeight:700,fontSize:13},children:I.label}),n.jsx("div",{style:{fontSize:10,color:"#6b7280"},children:I.desc})]}),J&&n.jsx("button",{onClick:()=>V(F),disabled:h,title:"Swap primary ↔ fallback (draft)",style:{padding:"2px 6px",fontSize:11,border:"1px solid #d1d5db",borderRadius:3,cursor:"pointer",background:"#fff",color:"#6b7280",flexShrink:0},children:"⇅"})]}),$(F,"primary"),$(F,"fallback")]},F)})}),n.jsxs("div",{style:{marginTop:10,display:"flex",alignItems:"center",gap:8,padding:"8px 12px",borderRadius:6,background:A?"#fffbeb":"#f9fafb",border:`1px solid ${A?"#fcd34d":"#e5e7eb"}`,transition:"background 0.2s, border-color 0.2s"},children:[n.jsx("span",{style:{fontSize:12,color:A?"#92400e":"#9ca3af",flex:1},children:A?"⚠️ Unsaved changes":"✓ All changes saved"}),n.jsx("button",{onClick:X,disabled:!A||h,style:{padding:"4px 12px",fontSize:12,border:"1px solid #d1d5db",borderRadius:4,cursor:A&&!h?"pointer":"not-allowed",background:"#fff",color:A?"#374151":"#9ca3af",opacity:A?1:.5},children:"Revert"}),n.jsx("button",{onClick:R,disabled:!A||h,style:{padding:"4px 16px",fontSize:12,border:"none",borderRadius:4,cursor:A&&!h?"pointer":"not-allowed",background:A?"#2563eb":"#93c5fd",color:"#fff",fontWeight:700,opacity:A?1:.6},children:h?"Saving…":"✓ Apply"})]}),n.jsxs("div",{style:{marginTop:12,display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[d.length>0&&n.jsxs("span",{style:{fontSize:10,color:"#9ca3af"},children:["📊 ",d.length," model(s) scored · ★ = bucket fitness score (higher = better)"]}),n.jsxs("label",{style:{display:"flex",alignItems:"center",gap:4,fontSize:11,color:"#6b7280",cursor:"pointer"},children:[n.jsx("input",{type:"checkbox",checked:w,onChange:F=>C(F.target.checked)}),"Scored models only"]}),n.jsx("div",{style:{display:"flex",gap:4,marginLeft:"auto",flexWrap:"wrap"},children:Object.values(py).map(F=>n.jsxs("span",{style:{fontSize:10,padding:"2px 6px",borderRadius:3,background:F.bg,color:F.color,fontWeight:600},children:[F.icon," ",F.label]},F.label))})]})]})}const Ko=new Map,Yk=[{label:"All",max:999},{label:"≤ 4 GB",max:4},{label:"≤ 8 GB",max:8},{label:"≤ 12 GB",max:12},{label:"≤ 16 GB",max:16},{label:"≤ 24 GB",max:24}],Vk={excellent:"#16a34a",great:"#2563eb",good:"#ca8a04"};function Xk(){const{toast:t}=et(),[o,r]=x.useState([]),[l,c]=x.useState(null),[d,u]=x.useState([]),[p,g]=x.useState(!0),[h,v]=x.useState(!1),[y,b]=x.useState(-1),[S,k]=x.useState(()=>{const Y={};for(const[H,A]of Ko)Y[H]={pct:A.pct,status:A.status};return Y}),[_,T]=x.useState({set:!1,editing:!1,value:""}),w=async()=>{g(!0);try{const[Y,H,A]=await Promise.all([G2(),P2().catch(()=>null),Lb()]);r(Y.models),v(Y.running),c(H),u(A.scores);try{const G=await ad();T(R=>{var X,B;return{...R,set:((B=(X=G.keys)==null?void 0:X.hf_api_token)==null?void 0:B.set)??!1}})}catch{}H&&H.vram_gb>0&&y===-1?b(-1):y===-1&&b(999)}catch{}g(!1)};x.useEffect(()=>{w()},[]);const C=Y=>d.find(H=>H.model_name===Y||Y.includes(H.model_name)||H.model_name.includes(Y)),j=Y=>{if(Ko.has(Y))return;const H={pct:0,status:"connecting…"},A=new EventSource(`/api/v1/ollama/pull/${encodeURIComponent(Y)}`);Ko.set(Y,{es:A,...H}),k(G=>({...G,[Y]:H})),A.onmessage=G=>{try{const R=JSON.parse(G.data);if(R.error){t(`Pull failed: ${R.error}`,"error"),Ko.delete(Y),k(Q=>{const N={...Q};return delete N[Y],N}),A.close();return}if(R.status==="success"){t(`${Y} downloaded`,"success"),Ko.delete(Y),k(Q=>{const N={...Q};return delete N[Y],N}),A.close(),w();return}const X=R.total&&R.completed?Math.round(R.completed/R.total*100):0,B=R.status||"downloading…",V=Ko.get(Y);V&&(V.pct=X,V.status=B),k(Q=>({...Q,[Y]:{pct:X,status:B}}))}catch{}},A.onerror=()=>{Ko.delete(Y),k(G=>{const R={...G};return delete R[Y],R}),A.close()}},L=async()=>{try{await sr({hf_api_token:_.value}),T({set:!0,editing:!1,value:""}),t("HF token saved — click Sync Scores to fetch leaderboard data","success")}catch(Y){t(Y instanceof Error?Y.message:"Save failed","error")}},W=async()=>{try{const Y=await Nb();t(Y.message,"success"),w()}catch(Y){t(Y instanceof Error?Y.message:"Sync failed","error")}},P=async Y=>{if(confirm(`Delete ${Y}?`))try{await F2(Y),t(`${Y} deleted`,"success"),w()}catch(H){t(H instanceof Error?H.message:"Delete failed","error")}},z=(l==null?void 0:l.vram_gb)??0,M=y===-1?z:y,q=y!==999&&!(y===-1&&z===0),K=o.slice().sort((Y,H)=>{if(q){const A=Y.min_vram_gb<=M?0:1,G=H.min_vram_gb<=M?0:1;if(A!==G)return A-G}return H.glossa_score-Y.glossa_score||Y.min_vram_gb-H.min_vram_gb}),D={section:{border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"}};return n.jsxs("section",{style:D.section,children:[n.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10},children:[n.jsx("h3",{style:{margin:0,fontSize:15,fontWeight:700},children:"🏪 Model Hub"}),n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[n.jsx("span",{style:{width:8,height:8,borderRadius:"50%",background:h?"#16a34a":"#ef4444"}}),n.jsx("span",{style:{fontSize:11,color:"#6b7280"},children:h?"Ollama running":"Ollama offline"})]})]}),n.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center",marginBottom:10,fontSize:11},children:[n.jsx("span",{style:{color:"#6b7280"},children:"HuggingFace token:"}),_.editing?n.jsxs(n.Fragment,{children:[n.jsx("input",{value:_.value,onChange:Y=>T(H=>({...H,value:Y.target.value})),placeholder:"hf_...",type:"password",style:{flex:1,maxWidth:220,padding:"2px 6px",border:"1px solid #d1d5db",borderRadius:4,fontSize:11}}),n.jsx("button",{onClick:L,style:{padding:"2px 8px",fontSize:10,border:"none",borderRadius:4,background:"#2563eb",color:"#fff",cursor:"pointer"},children:"Save"}),n.jsx("button",{onClick:()=>T(Y=>({...Y,editing:!1,value:""})),style:{padding:"2px 8px",fontSize:10,border:"1px solid #d1d5db",borderRadius:4,background:"#fff",cursor:"pointer"},children:"Cancel"})]}):n.jsxs(n.Fragment,{children:[n.jsx("span",{style:{color:_.set?"#16a34a":"#9ca3af"},children:_.set?"set ✓":"not set"}),n.jsx("button",{onClick:()=>T(Y=>({...Y,editing:!0})),style:{padding:"2px 8px",fontSize:10,border:"1px solid #d1d5db",borderRadius:4,background:"#fff",cursor:"pointer"},children:_.set?"Change":"Add"}),n.jsx("button",{onClick:W,style:{padding:"2px 8px",fontSize:10,border:"1px solid #d1d5db",borderRadius:4,background:"#fff",cursor:"pointer"},children:"🔄 Sync from HF"}),!_.set&&n.jsx("span",{style:{color:"#9ca3af",fontSize:10},children:"Optional — free at huggingface.co/settings/tokens"})]})]}),l&&l.vram_gb>0&&n.jsxs("div",{style:{background:"#f0fdf4",border:"1px solid #86efac",borderRadius:6,padding:"8px 12px",marginBottom:10,fontSize:11,color:"#166534"},children:["🖥️ ",n.jsx("strong",{children:l.gpu_name})," — ",l.vram_gb," GB VRAM · Recommended: ",n.jsx("strong",{children:l.recommended.display})]}),n.jsxs("div",{style:{display:"flex",gap:4,marginBottom:12,flexWrap:"wrap"},children:[z>0&&n.jsxs("button",{onClick:()=>b(-1),style:{padding:"3px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:y===-1?"#16a34a":"#fff",color:y===-1?"#fff":"#374151",fontWeight:y===-1?700:400},children:["🖥️ My GPU (",z," GB)"]}),Yk.map(Y=>n.jsx("button",{onClick:()=>b(Y.max),style:{padding:"3px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:y===Y.max?"#2563eb":"#fff",color:y===Y.max?"#fff":"#374151",fontWeight:y===Y.max?700:400},children:Y.label},Y.max)),n.jsxs("span",{style:{fontSize:10,color:"#9ca3af",alignSelf:"center",marginLeft:4},children:[K.length," model",K.length!==1?"s":""]})]}),p&&n.jsx("div",{style:{color:"#9ca3af",fontSize:12,padding:16,textAlign:"center"},children:"Loading…"}),!p&&!h&&n.jsxs("div",{style:{textAlign:"center",padding:20,color:"#9ca3af",fontSize:12,background:"#fef2f2",border:"1px solid #fca5a5",borderRadius:6},children:["Ollama is not running. Install from ",n.jsx("a",{href:"https://ollama.com",target:"_blank",rel:"noopener noreferrer",children:"ollama.com"})," and start it to download models."]}),!p&&K.map(Y=>{const H=C(Y.name),A=S[Y.name],G=!q||Y.min_vram_gb<=M,R=q&&!G;return n.jsxs("div",{style:{display:"flex",gap:10,alignItems:"flex-start",padding:"10px 0",borderBottom:"1px solid #f3f4f6",opacity:R?.45:1},children:[n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,flexWrap:"wrap"},children:[n.jsx("span",{style:{fontSize:13,fontWeight:700},children:Y.display}),n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:Vk[Y.quality]||"#6b7280",color:"#fff",fontWeight:600},children:Y.quality}),Y.installed&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#16a34a",color:"#fff",fontWeight:600},children:"installed"}),Y.tags.includes("top-pick")&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#f59e0b",color:"#78350f",fontWeight:700},children:"⭐ TOP PICK"}),Y.tags.includes("moe")&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#8b5cf6",color:"#fff",fontWeight:600},children:"MoE"}),R&&n.jsxs("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#ef4444",color:"#fff",fontWeight:600},children:["needs ≥",Y.min_vram_gb," GB"]})]}),n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:Y.desc}),n.jsxs("div",{style:{display:"flex",gap:10,marginTop:3,fontSize:10,color:"#9ca3af"},children:[n.jsxs("span",{children:[Y.param_b,"B params"]}),n.jsxs("span",{children:[Y.size_gb," GB"]}),n.jsxs("span",{children:["≥",Y.min_vram_gb," GB VRAM"]}),H&&n.jsxs(n.Fragment,{children:[n.jsxs("span",{title:"Reasoning",children:["🧠",H.reasoning_score.toFixed(0)]}),n.jsxs("span",{title:"Conversational",children:["💬",H.conversational_score.toFixed(0)]}),n.jsxs("span",{title:"Long-form",children:["📝",H.longform_score.toFixed(0)]})]})]}),A&&n.jsxs("div",{style:{marginTop:4},children:[n.jsx("div",{style:{height:4,background:"#e5e7eb",borderRadius:2,overflow:"hidden"},children:n.jsx("div",{style:{height:"100%",width:`${A.pct}%`,background:"#2563eb",transition:"width 0.3s"}})}),n.jsxs("div",{style:{fontSize:9,color:"#6b7280",marginTop:1},children:[A.status," ",A.pct>0?`${A.pct}%`:""]})]})]}),n.jsx("div",{style:{display:"flex",gap:4,flexShrink:0,alignItems:"center"},children:Y.installed?n.jsx("button",{onClick:()=>P(Y.name),style:{padding:"3px 8px",fontSize:10,border:"1px solid #fca5a5",borderRadius:4,background:"#fff",color:"#dc2626",cursor:"pointer"},children:"🗑️ Delete"}):n.jsx("button",{onClick:()=>j(Y.name),disabled:!h||!!A,style:{padding:"3px 10px",fontSize:10,border:"none",borderRadius:4,cursor:h&&!A?"pointer":"not-allowed",background:h&&!A?"#2563eb":"#e5e7eb",color:h&&!A?"#fff":"#9ca3af",fontWeight:600},children:A?"Pulling…":"⬇ Pull"})})]},Y.name)}),h&&n.jsx(Jk,{onPull:j,pulling:S})]})}function Jk({onPull:t,pulling:o}){const[r,l]=x.useState("");return n.jsxs("div",{style:{marginTop:10,display:"flex",gap:6,alignItems:"center"},children:[n.jsx("input",{value:r,onChange:c=>l(c.target.value),placeholder:"any-model:tag",style:{flex:1,fontSize:11,padding:"4px 8px",border:"1px solid #d1d5db",borderRadius:4},onKeyDown:c=>{c.key==="Enter"&&r.trim()&&(t(r.trim()),l(""))}}),n.jsx("button",{onClick:()=>{r.trim()&&(t(r.trim()),l(""))},disabled:!r.trim()||!!o[r.trim()],style:{padding:"4px 10px",fontSize:10,border:"none",borderRadius:4,background:"#7c3aed",color:"#fff",cursor:"pointer",fontWeight:600},children:"Pull custom"})]})}function Kk(){const{toast:t}=et(),[o,r]=x.useState(null),[l,c]=x.useState(!0),[d,u]=x.useState(!1),[p,g]=x.useState([]),[h,v]=x.useState(null),[y,b]=x.useState(!0),[S,k]=x.useState(!0),_=x.useRef(null),T=async()=>{c(!0);try{r(await kb())}catch{}finally{c(!1)}};x.useEffect(()=>{T()},[]),x.useEffect(()=>{const z=_.current;z&&(z.scrollTop=z.scrollHeight)},[p]);const w=async(z,M)=>{u(!0),g([{text:`Running: ${M}…`,type:"info"}]);try{const q=await z();if(!q.body){g(H=>[...H,{text:"No response body",type:"error"}]);return}const K=q.body.getReader(),D=new TextDecoder;let Y="";for(;;){const{done:H,value:A}=await K.read();if(H)break;Y+=D.decode(A,{stream:!0});const G=Y.split(` - -`);Y=G.pop()??"";for(const R of G)for(const X of R.split(` -`))if(X.startsWith("data: "))try{const B=JSON.parse(X.slice(6));if(B.text){const V=B.text.toLowerCase().includes("error")||B.text.startsWith("⚠"),Q=B.text.startsWith("✓");g(N=>[...N,{text:B.text,type:V?"error":Q?"success":"output"}])}}catch{}else X.startsWith("event: done")||X.startsWith("event: error")}await T(),t(`${M} complete`,"success")}catch(q){g(K=>[...K,{text:`Failed: ${q instanceof Error?q.message:String(q)}`,type:"error"}]),t(`${M} failed`,"error")}finally{u(!1)}},C=async()=>{if(h!==null){v(null);return}const z=await ij();v(z.packages),k(!0)},j=o==null?void 0:o.venv_exists,L=l?"#9ca3af":j?"#16a34a":"#ef4444",W=l?"checking…":j?`Active · Python ${(o==null?void 0:o.python_version)??"?"}`:"Not found",P=(z,M)=>({padding:"5px 12px",border:"none",borderRadius:5,background:M?"#e5e7eb":z,color:M?"#9ca3af":"#fff",cursor:M?"not-allowed":"pointer",fontSize:12,fontWeight:600});return n.jsxs("section",{style:n3,children:[n.jsx("h3",{style:{margin:"0 0 10px",fontSize:15,fontWeight:600,color:"#111827"},children:"🐍 Python Environment"}),n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:12,padding:"10px 14px",background:j?"#f0fdf4":"#fef2f2",border:`1px solid ${j?"#86efac":"#fca5a5"}`,borderRadius:7},children:[n.jsx("span",{style:{width:9,height:9,borderRadius:"50%",background:L,flexShrink:0}}),n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:13,fontWeight:600,color:"#111827"},children:W}),(o==null?void 0:o.venv_path)&&n.jsx("div",{style:{fontSize:10,color:"#6b7280",fontFamily:"monospace",marginTop:1},children:o.venv_path}),j&&n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:[(o==null?void 0:o.pkg_count)??0," packages installed"]})]}),n.jsx("button",{onClick:T,style:{padding:"3px 8px",border:"1px solid #d1d5db",borderRadius:4,background:"#fff",cursor:"pointer",fontSize:11,color:"#6b7280"},children:"⟳"})]}),!j&&!l&&n.jsxs("div",{style:{padding:"12px 14px",background:"#fef3c7",border:"1px solid #fcd34d",borderRadius:6,marginBottom:12,fontSize:12,color:"#92400e"},children:["No virtual environment found. Click ",n.jsx("strong",{children:"Setup venv"})," to create one and install all dependencies."]}),n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:12},children:[n.jsx("button",{onClick:()=>w(oj,"Setup venv"),disabled:d,style:P("#16a34a",d),children:"⬇ Setup venv"}),n.jsx("button",{onClick:()=>w(sj,"Rebuild venv"),disabled:d,style:P("#ea580c",d),children:"↺ Rebuild venv"}),n.jsx("button",{onClick:()=>w(rj,"Upgrade deps"),disabled:d||!j,style:P("#2563eb",d||!j),children:"↑ Upgrade deps"}),n.jsx("button",{onClick:C,disabled:!j,style:P("#7c3aed",!j),title:h!==null?"Hide the package list (does not uninstall anything)":"Fetch and show installed packages",children:h!==null?"📦 Hide packages":"📦 Show packages"})]}),p.length>0&&n.jsxs("div",{style:{marginBottom:10},children:[n.jsxs("button",{onClick:()=>b(z=>!z),style:{display:"flex",alignItems:"center",gap:5,background:"none",border:"none",cursor:"pointer",padding:"2px 0",marginBottom:4,fontSize:11,fontWeight:700,color:"#374151",textTransform:"uppercase",letterSpacing:.5},children:[n.jsx("span",{style:{fontSize:9,transition:"transform .15s",transform:y?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),"Install output"]}),y&&n.jsx("div",{ref:_,style:{background:"#0f172a",borderRadius:5,padding:"8px 10px",maxHeight:200,overflowY:"auto",fontFamily:"monospace",fontSize:11},children:p.map((z,M)=>n.jsx("div",{style:{color:z.type==="error"?"#f87171":z.type==="success"?"#86efac":"#e2e8f0",lineHeight:1.6},children:z.text},M))})]}),h&&n.jsxs("div",{children:[n.jsxs("button",{onClick:()=>k(z=>!z),style:{display:"flex",alignItems:"center",gap:5,background:"none",border:"none",cursor:"pointer",padding:"2px 0",marginBottom:4,fontSize:11,fontWeight:700,color:"#374151",textTransform:"uppercase",letterSpacing:.5},children:[n.jsx("span",{style:{fontSize:9,transition:"transform .15s",transform:S?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),"Installed packages (",h.length,")"]}),S&&n.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:"2px 8px",maxHeight:140,overflowY:"auto"},children:h.map(z=>n.jsxs("span",{style:{fontSize:10,fontFamily:"monospace",color:"#374151"},children:[z.name," ",n.jsx("span",{style:{color:"#9ca3af"},children:z.version})]},z.name))})]})]})}const hy="glossa_settings_tab",gy=[{id:"ai",label:"AI",icon:"🤖"},{id:"discovery",label:"Discovery",icon:"🔭"},{id:"notifications",label:"Notifications",icon:"✉️"},{id:"system",label:"System",icon:"⚙️"}];function Qk(){const[t,o]=x.useState(()=>{const b=localStorage.getItem(hy);return b&&gy.some(S=>S.id===b)?b:"ai"}),r=b=>{o(b),localStorage.setItem(hy,b)},[l,c]=x.useState(""),[d,u]=x.useState(""),[p,g]=x.useState(""),[h,v]=x.useState(""),y=async()=>{try{const[b,S]=await Promise.all([ad(),Na()]);c(b.data_dir),u(S.version??"");const k=S.uptime_seconds??0,_=Math.floor(k/60),T=Math.floor(_/60);g(T>0?`${T}h ${_%60}m`:_>0?`${_}m`:`${Math.round(k)}s`),v("")}catch{}};return x.useEffect(()=>{y()},[]),n.jsxs("div",{style:{maxWidth:760},children:[n.jsx("h2",{style:{marginTop:0,marginBottom:12},children:"Settings"}),n.jsx("div",{style:{display:"flex",gap:2,borderBottom:"2px solid #e5e7eb",marginBottom:20},children:gy.map(b=>n.jsxs("button",{onClick:()=>r(b.id),style:{padding:"8px 16px",border:"none",cursor:"pointer",fontSize:13,fontWeight:t===b.id?700:500,color:t===b.id?"#2563eb":"#6b7280",background:t===b.id?"#eff6ff":"transparent",borderBottom:t===b.id?"2px solid #2563eb":"2px solid transparent",borderRadius:"6px 6px 0 0",marginBottom:-2},children:[b.icon," ",b.label]},b.id))}),h&&n.jsx("div",{style:{...t3,background:"#fef2f2",borderColor:"#fca5a5",color:"#991b1b"},children:h}),t==="ai"&&n.jsxs(n.Fragment,{children:[n.jsx(qk,{}),n.jsx(Fk,{}),n.jsx(Xk,{}),n.jsxs("section",{style:mp,children:[n.jsx("h3",{style:xp,children:"AI Behavior"}),n.jsx("p",{style:is,children:"Control how Glossa AI handles action proposals during chat."}),n.jsx(e3,{})]})]}),t==="discovery"&&n.jsx(Lk,{}),t==="notifications"&&n.jsx(Tk,{}),t==="system"&&n.jsxs(n.Fragment,{children:[n.jsx(Kk,{}),n.jsx(Zk,{}),n.jsxs("section",{style:mp,children:[n.jsx("h3",{style:xp,children:"System"}),n.jsx("table",{style:{borderCollapse:"collapse"},children:n.jsxs("tbody",{children:[n.jsx(Uf,{label:"Data directory",value:l||"—",mono:!0}),d&&n.jsx(Uf,{label:"Backend version",value:d}),p&&n.jsx(Uf,{label:"Backend uptime",value:p})]})}),n.jsx("p",{style:{...is,marginTop:10,color:"#9ca3af"},children:"Corpus, sign mapping, and pipeline settings are project-specific. Open or create a project to configure them."})]})]})]})}function Zk(){const{toast:t}=et(),[o,r]=x.useState(!1),l=async()=>{r(!0);try{const c=await h2();g2(),window.dispatchEvent(new CustomEvent("glossa:seq_queue_updated")),t(`${c.cleared_jobs} job(s) cleared — cache reset`,"success")}catch(c){t(c instanceof Error?c.message:"Clear failed","error")}finally{r(!1)}};return n.jsxs("section",{style:mp,children:[n.jsx("h3",{style:xp,children:"🗑 Clear Cache"}),n.jsx("p",{style:is,children:"Removes all non-running jobs from the database (completed, failed, paused, queued) and clears all run-related browser state:"}),n.jsxs("ul",{style:{...is,margin:"6px 0 0 16px",padding:0},children:[n.jsx("li",{children:"Experiment run badges (✓/✗) in the Builder"}),n.jsx("li",{children:"Sequential run queue"}),n.jsx("li",{children:"Dashboard AI insight + applied action state"})]}),n.jsxs("p",{style:{...is,marginTop:8,color:"#9ca3af"},children:[n.jsx("strong",{children:"Running jobs are never affected."})," Use this before re-running experiments to start completely clean."]}),n.jsx("button",{onClick:l,disabled:o,style:{marginTop:12,padding:"6px 16px",border:"none",borderRadius:5,background:o?"#e5e7eb":"#b45309",color:o?"#9ca3af":"#fff",cursor:o?"not-allowed":"pointer",fontSize:13,fontWeight:600},children:o?"Clearing…":"🗑 Clear Cache"})]})}const my="glossa_auto_approve";function e3(){const{toast:t}=et(),[o,r]=x.useState(()=>localStorage.getItem(my)==="true"),l=c=>{r(c),localStorage.setItem(my,c?"true":"false"),window.dispatchEvent(new CustomEvent("glossa:auto_approve_changed")),t(c?"Auto-approve enabled — Glossa AI will run all actions automatically":"Auto-approve disabled",c?"success":"info")};return n.jsxs("div",{style:{marginTop:12},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 14px",borderRadius:7,border:`1px solid ${o?"#fbbf24":"#e5e7eb"}`,background:o?"#fffbeb":"#fafafa"},children:[n.jsxs("div",{children:[n.jsxs("div",{style:{fontSize:13,fontWeight:600,color:o?"#92400e":"#374151",display:"flex",alignItems:"center",gap:6},children:[n.jsx("span",{style:{fontSize:15},children:o?"⚡":"✋"}),"Auto Approve All AI Actions",o&&n.jsx("span",{style:{fontSize:9,padding:"1px 6px",borderRadius:8,background:"#f59e0b",color:"#78350f",fontWeight:700},children:"ACTIVE"})]}),n.jsx("p",{style:{...is,marginTop:3},children:o?"Glossa AI will execute all proposed actions automatically without asking for approval. Click to disable.":"Glossa AI will ask for approval before executing actions. Toggle on to run all actions automatically."})]}),n.jsx("div",{onClick:()=>l(!o),title:o?"Click to disable auto-approve":"Click to enable auto-approve",style:{width:44,height:24,borderRadius:12,cursor:"pointer",flexShrink:0,background:o?"#f59e0b":"#d1d5db",position:"relative",transition:"background 0.2s"},children:n.jsx("div",{style:{position:"absolute",top:3,left:o?23:3,width:18,height:18,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 3px rgba(0,0,0,0.25)",transition:"left 0.2s"}})})]}),n.jsxs("p",{style:{...is,marginTop:6,color:"#9ca3af"},children:["You can also toggle auto-approve per-session from the ",n.jsx("strong",{children:"⚡ AUTO"})," badge in the Glossa AI chat header, or via the ",n.jsx("strong",{children:"▾"})," dropdown on any Approve button."]})]})}function Uf({label:t,value:o,mono:r}){return n.jsxs("tr",{children:[n.jsx("td",{style:{padding:"3px 16px 3px 0",fontSize:13,color:"#6b7280",whiteSpace:"nowrap"},children:t}),n.jsx("td",{style:{padding:"3px 0",fontSize:13,fontFamily:r?"monospace":void 0},children:o})]})}const mp={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #e5e7eb",borderRadius:8},xp={margin:"0 0 0.75rem 0",fontSize:15,fontWeight:600,color:"#111827"},is={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},t3={padding:"10px 14px",borderRadius:6,border:"1px solid",marginBottom:"1rem",fontSize:13},n3={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #d1fae5",borderRadius:8,background:"#fafffe"},ma="glossa_active_project",xy="__global__",qb=x.createContext({activeProject:null,projects:[],setActiveProject:async()=>{},refreshProjects:async()=>{},loading:!0});function i3({children:t}){const[o,r]=x.useState([]),[l,c]=x.useState(null),[d,u]=x.useState(!0),p=x.useCallback(async()=>{try{const h=await Ab();r(h);const v=localStorage.getItem(ma);let y=null;const b=v===xy;if(v&&!b&&(y=h.find(S=>S.id===v)??null),!y)try{const S=await _j();y=h.find(k=>k.id===S.id)??null}catch{}!y&&h.length===1&&!b&&(y=h[0]),c(y),y&&localStorage.setItem(ma,y.id)}catch{}finally{u(!1)}},[]);x.useEffect(()=>{p()},[p]),x.useEffect(()=>{const h=()=>{p()};return window.addEventListener("glossa:project-changed",h),()=>window.removeEventListener("glossa:project-changed",h)},[p]);const g=x.useCallback(async h=>{if(h===null)c(null),localStorage.setItem(ma,xy);else{try{await Mb(h)}catch{}const v=o.find(y=>y.id===h)??null;c(v),v?localStorage.setItem(ma,v.id):localStorage.removeItem(ma)}window.dispatchEvent(new CustomEvent("glossa:project-changed"))},[o]);return n.jsx(qb.Provider,{value:{activeProject:l,projects:o,setActiveProject:g,refreshProjects:p,loading:d},children:t})}function zo(){return x.useContext(qb)}function yy(t){return t.replace(/^### (.+)$/gm,'

$1

').replace(/^## (.+)$/gm,'

$1

').replace(/^# (.+)$/gm,'

$1

').replace(/\*\*(.+?)\*\*/g,"$1").replace(/\*(.+?)\*/g,"$1").replace(/^\| (.+) \|$/gm,o=>""+o.split("|").filter(l=>l.trim()).map(l=>`${l.trim()}`).join("")+"").replace(/(.*?<\/tr>\n?)+/gs,o=>`${o}
`).replace(/^- (.+)$/gm,'
  • $1
  • ').replace(/(\n?)+/gs,'
      $1
    ').replace(/^(?!<[a-z])(.+)$/gm,'

    $1

    ').replace(/```[\s\S]*?```/g,o=>`
    ${o.replace(/```\w*/g,"").trim()}
    `)}const by=new Set(["data","document"]),vy=new Set(["report"]),xa={report:"PDF Report",data:"Data",document:"Document"},Sy={report:"#dc2626",data:"#2563eb",document:"#7c3aed"};function wy({label:t,options:o,selected:r,onChange:l,colorMap:c}){const[d,u]=x.useState(!1),[p,g]=x.useState(""),h=x.useRef(null);x.useEffect(()=>{if(!d)return;const S=k=>{h.current&&!h.current.contains(k.target)&&u(!1)};return document.addEventListener("mousedown",S),()=>document.removeEventListener("mousedown",S)},[d]);const v=S=>{const k=new Set(r);k.has(S)?k.delete(S):k.add(S),l(k)},y=o.filter(S=>!p||S.toLowerCase().includes(p.toLowerCase())),b=r.size;return n.jsxs("div",{ref:h,style:{position:"relative"},children:[n.jsxs("button",{onClick:()=>u(S=>!S),style:{display:"flex",alignItems:"center",gap:5,padding:"4px 10px",border:`1px solid ${b>0?"#2563eb":"#d1d5db"}`,borderRadius:6,background:b>0?"#eff6ff":"#fff",cursor:"pointer",fontSize:12,color:"#374151",whiteSpace:"nowrap"},children:[n.jsxs("span",{style:{fontSize:11,color:"#6b7280"},children:[t,":"]}),b===0?n.jsx("span",{style:{color:"#9ca3af"},children:"All"}):n.jsxs("span",{style:{fontWeight:700,color:"#2563eb"},children:[b," selected"]}),n.jsx("span",{style:{fontSize:9,color:"#9ca3af"},children:d?"▲":"▼"})]}),d&&n.jsxs("div",{style:{position:"absolute",top:"calc(100% + 4px)",left:0,zIndex:200,background:"#fff",border:"1px solid #e5e7eb",borderRadius:8,boxShadow:"0 8px 24px rgba(0,0,0,0.12)",minWidth:200,maxHeight:280,display:"flex",flexDirection:"column"},children:[o.length>6&&n.jsx("div",{style:{padding:"6px 8px",borderBottom:"1px solid #f3f4f6"},children:n.jsx("input",{value:p,onChange:S=>g(S.target.value),placeholder:"Search\\u2026",style:{width:"100%",border:"1px solid #e5e7eb",borderRadius:4,padding:"3px 7px",fontSize:11,outline:"none",boxSizing:"border-box"},autoFocus:!0})}),n.jsxs("button",{onClick:()=>l(new Set),style:{padding:"6px 12px",border:"none",background:"none",textAlign:"left",cursor:"pointer",fontSize:11,color:b===0?"#2563eb":"#374151",fontWeight:b===0?700:400,borderBottom:"1px solid #f3f4f6"},children:[b===0?"✔ ":""," All (",o.length,")"]}),n.jsxs("div",{style:{overflowY:"auto",flex:1},children:[y.map(S=>{const k=(c==null?void 0:c[S])??"#2563eb",_=r.has(S);return n.jsxs("button",{onClick:()=>v(S),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"6px 12px",border:"none",background:_?k+"10":"none",cursor:"pointer",textAlign:"left",fontSize:11,borderBottom:"1px solid #f9fafb"},children:[n.jsx("span",{style:{width:14,height:14,borderRadius:3,border:`2px solid ${_?k:"#d1d5db"}`,background:_?k:"#fff",flexShrink:0,display:"flex",alignItems:"center",justifyContent:"center"},children:_&&n.jsx("span",{style:{color:"#fff",fontSize:9,fontWeight:700},children:"\\u2713"})}),n.jsx("span",{style:{flex:1,color:_?k:"#374151",fontWeight:_?600:400},children:S})]},S)}),y.length===0&&n.jsx("div",{style:{padding:"8px 12px",color:"#9ca3af",fontSize:11},children:"No matches"})]}),b>0&&n.jsx("button",{onClick:()=>{l(new Set),u(!1)},style:{padding:"5px 12px",border:"none",background:"none",borderTop:"1px solid #f3f4f6",cursor:"pointer",fontSize:10,color:"#6b7280",textAlign:"left"},children:"Clear selection"})]}),b>0&&n.jsx("div",{style:{display:"flex",gap:3,flexWrap:"wrap",marginTop:4},children:Array.from(r).map(S=>n.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:3,padding:"1px 6px",borderRadius:10,fontSize:10,fontWeight:600,background:((c==null?void 0:c[S])??"#2563eb")+"18",color:(c==null?void 0:c[S])??"#2563eb",border:`1px solid ${(c==null?void 0:c[S])??"#2563eb"}30`},children:[S,n.jsx("button",{onClick:()=>v(S),style:{border:"none",background:"none",cursor:"pointer",color:"inherit",fontSize:11,padding:0,lineHeight:1},children:"\\u00d7"})]},S))})]})}function o3(){const{activeProject:t}=zo(),o=(t==null?void 0:t.id)??null,[r,l]=x.useState([]),[c,d]=x.useState(!0),[u,p]=x.useState(null),[g,h]=x.useState("reports"),[v,y]=x.useState(""),[b,S]=x.useState(new Set),[k,_]=x.useState(new Set),[T,w]=x.useState("updated_at"),[C,j]=x.useState("desc"),[L,W]=x.useState(!0),[P,z]=x.useState(null),[M,q]=x.useState(!1),[K,D]=x.useState([]),[Y,H]=x.useState(""),[A,G]=x.useState(!1),[R,X]=x.useState(null),B=async()=>{X(null),q(!0);try{const oe=await v2();D(oe),oe.length>0&&H(oe[0].id)}catch{D([])}},V=async()=>{if(Y){G(!0),X(null);try{const oe=await S2(Y);X(oe.message),setTimeout(()=>{q(!1),X(null),de()},3e3)}catch(oe){X(oe instanceof Error?oe.message:"Generation failed")}finally{G(!1)}}},[Q,N]=x.useState(!1),[O,$]=x.useState(new Set),[F,I]=x.useState(!1),[J,ne]=x.useState(null),se=async()=>{const oe=r.filter(Ne=>O.has(Ne.id));if(oe.length){I(!0);try{const Ne=await Promise.all(oe.map(async mt=>{const St=Df(mt.id);try{const Ht=await fetch(St);if(Ht.ok){const Kt=await Ht.json();return{name:mt.name,filename:mt.relative_path,data:Kt}}}catch{}return{name:mt.name,filename:mt.relative_path,data:{}}})),We=await jb({report_contents:Ne,title:oe.length===1?`Analysis: ${oe[0].name}`:`Synthesis of ${oe.length} Reports`});ne(We)}catch(Ne){alert(Ne instanceof Error?Ne.message:"AI report generation failed. Check that a language model is configured in Settings.")}finally{I(!1)}}},pe=oe=>$(Ne=>{const We=new Set(Ne);return We.has(oe)?We.delete(oe):We.add(oe),We}),[_e,we]=x.useState(()=>{try{return new Set(JSON.parse(localStorage.getItem("glossa_starred_reports")??"[]"))}catch{return new Set}}),ke=oe=>{we(Ne=>{const We=new Set(Ne);return We.has(oe)?We.delete(oe):We.add(oe),localStorage.setItem("glossa_starred_reports",JSON.stringify([...We])),We})},te=async()=>{const oe=r.filter(St=>O.has(St.id));if(!oe.length)return;const We=(await Promise.all(oe.map(async St=>{const Ht=Df(St.id);let Kt=`Open source file →`;try{const _i=await fetch(Ht);if(_i.ok&&St.kind==="data"){const bn=await _i.json();if(bn.results&&typeof bn.results=="object"){const di=Object.entries(bn.results).map(([Qi,gn])=>{const Rt=typeof gn=="object"?JSON.stringify(gn,null,2):String(gn);return`${Qi.replace(/_/g," ")}
    ${Rt.slice(0,800)}${Rt.length>800?"…":""}
    `}).join("");Kt=(typeof bn.generated=="string"?`

    ${bn.generated}

    `:"")+(di.length?`${di}
    `:`
    ${JSON.stringify(bn,null,2).slice(0,1200)}
    `)}else Kt=`
    ${JSON.stringify(bn,null,2).slice(0,2e3)}
    `}}catch{}return`

    ${St.name}

    ${St.kind.replace("_"," ")} · ${St.relative_path}

    `+Kt+"
    "}))).join(`
    -`),mt=window.open("","_blank","width=920,height=940");if(!mt){alert("Allow popups from localhost in your browser settings, then try again.");return}mt.document.write(`Glossa Lab — Research Report

    Glossa Lab — Research Report

    Generated ${new Date().toLocaleString()} · ${oe.length} report${oe.length!==1?"s":""}


    `+We+" + -
    +
    diff --git a/frontend/src/api.ts b/frontend/src/api.ts index d84a51dc..a142b2d2 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -1721,6 +1721,45 @@ export interface LatestInsightResponse { export const getLatestInsight = (): Promise => request("GET", "/dashboard/latest-insight"); +// ── Foundation automation ──────────────────────────────────────────── + +export interface FoundationStatus { + last_checked_at: string | null; + verdict: string | null; + n_ok: number; + n_fail: number; + n_warn: number; + auto_check_enabled: boolean; + dirty: boolean; + running: boolean; +} + +export interface FoundationCheckResult { + n_ok?: number; + n_fail?: number; + n_warn?: number; + verdict?: string; + failed?: string[]; + skipped?: boolean; + reason?: string; + error?: string; +} + +export const getFoundationStatus = (): Promise => + request("GET", "/foundation/status"); + +export const runFoundationCheck = (): Promise => + request("POST", "/foundation/check"); + +export const updateFoundationConfig = ( + body: { auto_check_enabled?: boolean }, +): Promise<{ ok: boolean; auto_check_enabled: boolean }> => + request("PATCH", "/foundation/config", body); + +// ── SSE events stream URL ─────────────────────────────────────────── + +export const getEventsStreamUrl = (): string => `/api/v1/events/stream`; + // ── AI profile suggestions ─────────────────────────────────────────── export interface AIProfileSuggestion { diff --git a/frontend/src/components/DashboardView.tsx b/frontend/src/components/DashboardView.tsx index 9b5bfaee..b068a77c 100644 --- a/frontend/src/components/DashboardView.tsx +++ b/frontend/src/components/DashboardView.tsx @@ -25,6 +25,7 @@ import { updateHypothesis, executeAiAction, getDashboardHighlights, + getEventsStreamUrl, getHealth, getLatestInsight, listExperiments, @@ -53,6 +54,23 @@ import { ResearchLoopPanel } from "./ResearchLoopPanel"; // Bump version to invalidate stale caches that contain hallucinated hex-hash // experiment IDs from before the backend validation was deployed. const INSIGHT_LS_KEY = "glossa_dashboard_insight_v2"; +const INSIGHT_INTERVAL_LS_KEY = "glossa_insight_interval_min"; +const INSIGHT_LAST_AUTO_KEY = "insight_last_auto_regen"; + +/** Read auto-refresh interval from localStorage (default 20 min). */ +function _getInsightInterval(): number { + try { + const v = parseInt(localStorage.getItem(INSIGHT_INTERVAL_LS_KEY) ?? "20", 10); + if ([10, 15, 20, 30, 60].includes(v)) return v; + } catch { /* ignore */ } + return 20; +} +function _getLastAutoRegen(): number { + try { return parseInt(localStorage.getItem(INSIGHT_LAST_AUTO_KEY) ?? "0", 10) || 0; } catch { return 0; } +} +function _setLastAutoRegen(ms: number): void { + try { localStorage.setItem(INSIGHT_LAST_AUTO_KEY, String(ms)); } catch { /* ignore */ } +} interface PersistedInsight { insight: DashboardInsight; generated_at: number; // epoch ms when LLM generated this @@ -206,6 +224,76 @@ export function DashboardView() { } }, [days, projectId, toast, setApplyResult]); + // ── Insight auto-refresh interval setting ──────────────────────────── + const [insightIntervalMin, setInsightIntervalMin] = useState(_getInsightInterval); + const [autoCountdown, setAutoCountdown] = useState(""); + const [jobsRunning, setJobsRunning] = useState(false); + + // Listen for loop-running custom event (dispatched by ResearchLoopPanel) + useEffect(() => { + const onRunning = (e: Event) => { + setJobsRunning((e as CustomEvent).detail?.running ?? true); + }; + window.addEventListener("glossa:loop-running", onRunning); + return () => window.removeEventListener("glossa:loop-running", onRunning); + }, []); + + // shouldAutoRegen — checks throttle and whether batch jobs are active + const shouldAutoRegen = useCallback((): boolean => { + if (jobsRunning) return false; + if (insightLoading) return false; + const last = _getLastAutoRegen(); + const intervalMs = insightIntervalMin * 60 * 1000; + return Date.now() - last > intervalMs; + }, [jobsRunning, insightLoading, insightIntervalMin]); + + // Auto-refresh timer: check every 60s + useEffect(() => { + const tick = () => { + const last = _getLastAutoRegen(); + const intervalMs = insightIntervalMin * 60 * 1000; + const remaining = Math.max(0, intervalMs - (Date.now() - last)); + const mins = Math.ceil(remaining / 60_000); + if (jobsRunning) { + setAutoCountdown("⏳ Waiting for jobs to complete..."); + } else if (remaining <= 0 || last === 0) { + setAutoCountdown("✅ Up to date"); + } else { + setAutoCountdown(`🔄 Auto-update in ${mins}m`); + } + // Trigger auto-regen if due + if (shouldAutoRegen()) { + _setLastAutoRegen(Date.now()); + void generateInsight(); + } + }; + tick(); // run immediately + const id = setInterval(tick, 60_000); + return () => clearInterval(id); + }, [insightIntervalMin, jobsRunning, shouldAutoRegen, generateInsight]); + + // ── SSE subscription for real-time insight triggers ────────────────── + useEffect(() => { + const url = getEventsStreamUrl(); + let es: EventSource | null = null; + try { + es = new EventSource(url); + es.onmessage = (ev) => { + try { + const data = JSON.parse(ev.data) as { type?: string }; + if (data.type === "insight_trigger" && shouldAutoRegen()) { + _setLastAutoRegen(Date.now()); + void generateInsight(); + } + } catch { /* ignore parse errors */ } + }; + es.onerror = () => { + // Silently reconnect — browser EventSource handles this + }; + } catch { /* SSE not available */ } + return () => { es?.close(); }; + }, [shouldAutoRegen, generateInsight]); + // Auto-refresh dashboard data every 30 s useEffect(() => { const id = setInterval(() => void refresh(), 30_000); @@ -810,6 +898,26 @@ export function DashboardView() { ({fmtRelative(new Date(insightGeneratedAt).toISOString())}) )} + {/* Auto-refresh freshness indicator */} + + {autoCountdown} + + {/* Auto-refresh interval setting */} + + + )} + {/* Status footer */}
    {totalAnchors} signs deciphered — all signs encountered in the publicly accessible Holdat + ICIT + Firestore corpora have Proto-Dravidian readings ({high} HIGH confidence). diff --git a/frontend/src/components/ResearchLoopPanel.tsx b/frontend/src/components/ResearchLoopPanel.tsx index 891c7e2f..b51d87b4 100644 --- a/frontend/src/components/ResearchLoopPanel.tsx +++ b/frontend/src/components/ResearchLoopPanel.tsx @@ -63,12 +63,16 @@ interface AnchorCandidate { dedr_support?: string; source_experiment: string; conflict?: string; - review_status: "staged" | "blocked" | "approved" | "rejected"; + review_status: "staged" | "blocked" | "approved" | "rejected" | "verified" | "expired"; neighbor_reading?: string; neighbor_count?: number; corpus_freq?: number; animal_freq?: number; partner_reading?: string; + verified_at?: string; + archived_at?: string; + archived_reason?: string; + sa_delta?: number; } interface Synthesis { @@ -689,11 +693,7 @@ function CandidatesTable({ whiteSpace: "nowrap" }}> {c.evidence_type.replace(/_/g, "\u200b").slice(0, 18)} - - staged - +
    ))} {/* Blocked (collapsed) */} @@ -711,6 +711,28 @@ function CandidatesTable({ // ── Sub-components ─────────────────────────────────────────────────────────── +/** Lifecycle stage badge for anchor candidates. */ +function LifecycleBadge({ status }: { status: string }) { + const styles: Record = { + staged: { bg: "#dcfce7", fg: "#15803d", label: "staged" }, + approved: { bg: "#dbeafe", fg: "#1d4ed8", label: "approved" }, + rejected: { bg: "#fef2f2", fg: "#991b1b", label: "rejected" }, + verified: { bg: "#ecfdf5", fg: "#065f46", label: "verified" }, + expired: { bg: "#f3f4f6", fg: "#6b7280", label: "expired" }, + blocked: { bg: "#fef3c7", fg: "#92400e", label: "blocked" }, + }; + const s = styles[status] ?? styles.staged; + return ( + + {s.label} + + ); +} + function FoundationBadge({ fc }: { fc: FoundationCheck }) { if (fc.skipped) { return ( @@ -908,6 +930,20 @@ function StagingReview({
    All {approved.length + rejected.length} candidates reviewed!
    + {/* Show auto-verified count if any candidates were auto-archived */} + {(() => { + const autoVerified = staging.candidates.filter( + (c) => c.review_status === "verified" || c.archived_reason === "auto_verified" + ); + if (autoVerified.length > 0) { + return ( +
    + ✨ Auto-verified and archived: {autoVerified.length} candidate{autoVerified.length !== 1 ? "s" : ""} +
    + ); + } + return null; + })()}
    {approved.length > 0 ? <>{approved.length} approved reading{approved.length !== 1 ? "s" : ""} are ready to anchor.{" "}