From 1d2e10a3c314f9dfaa1d2855c57563ab0fcee4c4 Mon Sep 17 00:00:00 2001 From: Tristen Pierson Date: Mon, 1 Jun 2026 16:58:02 -0400 Subject: [PATCH] =?UTF-8?q?feat(experiments):=20Phase=20C=20=E2=80=94=20ex?= =?UTF-8?q?periment=20ledger,=20contact-zone=20templates,=20A/B=20language?= =?UTF-8?q?=20templates,=20cross-culture=20matrix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add experiment_ledger.json and EXPERIMENT_LEDGER.md cataloging all 60+ phase files - Add EXPERIMENT_METADATA dict + GET /api/v1/experiments/metadata endpoint - Create experiment_graph_contact_zone.py (KLDivergence, Synthesis, ABComparison) - Create experiment_graph_ab_language.py (AnchoredSALanguageAB, LMConsistencyMatrix) - Create experiment_graph_cross_culture.py (CulturalContactMatrix, ScriptFamilyClassifier) - Register all new node modules in experiment_graph.py ATOMIC_NODES - Add ExperimentLedgerEntry type + getExperimentMetadata API in frontend api.ts - Add ExperimentRegistry collapsible component in DashboardView with category filter chips, status badges, and description tooltips Co-Authored-By: Oz --- backend/glossa_lab/EXPERIMENT_LEDGER.md | 87 +++ backend/glossa_lab/api/experiments.py | 11 + backend/glossa_lab/experiment_graph.py | 88 +++ .../experiment_graph_ab_language.py | 275 +++++++ .../experiment_graph_contact_zone.py | 333 +++++++++ .../experiment_graph_cross_culture.py | 380 ++++++++++ backend/glossa_lab/experiment_ledger.json | 682 ++++++++++++++++++ .../{index-BXsZCCru.js => index-C42v41e-.js} | 96 +-- frontend/dist/index.html | 4 +- frontend/package-lock.json | 4 +- frontend/src/api.ts | 14 + frontend/src/components/DashboardView.tsx | 4 + .../src/components/ExperimentRegistry.tsx | 190 +++++ 13 files changed, 2116 insertions(+), 52 deletions(-) create mode 100644 backend/glossa_lab/EXPERIMENT_LEDGER.md create mode 100644 backend/glossa_lab/experiment_graph_ab_language.py create mode 100644 backend/glossa_lab/experiment_graph_contact_zone.py create mode 100644 backend/glossa_lab/experiment_graph_cross_culture.py create mode 100644 backend/glossa_lab/experiment_ledger.json rename frontend/dist/assets/{index-BXsZCCru.js => index-C42v41e-.js} (61%) create mode 100644 frontend/src/components/ExperimentRegistry.tsx diff --git a/backend/glossa_lab/EXPERIMENT_LEDGER.md b/backend/glossa_lab/EXPERIMENT_LEDGER.md new file mode 100644 index 00000000..6c3d313c --- /dev/null +++ b/backend/glossa_lab/EXPERIMENT_LEDGER.md @@ -0,0 +1,87 @@ +# Experiment Ledger + +Comprehensive catalog of all experiment graph phase files in the Glossa Lab research platform. + +## Summary + +| Phase File | Category | Status | Purpose | Recommendation | +|---|---|---|---|---| +| experiment_graph.py | structural_analysis | active | Core engine with ~50 built-in atomic nodes and graph execution runtime | keep | +| experiment_graph_ctt.py | ctt | active | CTT nodes: sign role classifier, admissibility filter, holdout recall, compound constraint, anchored SA | keep | +| experiment_graph_indus_evidence.py | misc | active | Evidence graph nodes for literature/claims management | keep | +| experiment_graph_phase14.py | structural_analysis | active | Block entropy, conditional entropy, Zipf-Mandelbrot, MI decay, epistatic detection, language verdict | keep | +| experiment_graph_phase15.py | structural_analysis | active | Long-tail validity, cipher self-test, multi-hypothesis ranker, deciphered mapping exporter | keep | +| experiment_graph_phase_legacy.py | misc | legacy | Migration shims for Phase 16-19 standalone scripts | keep | +| experiment_graph_phase20.py | structural_analysis | active | Length-stratified spectral, cluster archaeology, Ferrara OCR, Fuls classifier | keep | +| experiment_graph_phase21.py | structural_analysis | active | Repetition collapser, site stratifier, numerical-weight regression | keep | +| experiment_graph_phase22.py | contact_zone | active | CDLI Meluhha-mention corpus, Meluhhan persons, Indus seals at Mesopotamia | keep | +| experiment_graph_phase23.py | contact_zone | active | Refined seal audit, strict PN extraction, bilingual readout test | keep | +| experiment_graph_phase24.py | contact_zone | active | Laursen Table 1, seal sign upgrade, persons-v2, bipartite readout v2 | keep | +| experiment_graph_phase25.py | sa_variant | active | Janabiyah readout, held-out test, period-stratified replication, Tamil-Brahmi | keep | +| experiment_graph_phase26.py | sa_variant | active | Provenience-stratified SA, Bayesian decoder, expanded readout | keep | +| experiment_graph_phase27.py | sa_variant | active | Reverse Janabiyah, Bayesian v2, iconographic anchors | keep | +| experiment_graph_phase28.py | archaeological | active | CISI Vol 3 OCR, Mahadevan crosswalk, allograph-aware SA | keep | +| experiment_graph_phase29.py | archaeological | active | Corpus 10x expansion: M77, ePSD2, Fuls, ICIT loaders | keep | +| experiment_graph_phase30.py | sa_variant | active | Length-cohort reverse Janabiyah, permutation test, Dravidian syllable LM | keep | +| experiment_graph_phase_misc_gaps.py | misc | legacy | Phases 44-47, 202, 209-215, 254-256 wrapped as subprocess runners | keep | +| experiment_graph_phase48_55.py | sa_variant | active | Full Indus decipherment pipeline (GPU mandatory) | keep | +| experiment_graph_phase56_61.py | sa_variant | active | Expanded Parpola SA, phonotactic falsification (GPU mandatory) | keep | +| experiment_graph_phase62_66.py | sa_variant | active | Ensemble fix, phonotactic filter, morpheme boundary, Sanskrit SA | keep | +| experiment_graph_phase67_73.py | sa_variant | active | Sanskrit norm, formula translation, M267 validation, parser | keep | +| experiment_graph_phase74_80.py | lm_scoring | active | Grammar test, Levit, place formula, SA agreement, semantic cluster, DEDR | keep | +| experiment_graph_phase81_87.py | sa_variant | active | M293 deep-dive, seal translation, formula lexicon, phonology | keep | +| experiment_graph_phase88_90.py | misc | active | Literature mine, DEDR expansion to 120, scholarly translations | keep | +| experiment_graph_phase91_100.py | sa_variant | active | Anchor-120 SA, M293 SA, trigram, grammar, full-corpus runs | keep | +| experiment_graph_phase101_103.py | archaeological | active | M293 iconographic, PDF extraction, personal name lexicon | keep | +| experiment_graph_phase104_109.py | sa_variant | active | OCR, name signs, name SA, Tamil-Brahmi check, phoneme exhaustion | keep | +| experiment_graph_phase110_115.py | sa_variant | active | Targeted SA, allographs, grammar inference, seal translations | keep | +| experiment_graph_phase116_121.py | sa_variant | active | SA recalibration, grammar LOW, site semantics, arXiv | keep | +| experiment_graph_phase122_123.py | cross_language | active | Syllabic SA, Munda/BMAC substrate hypothesis | keep | +| experiment_graph_phase124_125.py | structural_analysis | active | Fish-sign polysemy, Arthasastra mining | keep | +| experiment_graph_phase126.py | archaeological | active | ICIT corpus integration and sign inventory alignment | keep | +| experiment_graph_phase127.py | contact_zone | active | Gulf corpus analysis, Roif mining, fish-sign polysemy | keep | +| experiment_graph_phase128_133.py | sa_variant | active | SA refinement and anchor injection cycles | keep | +| experiment_graph_phase134_141.py | structural_analysis | active | Falsification suite, advancement testing, master scorecard | keep | +| experiment_graph_phase142_145.py | sa_variant | active | SA anchor injection and refinement cycles | keep | +| experiment_graph_phase146_155.py | sa_variant | active | SA parameter exploration and convergence testing | keep | +| experiment_graph_phase156_165.py | sa_variant | active | Advanced SA with refined anchors | keep | +| experiment_graph_phase166_168.py | lm_scoring | active | Sibilant validation, Meluhhan expansion, blocker SA | keep | +| experiment_graph_phase169_170.py | structural_analysis | active | Master synthesis, grammar variance — computational frontier | keep | +| experiment_graph_phase171_178.py | structural_analysis | active | Network centrality, betweenness stratification, network deep-dive | keep | +| experiment_graph_phase179_180.py | misc | active | Literature mine, Mesopotamian contact mine | keep | +| experiment_graph_phase181.py | archaeological | active | aDNA archaeogenetics mine | keep | +| experiment_graph_phase182.py | misc | active | Deep evidence mine | keep | +| experiment_graph_phase183.py | misc | active | Bulk mine 5000 (superseded by phase184) | keep | +| experiment_graph_phase184.py | misc | active | Bulk mine 5000 second run, fresh clusters | keep | +| experiment_graph_phase185_189.py | cross_language | active | Fish-sign battery, Elamo-Dravidian gap, commodity semantic, north Dravidian LM | keep | +| experiment_graph_phase190_192.py | sa_variant | active | Elamite anchor injection, grammar validation | keep | +| experiment_graph_phase193_195.py | sa_variant | active | SA rerun, SSRN fetch, grammar revalidation | keep | +| experiment_graph_phase196_201.py | sa_variant | active | Mine3, top-8, DEDR lookup, triple-LM, inscription reading | keep | +| experiment_graph_phase203_205.py | cross_language | active | E28 falsification, McAlpin cognates, Bayesian phylogenetics | keep | +| experiment_graph_phase206_208.py | sa_variant | active | Anchor injection M692/M861, SA rerun 404, mine5 | keep | +| experiment_graph_phase216_220.py | sa_variant | active | SA recalibration, site semantic, arXiv, Parpola/CISI | keep | +| experiment_graph_phase221_225.py | sa_variant | active | P324/P122 investigation, CISI injection, slot mismatch | keep | +| experiment_graph_phase226_228.py | sa_variant | active | P122 phonetic, P324 formula, CISI tripartite | keep | +| experiment_graph_phase229.py | sa_variant | active | CISI anchor SA test, M122 upgrade | keep | +| experiment_graph_phase230_234.py | contact_zone | active | Cross-ref matrix, indirect bilingual, cultural/demographic | keep | +| experiment_graph_phase235_236.py | cross_language | active | Elamite–PDr bridge, Sanskrit loanword mapping | keep | +| experiment_graph_phase237_246.py | sa_variant | active | Blocker mine, batch upgrades, synthesis, SA crossing | keep | +| experiment_graph_phase248_253.py | sa_variant | active | Ceiling-breaker mine, allograph, semantic constraint | keep | +| experiment_graph_phase257_294.py | sa_variant | active | SA reruns, Yajnadevam, DEDR resolution, 605/605 decipherment | keep | +| experiment_graph_phase295_297.py | misc | active | Bulk mine May 2026, cross-reference, gap analysis | keep | +| experiment_graph_phase298_308.py | cross_language | active | Munda mine/SA, substrate, archaeology, DEDR, Elamite baseline | keep | +| experiment_graph_phase322_362.py | sa_variant | active | May 2026 decipherment advancement session | keep | +| experiment_graph_contact_zone.py | contact_zone | active | KL divergence, synthesis, A/B comparison for contact signals | keep | +| experiment_graph_ab_language.py | cross_language | active | A/B language SA: Dravidian vs Sanskrit/Munda/Hebrew, LM consistency | keep | +| experiment_graph_cross_culture.py | cross_language | active | Cultural contact matrix, script family classifier | keep | + +## Category Legend + +- **structural_analysis** — Entropy, positional, spectral, network analysis of sign/symbol systems +- **lm_scoring** — Language model scoring, grammar tests, validation +- **sa_variant** — Simulated annealing decipherment runs and variants +- **ctt** — Constraint Topology Theory framework +- **contact_zone** — Mesopotamian contact corpus, bilingual analysis, seals +- **cross_language** — Cross-language comparison, substrate hypothesis, phylogenetics +- **archaeological** — OCR, corpus expansion, archaeogenetics, iconography +- **misc** — Literature mining, evidence management, infrastructure, legacy shims diff --git a/backend/glossa_lab/api/experiments.py b/backend/glossa_lab/api/experiments.py index 28e606ea..f7438b35 100644 --- a/backend/glossa_lab/api/experiments.py +++ b/backend/glossa_lab/api/experiments.py @@ -38,6 +38,17 @@ router = APIRouter() +@router.get("/experiments/metadata") +async def get_experiments_metadata() -> list[dict[str, Any]]: + """Return experiment ledger metadata for all registered nodes. + + Merges the static experiment_ledger.json with live ATOMIC_NODES + registration data. Used by the frontend ExperimentRegistry component. + """ + from glossa_lab.experiment_graph import get_experiment_metadata # noqa: PLC0415 + return get_experiment_metadata() + + @router.get("/experiments") async def list_experiments() -> list[dict[str, Any]]: """Return graph experiments only (H16 compliance). diff --git a/backend/glossa_lab/experiment_graph.py b/backend/glossa_lab/experiment_graph.py index b74bb2d7..1ddf9344 100644 --- a/backend/glossa_lab/experiment_graph.py +++ b/backend/glossa_lab/experiment_graph.py @@ -2834,6 +2834,39 @@ def _experiment_wrapper(inputs: dict, params: dict) -> dict: except Exception as _p322390_exc: # noqa: BLE001 logger.warning("Phase-322-390 nodes not registered: %s", _p322390_exc) +# ── Contact-zone analysis templates (KL divergence, synthesis, A/B) ───────── +try: + from glossa_lab.experiment_graph_contact_zone import ( + _contact_zone_node_defs as _cz_defs, + ) + for _d in _cz_defs(): + ATOMIC_NODES[_d.id] = _d + logger.info("Registered %d contact-zone template nodes", len(_cz_defs())) +except Exception as _cz_exc: # noqa: BLE001 + logger.warning("Contact-zone template nodes not registered: %s", _cz_exc) + +# ── A/B language comparison templates (anchored SA, consistency matrix) ────── +try: + from glossa_lab.experiment_graph_ab_language import ( + _ab_language_node_defs as _ab_defs, + ) + for _d in _ab_defs(): + ATOMIC_NODES[_d.id] = _d + logger.info("Registered %d A/B language template nodes", len(_ab_defs())) +except Exception as _ab_exc: # noqa: BLE001 + logger.warning("A/B language template nodes not registered: %s", _ab_exc) + +# ── Cross-culture contact matrix + script family classifier ───────────────── +try: + from glossa_lab.experiment_graph_cross_culture import ( + _cross_culture_node_defs as _cc_defs, + ) + for _d in _cc_defs(): + ATOMIC_NODES[_d.id] = _d + logger.info("Registered %d cross-culture template nodes", len(_cc_defs())) +except Exception as _cc_exc: # noqa: BLE001 + logger.warning("Cross-culture template nodes not registered: %s", _cc_exc) + # ── Research Loop Runner (meta-node for Experiment Builder) try: from glossa_lab.pipelines.research_loop import ResearchLoop as _RL @@ -2869,6 +2902,61 @@ def _research_loop_runner(inputs: dict, params: dict) -> dict: logger.warning("ResearchLoopRunner not registered: %s", _rl_exc) +# ── Experiment metadata (ledger-backed) ────────────────────────────────────── + +def get_experiment_metadata() -> list[dict[str, Any]]: + """Return ledger metadata for all registered experiment nodes. + + Merges the static experiment_ledger.json with live registration data + from ATOMIC_NODES to provide a unified metadata view. + """ + ledger_path = Path(__file__).parent / "experiment_ledger.json" + ledger: list[dict] = [] + if ledger_path.exists(): + try: + ledger = json.loads(ledger_path.read_text("utf-8")) + except Exception: # noqa: BLE001 + pass + + # Build a lookup from node ID to ledger entry + node_to_ledger: dict[str, dict] = {} + for entry in ledger: + for node_name in entry.get("key_nodes", []): + node_to_ledger[node_name] = entry + + # Merge live registration with ledger + result: list[dict[str, Any]] = [] + for node_id, node_def in ATOMIC_NODES.items(): + ledger_entry = node_to_ledger.get(node_id, {}) + result.append({ + "id": node_id, + "display_name": node_def.name, + "category": ledger_entry.get("category", node_def.category), + "phase": ledger_entry.get("phases", ""), + "description": node_def.description, + "status": ledger_entry.get("status", "active"), + "superseded_by": ledger_entry.get("superseded_by"), + "source_file": ledger_entry.get("file", ""), + }) + + # Also include ledger-only entries (files without individually named nodes) + seen_files = {e.get("source_file") for e in result if e.get("source_file")} + for entry in ledger: + if entry.get("file") not in seen_files: + result.append({ + "id": entry.get("file", "").replace(".py", ""), + "display_name": entry.get("file", "").replace("experiment_graph_", "").replace(".py", ""), + "category": entry.get("category", "misc"), + "phase": entry.get("phases", ""), + "description": entry.get("purpose", ""), + "status": entry.get("status", "active"), + "superseded_by": entry.get("superseded_by"), + "source_file": entry.get("file", ""), + }) + + return result + + # ── Graph execution def _topo_sort(nodes: list[dict], edges: list[dict]) -> list[dict]: diff --git a/backend/glossa_lab/experiment_graph_ab_language.py b/backend/glossa_lab/experiment_graph_ab_language.py new file mode 100644 index 00000000..7924345b --- /dev/null +++ b/backend/glossa_lab/experiment_graph_ab_language.py @@ -0,0 +1,275 @@ +"""A/B language comparison experiment templates. + +Provides generic anchored SA language comparison and concrete A/B +experiment definitions: + + AnchoredSALanguageAB — Parameterised by lang_a and lang_b. Loads the + relevant LM for each, runs anchored SA on the Indus corpus, + computes z-scores and consistency for each, returns winner with + confidence and evidence. + + Concrete experiments (using AnchoredSALanguageAB with fixed params): + ab_dravidian_vs_sanskrit — Dravidian vs Sanskrit anchored SA + ab_dravidian_vs_munda — Dravidian vs Munda anchored SA + ab_dravidian_vs_hebrew — Dravidian vs Hebrew anchored SA + + LMConsistencyMatrix — Runs all pairings and produces a summary + matrix with overall Dravidian confidence. +""" +from __future__ import annotations + +import math +import random +from collections import Counter +from typing import Any + + +# ── Helpers ────────────────────────────────────────────────────────────── + + +def _load_lm(lang: str) -> Any: + """Load a LanguageModel for the given language identifier.""" + # Delegate to the builtin LM loader logic in experiment_graph.py + from glossa_lab.experiment_graph import _builtin_lm # noqa: PLC0415 + result = _builtin_lm({}, {"language": lang}) + return result.get("lm") if not result.get("error") else None + + +def _load_indus_sequences() -> list[list[str]]: + """Load the default Indus corpus sequences.""" + from glossa_lab.experiment_graph import _builtin_corpus # noqa: PLC0415 + result = _builtin_corpus({}, {"corpus": "indus_m77"}) + return result.get("sequences") or [] + + +def _quick_sa(flat: list[str], lm: Any, n_seeds: int = 3, max_iter: int = 3000) -> dict: + """Run a lightweight SA decipherment and return modal mapping + consistency.""" + from glossa_lab.pipelines.decipher import decipher # noqa: PLC0415 + + all_maps: list[dict] = [] + for seed in range(n_seeds): + try: + r = decipher( + flat, lm, seed=seed, max_iterations=max_iter, restarts=2, + cipher_inscriptions=None, surjective=True, + ocp_weight=0.0, positional_weight=0.0, + ) + m = r.get("proposed_mapping", {}) + if m: + all_maps.append(m) + except Exception: # noqa: BLE001 + pass + + if not all_maps: + return {"proposed_mapping": {}, "mean_consistency": 0.0, "hci_count": 0, "n_seeds": 0} + + all_signs = set().union(*[m.keys() for m in all_maps]) + modal: dict[str, str] = {} + cons: dict[str, float] = {} + for s in all_signs: + props = [m[s] for m in all_maps if s in m] + if props: + cnt = Counter(props) + mo, mc = cnt.most_common(1)[0] + modal[s] = mo + cons[s] = mc / len(props) + + mean_c = sum(cons.values()) / len(cons) if cons else 0.0 + hci = sum(1 for v in cons.values() if v >= 0.75) + + return { + "proposed_mapping": modal, + "mean_consistency": round(mean_c, 4), + "hci_count": hci, + "n_seeds": len(all_maps), + "n_signs": len(modal), + } + + +# ── Node 1: AnchoredSALanguageAB ──────────────────────────────────────── + + +def _anchored_sa_language_ab(inputs: dict, params: dict) -> dict: + """A/B language comparison using anchored SA decipherment. + + Loads LMs for lang_a and lang_b, runs SA on the Indus corpus with each, + compares consistency z-scores. + """ + lang_a = str(params.get("lang_a", "dravidian")).lower().strip() + lang_b = str(params.get("lang_b", "sanskrit")).lower().strip() + n_seeds = max(1, int(params.get("n_seeds", 3))) + max_iter = max(500, int(params.get("max_iterations", 3000))) + + # Load Indus sequences + sequences = inputs.get("sequences") or _load_indus_sequences() + if not sequences: + return {"error": "No Indus sequences available."} + flat = [s for seq in sequences for s in seq] + + # Load LMs + lm_a = _load_lm(lang_a) + lm_b = _load_lm(lang_b) + if not lm_a: + return {"error": f"Failed to load LM for '{lang_a}'."} + if not lm_b: + return {"error": f"Failed to load LM for '{lang_b}'."} + + # Run SA with each LM + result_a = _quick_sa(flat, lm_a, n_seeds=n_seeds, max_iter=max_iter) + result_b = _quick_sa(flat, lm_b, n_seeds=n_seeds, max_iter=max_iter) + + cons_a = result_a["mean_consistency"] + cons_b = result_b["mean_consistency"] + hci_a = result_a["hci_count"] + hci_b = result_b["hci_count"] + + # Compute z-score-like difference + pooled = (cons_a + cons_b) / 2 if (cons_a + cons_b) > 0 else 1.0 + z_diff = (cons_a - cons_b) / max(pooled * 0.1, 0.01) + + if cons_a > cons_b + 0.05: + winner = lang_a + confidence = round(min(1.0, abs(z_diff) / 5.0), 4) + elif cons_b > cons_a + 0.05: + winner = lang_b + confidence = round(min(1.0, abs(z_diff) / 5.0), 4) + else: + winner = "inconclusive" + confidence = 0.0 + + evidence = ( + f"{lang_a}: consistency={cons_a:.4f}, HCI={hci_a}; " + f"{lang_b}: consistency={cons_b:.4f}, HCI={hci_b}. " + f"z_diff={z_diff:.2f}." + ) + + return { + "lang_a": lang_a, + "lang_b": lang_b, + "lang_a_zscore": round(cons_a, 4), + "lang_b_zscore": round(cons_b, 4), + "lang_a_hci": hci_a, + "lang_b_hci": hci_b, + "winner": winner, + "confidence": confidence, + "evidence": evidence, + "z_diff": round(z_diff, 4), + "result_a": {k: v for k, v in result_a.items() if k != "proposed_mapping"}, + "result_b": {k: v for k, v in result_b.items() if k != "proposed_mapping"}, + "verdict": f"A/B test: {winner} wins (confidence={confidence:.2%}). {evidence}", + } + + +# ── Node 2: LMConsistencyMatrix ────────────────────────────────────────── + + +def _lm_consistency_matrix(inputs: dict, params: dict) -> dict: + """Run all A/B language pairings and produce a summary matrix. + + Takes outputs from multiple AnchoredSALanguageAB nodes (wired + through Merger) and synthesises an overall Dravidian confidence score. + """ + pairings: list[dict] = [] + if "pairings" in inputs and isinstance(inputs["pairings"], list): + pairings = inputs["pairings"] + else: + for _k, v in sorted(inputs.items()): + if isinstance(v, dict) and "winner" in v and "lang_a" in v: + pairings.append(v) + + if not pairings: + return {"error": "No A/B pairing results — connect AnchoredSALanguageAB outputs."} + + matrix = [] + dravidian_wins = 0 + total = len(pairings) + + for p in pairings: + row = { + "lang_a": p.get("lang_a"), + "lang_b": p.get("lang_b"), + "winner": p.get("winner"), + "confidence": p.get("confidence"), + "lang_a_zscore": p.get("lang_a_zscore"), + "lang_b_zscore": p.get("lang_b_zscore"), + } + matrix.append(row) + if p.get("winner") in ("dravidian", "tamil", "south_dravidian"): + dravidian_wins += 1 + + dravidian_confidence = round(dravidian_wins / max(1, total), 4) + avg_confidence = round( + sum(p.get("confidence", 0) for p in pairings) / max(1, total), 4 + ) + + verdict = ( + f"LM consistency matrix: {total} pairings. " + f"Dravidian wins {dravidian_wins}/{total} ({dravidian_confidence:.0%}). " + f"Average pairing confidence: {avg_confidence:.2%}." + ) + + return { + "matrix": matrix, + "n_pairings": total, + "dravidian_wins": dravidian_wins, + "dravidian_confidence": dravidian_confidence, + "avg_confidence": avg_confidence, + "verdict": verdict, + "json": {"matrix": matrix, "dravidian_confidence": dravidian_confidence}, + } + + +# ── Registration ───────────────────────────────────────────────────────── + + +def _ab_language_node_defs() -> list: + from glossa_lab.experiment_graph import AtomicNodeDef # noqa: PLC0415 + + return [ + AtomicNodeDef( + "AnchoredSALanguageAB", "Anchored SA Language A/B", + "Cross-Language", + "A/B language comparison using anchored SA: loads LMs for two languages, " + "runs SA on the Indus corpus, compares consistency and z-scores. " + "Returns winner, confidence, and per-language evidence.", + inputs=[ + {"name": "sequences", "type": "sequences", "required": False}, + ], + outputs=[ + {"name": "winner", "type": "text"}, + {"name": "confidence", "type": "number"}, + {"name": "evidence", "type": "text"}, + {"name": "verdict", "type": "text"}, + {"name": "lang_a_zscore", "type": "number"}, + {"name": "lang_b_zscore", "type": "number"}, + ], + params_schema={"type": "object", "properties": { + "lang_a": {"type": "string", "default": "dravidian", + "description": "Language A identifier (e.g. dravidian, sumerian)"}, + "lang_b": {"type": "string", "default": "sanskrit", + "description": "Language B identifier (e.g. sanskrit, hebrew)"}, + "n_seeds": {"type": "integer", "default": 3, "minimum": 1}, + "max_iterations": {"type": "integer", "default": 3000, "minimum": 500}, + }}, + fn=_anchored_sa_language_ab, + ), + AtomicNodeDef( + "LMConsistencyMatrix", "LM Consistency Matrix", + "Cross-Language", + "Synthesise multiple A/B language pairing results into an overall " + "consistency matrix with Dravidian confidence score.", + inputs=[ + {"name": "pairings", "type": "json", "required": False}, + {"name": "a", "type": "any", "required": False}, + {"name": "b", "type": "any", "required": False}, + {"name": "c", "type": "any", "required": False}, + ], + outputs=[ + {"name": "matrix", "type": "json"}, + {"name": "dravidian_confidence", "type": "number"}, + {"name": "verdict", "type": "text"}, + ], + params_schema={"type": "object", "properties": {}}, + fn=_lm_consistency_matrix, + ), + ] diff --git a/backend/glossa_lab/experiment_graph_contact_zone.py b/backend/glossa_lab/experiment_graph_contact_zone.py new file mode 100644 index 00000000..98dadfd5 --- /dev/null +++ b/backend/glossa_lab/experiment_graph_contact_zone.py @@ -0,0 +1,333 @@ +"""Contact-zone analysis experiment templates. + +Provides three atomic nodes for quantifying inter-corpus contact signals: + + ContactZoneKLDivergence — KL/JS divergence between two corpus symbol + distributions, top-N overlapping symbols, and + a contact-zone verdict. + ContactZoneSynthesis — Synthesises outputs from multiple KL comparisons + into a ranked summary of language-family contact. + ContactZoneABComparison — Runs two corpora A and B against Indus and + reports which has the stronger contact signal. + +Registered templates: + contact_zone_kl_v1, contact_zone_synthesis_v1, contact_zone_ab_v1 +""" +from __future__ import annotations + +import math +from collections import Counter +from typing import Any + + +# ── Helpers ────────────────────────────────────────────────────────────── + + +def _freq_map_from_sequences(sequences: list[list[str]]) -> dict[str, int]: + c: Counter[str] = Counter() + for seq in sequences: + c.update(seq) + return dict(c) + + +def _kl_js(p_map: dict[str, int], q_map: dict[str, int], top_n: int = 20) -> dict[str, Any]: + """Compute KL(P||Q) and JS divergence, plus top-N overlapping symbols.""" + total_p = sum(p_map.values()) or 1 + total_q = sum(q_map.values()) or 1 + all_keys = set(p_map) | set(q_map) + + kl = 0.0 + js = 0.0 + overlap_scores: list[tuple[str, float]] = [] + + for k in all_keys: + pk = p_map.get(k, 0) / total_p + qk = q_map.get(k, 0) / total_q + if pk > 0 and qk > 0: + kl += pk * math.log2(pk / qk) + # Score overlap by harmonic mean of the two probabilities + overlap_scores.append((k, 2 * pk * qk / (pk + qk))) + m = (pk + qk) / 2 + if pk > 0 and m > 0: + js += 0.5 * pk * math.log2(pk / m) + if qk > 0 and m > 0: + js += 0.5 * qk * math.log2(qk / m) + + overlap_scores.sort(key=lambda x: -x[1]) + top_overlap = [{"symbol": s, "score": round(sc, 6)} for s, sc in overlap_scores[:top_n]] + n_shared = sum(1 for k in all_keys if k in p_map and k in q_map) + + return { + "kl_divergence": round(kl, 6), + "js_divergence": round(js, 6), + "n_symbols_p": len(p_map), + "n_symbols_q": len(q_map), + "n_shared": n_shared, + "overlap_ratio": round(n_shared / max(1, len(all_keys)), 4), + "top_overlap": top_overlap, + } + + +# ── Node 1: ContactZoneKLDivergence ────────────────────────────────────── + + +def _contact_zone_kl_divergence(inputs: dict, params: dict) -> dict: + """Compute KL divergence between two corpus token sequences. + + Inputs: + sequences_a — list[list[str]] (corpus A, e.g. Indus) + sequences_b — list[list[str]] (corpus B, e.g. Sumerian) + OR freq_map_a / freq_map_b — pre-computed frequency maps + + Returns divergence score, top-N overlapping symbols, and a + contact-zone verdict based on JS divergence thresholds. + """ + seq_a = inputs.get("sequences_a") or inputs.get("sequences") or [] + seq_b = inputs.get("sequences_b") or [] + fm_a = inputs.get("freq_map_a") or inputs.get("freq_map") or ( + _freq_map_from_sequences(seq_a) if seq_a else {} + ) + fm_b = inputs.get("freq_map_b") or ( + _freq_map_from_sequences(seq_b) if seq_b else {} + ) + + label_a = str(params.get("label_a", "corpus_a")) + label_b = str(params.get("label_b", "corpus_b")) + top_n = int(params.get("top_n", 20)) + + if not fm_a or not fm_b: + return {"error": "Need two corpora: connect sequences_a + sequences_b or freq_map_a + freq_map_b."} + + result = _kl_js(fm_a, fm_b, top_n=top_n) + + # Verdict based on JS divergence + js = result["js_divergence"] + if js < 0.3: + verdict = "STRONG_CONTACT" + verdict_text = ( + f"Strong contact signal between {label_a} and {label_b}: " + f"JS divergence {js:.4f} < 0.3 with {result['n_shared']} shared symbols." + ) + elif js < 0.6: + verdict = "MODERATE_CONTACT" + verdict_text = ( + f"Moderate contact signal between {label_a} and {label_b}: " + f"JS divergence {js:.4f}. {result['n_shared']} shared symbols." + ) + else: + verdict = "WEAK_CONTACT" + verdict_text = ( + f"Weak/no contact signal between {label_a} and {label_b}: " + f"JS divergence {js:.4f} >= 0.6." + ) + + return { + **result, + "label_a": label_a, + "label_b": label_b, + "verdict": verdict, + "verdict_text": verdict_text, + "number": round(js, 6), + } + + +# ── Node 2: ContactZoneSynthesis ───────────────────────────────────────── + + +def _contact_zone_synthesis(inputs: dict, params: dict) -> dict: + """Synthesise outputs from multiple KL comparisons. + + Takes a list of KL divergence results (wired from multiple + ContactZoneKLDivergence nodes via Merger) and ranks which + language families show the highest contact signal with the + target corpus. + """ + # Collect all upstream KL results. They may arrive as individual + # keys (a, b, c, …) from a Merger or as a list under "comparisons". + comparisons: list[dict] = [] + if "comparisons" in inputs and isinstance(inputs["comparisons"], list): + comparisons = inputs["comparisons"] + else: + for _k, v in sorted(inputs.items()): + if isinstance(v, dict) and "js_divergence" in v: + comparisons.append(v) + + if not comparisons: + return {"error": "No KL comparison results — connect ContactZoneKLDivergence outputs."} + + # Rank by JS divergence (lower = stronger contact) + ranked = sorted(comparisons, key=lambda c: c.get("js_divergence", 999)) + top_n = int(params.get("top_n", 10)) + + summary = [] + for i, c in enumerate(ranked[:top_n]): + summary.append({ + "rank": i + 1, + "label_a": c.get("label_a", "?"), + "label_b": c.get("label_b", "?"), + "js_divergence": c.get("js_divergence"), + "kl_divergence": c.get("kl_divergence"), + "n_shared": c.get("n_shared"), + "overlap_ratio": c.get("overlap_ratio"), + "verdict": c.get("verdict"), + }) + + strongest = ranked[0] if ranked else {} + verdict_text = ( + f"Contact synthesis: {len(comparisons)} comparisons ranked. " + f"Strongest contact: {strongest.get('label_b', '?')} " + f"(JS={strongest.get('js_divergence', '?'):.4f}, " + f"{strongest.get('n_shared', 0)} shared symbols)." + ) if strongest else "No comparisons available." + + return { + "ranked_summary": summary, + "n_comparisons": len(comparisons), + "strongest_contact": strongest.get("label_b", ""), + "strongest_js": strongest.get("js_divergence"), + "verdict": verdict_text, + "json": {"ranked_summary": summary}, + } + + +# ── Node 3: ContactZoneABComparison ────────────────────────────────────── + + +def _contact_zone_ab_comparison(inputs: dict, params: dict) -> dict: + """Compare two corpora A and B against Indus, return which has stronger contact signal. + + Inputs: + sequences_indus — Indus corpus sequences + sequences_a — corpus A sequences (e.g. Dravidian) + sequences_b — corpus B sequences (e.g. Sumerian) + + Returns which corpus shows stronger contact with Indus. + """ + seq_indus = inputs.get("sequences_indus") or inputs.get("sequences") or [] + seq_a = inputs.get("sequences_a") or [] + seq_b = inputs.get("sequences_b") or [] + + label_a = str(params.get("label_a", "corpus_a")) + label_b = str(params.get("label_b", "corpus_b")) + top_n = int(params.get("top_n", 15)) + + if not seq_indus: + return {"error": "No Indus sequences — connect CorpusReader or BuiltinCorpus."} + if not seq_a and not seq_b: + return {"error": "Need at least one comparison corpus (sequences_a or sequences_b)."} + + fm_indus = _freq_map_from_sequences(seq_indus) + + result_a = _kl_js(fm_indus, _freq_map_from_sequences(seq_a), top_n) if seq_a else None + result_b = _kl_js(fm_indus, _freq_map_from_sequences(seq_b), top_n) if seq_b else None + + js_a = result_a["js_divergence"] if result_a else 999.0 + js_b = result_b["js_divergence"] if result_b else 999.0 + + if js_a < js_b: + winner = label_a + confidence = round(1.0 - js_a / max(js_b, 0.001), 4) + elif js_b < js_a: + winner = label_b + confidence = round(1.0 - js_b / max(js_a, 0.001), 4) + else: + winner = "tie" + confidence = 0.0 + + verdict_text = ( + f"A/B contact comparison: {label_a} JS={js_a:.4f} vs {label_b} JS={js_b:.4f}. " + f"Winner: {winner} (confidence={confidence:.2%})." + ) + + return { + "winner": winner, + "confidence": confidence, + "label_a": label_a, + "label_b": label_b, + "js_a": js_a, + "js_b": js_b, + "result_a": result_a, + "result_b": result_b, + "verdict": verdict_text, + } + + +# ── Registration ───────────────────────────────────────────────────────── + + +def _contact_zone_node_defs() -> list: + from glossa_lab.experiment_graph import AtomicNodeDef # noqa: PLC0415 + + return [ + AtomicNodeDef( + "ContactZoneKLDivergence", "Contact Zone KL Divergence", + "Contact Zone", + "Compute KL and JS divergence between two corpus symbol distributions. " + "Returns divergence score, top-N overlapping symbols, and contact verdict.", + inputs=[ + {"name": "sequences_a", "type": "sequences", "required": False}, + {"name": "sequences_b", "type": "sequences", "required": False}, + {"name": "freq_map_a", "type": "freq_map", "required": False}, + {"name": "freq_map_b", "type": "freq_map", "required": False}, + ], + outputs=[ + {"name": "kl_divergence", "type": "number"}, + {"name": "js_divergence", "type": "number"}, + {"name": "top_overlap", "type": "json"}, + {"name": "verdict", "type": "text"}, + {"name": "number", "type": "number"}, + ], + params_schema={"type": "object", "properties": { + "label_a": {"type": "string", "default": "corpus_a"}, + "label_b": {"type": "string", "default": "corpus_b"}, + "top_n": {"type": "integer", "default": 20, "minimum": 1}, + }}, + fn=_contact_zone_kl_divergence, + ), + AtomicNodeDef( + "ContactZoneSynthesis", "Contact Zone Synthesis", + "Contact Zone", + "Synthesise multiple KL divergence comparisons into a ranked summary " + "of which language families show highest contact signal with the target corpus.", + inputs=[ + {"name": "comparisons", "type": "json", "required": False}, + {"name": "a", "type": "any", "required": False}, + {"name": "b", "type": "any", "required": False}, + {"name": "c", "type": "any", "required": False}, + {"name": "d", "type": "any", "required": False}, + ], + outputs=[ + {"name": "ranked_summary", "type": "json"}, + {"name": "strongest_contact", "type": "text"}, + {"name": "verdict", "type": "text"}, + ], + params_schema={"type": "object", "properties": { + "top_n": {"type": "integer", "default": 10, "minimum": 1}, + }}, + fn=_contact_zone_synthesis, + ), + AtomicNodeDef( + "ContactZoneABComparison", "Contact Zone A/B Comparison", + "Contact Zone", + "Compare two corpora A and B against Indus to determine which shows " + "stronger contact signal. Returns winner, confidence, and per-corpus divergence.", + inputs=[ + {"name": "sequences_indus", "type": "sequences", "required": True}, + {"name": "sequences_a", "type": "sequences", "required": False}, + {"name": "sequences_b", "type": "sequences", "required": False}, + ], + outputs=[ + {"name": "winner", "type": "text"}, + {"name": "confidence", "type": "number"}, + {"name": "verdict", "type": "text"}, + {"name": "result_a", "type": "json"}, + {"name": "result_b", "type": "json"}, + ], + params_schema={"type": "object", "properties": { + "label_a": {"type": "string", "default": "corpus_a"}, + "label_b": {"type": "string", "default": "corpus_b"}, + "top_n": {"type": "integer", "default": 15, "minimum": 1}, + }}, + fn=_contact_zone_ab_comparison, + ), + ] diff --git a/backend/glossa_lab/experiment_graph_cross_culture.py b/backend/glossa_lab/experiment_graph_cross_culture.py new file mode 100644 index 00000000..83584611 --- /dev/null +++ b/backend/glossa_lab/experiment_graph_cross_culture.py @@ -0,0 +1,380 @@ +"""Cross-culture contact matrix and script family classifier. + + CulturalContactMatrix — Given a list of corpus IDs, computes pairwise + contact scores using entropy signature overlap and KL-divergence. + Returns a matrix and top-N ranking of which cultures show strongest + contact signals with Indus. + + ScriptFamilyClassifier — Applies a simple feature-based classifier + (bigram entropy, type-token ratio, Zipf alpha, positional bias) + to classify a script into families: syllabary, logographic, abjad, + alphabet, undetermined. Returns classification with confidence. + +Registered templates: + cross_culture_contact_matrix_v1, script_family_classifier_v1 +""" +from __future__ import annotations + +import math +from collections import Counter +from typing import Any + + +# ── Helpers ────────────────────────────────────────────────────────────── + + +def _freq_map(sequences: list[list[str]]) -> dict[str, int]: + c: Counter[str] = Counter() + for seq in sequences: + c.update(seq) + return dict(c) + + +def _h1(freq: dict[str, int]) -> float: + total = sum(freq.values()) + if total <= 0: + return 0.0 + return -sum((c / total) * math.log2(c / total) for c in freq.values() if c > 0) + + +def _bigram_h(sequences: list[list[str]]) -> float: + bg: Counter[tuple[str, str]] = Counter() + for seq in sequences: + for i in range(len(seq) - 1): + bg[(seq[i], seq[i + 1])] += 1 + total = sum(bg.values()) + if total <= 0: + return 0.0 + return -sum((c / total) * math.log2(c / total) for c in bg.values() if c > 0) + + +def _zipf_alpha(freq: dict[str, int]) -> float: + ranked = sorted(freq.values(), reverse=True) + n = len(ranked) + if n < 2: + return 0.0 + lrs = [math.log(r + 1) for r in range(n)] + lfs = [math.log(f) if f > 0 else 0 for f in ranked] + mr = sum(lrs) / n + mf = sum(lfs) / n + num = sum((lrs[i] - mr) * (lfs[i] - mf) for i in range(n)) + den = sum((lr - mr) ** 2 for lr in lrs) + return round(-num / den, 4) if den else 0.0 + + +def _type_token_ratio(freq: dict[str, int]) -> float: + total = sum(freq.values()) + return round(len(freq) / max(1, total), 6) + + +def _positional_bias(sequences: list[list[str]]) -> float: + """Compute average positional bias: how concentrated signs are in initial/terminal positions.""" + if not sequences: + return 0.0 + tc: Counter[str] = Counter(s for seq in sequences for s in seq) + te: Counter[str] = Counter(seq[-1] for seq in sequences if seq) + ic: Counter[str] = Counter(seq[0] for seq in sequences if seq) + biases = [] + for sym, n in tc.items(): + if n < 3: + continue + t_rate = te[sym] / n + i_rate = ic[sym] / n + biases.append(max(t_rate, i_rate)) + return round(sum(biases) / max(1, len(biases)), 4) if biases else 0.0 + + +def _js_divergence(p_map: dict[str, int], q_map: dict[str, int]) -> float: + total_p = sum(p_map.values()) or 1 + total_q = sum(q_map.values()) or 1 + all_k = set(p_map) | set(q_map) + js = 0.0 + for k in all_k: + pk = p_map.get(k, 0) / total_p + qk = q_map.get(k, 0) / total_q + m = (pk + qk) / 2 + if pk > 0 and m > 0: + js += 0.5 * pk * math.log2(pk / m) + if qk > 0 and m > 0: + js += 0.5 * qk * math.log2(qk / m) + return round(js, 6) + + +# ── Node 1: CulturalContactMatrix ──────────────────────────────────────── + + +def _cultural_contact_matrix(inputs: dict, params: dict) -> dict: + """Compute pairwise contact scores between multiple corpora. + + Inputs: + corpora — dict mapping corpus_name to list[list[str]] sequences, + OR multiple named inputs (a, b, c, ...) each being + {sequences: [...], label: "..."} + + Returns a pairwise JS-divergence matrix and a ranking of which + cultures show strongest contact signals. + """ + corpora: dict[str, list[list[str]]] = {} + + # Try structured input + if "corpora" in inputs and isinstance(inputs["corpora"], dict): + for name, seqs in inputs["corpora"].items(): + if isinstance(seqs, list): + corpora[name] = seqs + else: + # Try named inputs (a, b, c, ...) + for k, v in sorted(inputs.items()): + if isinstance(v, dict): + label = v.get("label") or v.get("corpus") or k + seqs = v.get("sequences") or [] + if seqs: + corpora[str(label)] = seqs + elif isinstance(v, list) and v and isinstance(v[0], list): + corpora[k] = v + + if len(corpora) < 2: + return {"error": "Need at least 2 corpora for pairwise comparison."} + + names = sorted(corpora.keys()) + freq_maps = {n: _freq_map(corpora[n]) for n in names} + + # Compute entropy signatures for overlap scoring + signatures: dict[str, dict] = {} + for n in names: + fm = freq_maps[n] + seqs = corpora[n] + signatures[n] = { + "h1": round(_h1(fm), 4), + "bigram_h": round(_bigram_h(seqs), 4), + "zipf_alpha": _zipf_alpha(fm), + "n_types": len(fm), + "n_tokens": sum(fm.values()), + "ttr": _type_token_ratio(fm), + } + + # Pairwise JS divergence matrix + matrix: list[dict] = [] + for i, a in enumerate(names): + for j, b in enumerate(names): + if j <= i: + continue + js = _js_divergence(freq_maps[a], freq_maps[b]) + # Entropy signature similarity + sig_a = signatures[a] + sig_b = signatures[b] + h1_diff = abs(sig_a["h1"] - sig_b["h1"]) + zipf_diff = abs(sig_a["zipf_alpha"] - sig_b["zipf_alpha"]) + # Combined contact score (lower = stronger contact) + contact_score = round(js * 0.6 + h1_diff * 0.1 + zipf_diff * 0.3, 6) + matrix.append({ + "corpus_a": a, + "corpus_b": b, + "js_divergence": js, + "h1_diff": round(h1_diff, 4), + "zipf_diff": round(zipf_diff, 4), + "contact_score": contact_score, + }) + + # Rank by contact score + matrix.sort(key=lambda x: x["contact_score"]) + top_n = int(params.get("top_n", 10)) + + verdict = ( + f"Cultural contact matrix: {len(names)} corpora, " + f"{len(matrix)} pairwise comparisons. " + f"Strongest contact: {matrix[0]['corpus_a']} ↔ {matrix[0]['corpus_b']} " + f"(score={matrix[0]['contact_score']:.4f})." + ) if matrix else "No comparisons computed." + + return { + "matrix": matrix[:top_n], + "full_matrix": matrix, + "signatures": signatures, + "n_corpora": len(names), + "n_pairs": len(matrix), + "corpus_names": names, + "verdict": verdict, + "json": {"matrix": matrix[:top_n], "signatures": signatures}, + } + + +# ── Node 2: ScriptFamilyClassifier ─────────────────────────────────────── + + +def _script_family_classifier(inputs: dict, params: dict) -> dict: + """Classify a script into writing system families using structural features. + + Features used: + - Bigram entropy (H2) + - Type-token ratio (TTR) + - Zipf alpha exponent + - Positional bias (max(initial_rate, terminal_rate) averaged) + - Vocabulary size (number of distinct symbols) + + Families: syllabary, logographic, abjad, alphabet, undetermined + """ + sequences = inputs.get("sequences") or [] + if not sequences: + return {"error": "No sequences — connect a corpus."} + + label = str(params.get("label", "unknown")) + + fm = _freq_map(sequences) + h1_val = _h1(fm) + h2_val = _bigram_h(sequences) + ttr = _type_token_ratio(fm) + zipf = _zipf_alpha(fm) + pos_bias = _positional_bias(sequences) + n_types = len(fm) + n_tokens = sum(fm.values()) + avg_len = round(sum(len(s) for s in sequences) / max(1, len(sequences)), 2) + + # Rule-based classification + scores: dict[str, float] = { + "syllabary": 0.0, + "logographic": 0.0, + "abjad": 0.0, + "alphabet": 0.0, + "undetermined": 0.0, + } + + # Vocabulary size signal + if n_types > 200: + scores["logographic"] += 3.0 + elif n_types > 80: + scores["syllabary"] += 2.0 + scores["logographic"] += 1.0 + elif n_types > 40: + scores["syllabary"] += 2.0 + elif n_types > 20: + scores["abjad"] += 2.0 + scores["alphabet"] += 1.5 + else: + scores["abjad"] += 3.0 + + # H1 signal + if h1_val > 8.0: + scores["logographic"] += 2.0 + elif h1_val > 5.5: + scores["syllabary"] += 2.0 + elif h1_val > 4.0: + scores["abjad"] += 1.5 + scores["alphabet"] += 1.0 + else: + scores["abjad"] += 2.0 + + # Zipf alpha signal + if zipf > 1.5: + scores["logographic"] += 1.0 + elif zipf > 1.0: + scores["syllabary"] += 0.5 + else: + scores["abjad"] += 0.5 + scores["alphabet"] += 0.5 + + # Positional bias signal (high = more structured/restricted) + if pos_bias > 0.4: + scores["logographic"] += 1.0 # logograms often position-specific + elif pos_bias > 0.25: + scores["syllabary"] += 0.5 + + # Average word length + if avg_len > 5: + scores["syllabary"] += 1.0 + elif avg_len < 3: + scores["abjad"] += 0.5 + + # Find winner + ranked = sorted(scores.items(), key=lambda x: -x[1]) + best_family = ranked[0][0] + best_score = ranked[0][1] + total_score = sum(scores.values()) + confidence = round(best_score / max(1.0, total_score), 4) + + # Low confidence → undetermined + if confidence < 0.3 or best_score < 2.0: + best_family = "undetermined" + confidence = round(confidence * 0.5, 4) + + verdict = ( + f"Script family classifier ({label}): {best_family} " + f"(confidence={confidence:.2%}). " + f"Features: H1={h1_val:.2f}, H2={h2_val:.2f}, TTR={ttr:.6f}, " + f"Zipf={zipf:.2f}, pos_bias={pos_bias:.3f}, " + f"vocab={n_types}, avg_len={avg_len}." + ) + + return { + "label": label, + "classification": best_family, + "confidence": confidence, + "scores": {k: round(v, 2) for k, v in ranked}, + "features": { + "h1": round(h1_val, 4), + "h2": round(h2_val, 4), + "ttr": ttr, + "zipf_alpha": zipf, + "positional_bias": pos_bias, + "n_types": n_types, + "n_tokens": n_tokens, + "avg_word_length": avg_len, + }, + "verdict": verdict, + "text": verdict, + } + + +# ── Registration ───────────────────────────────────────────────────────── + + +def _cross_culture_node_defs() -> list: + from glossa_lab.experiment_graph import AtomicNodeDef # noqa: PLC0415 + + return [ + AtomicNodeDef( + "CulturalContactMatrix", "Cultural Contact Matrix", + "Cross-Language", + "Compute pairwise contact scores between multiple corpora using " + "entropy signature overlap and KL-divergence. Returns a ranked matrix " + "of which cultures show strongest contact signals.", + inputs=[ + {"name": "corpora", "type": "json", "required": False}, + {"name": "a", "type": "any", "required": False}, + {"name": "b", "type": "any", "required": False}, + {"name": "c", "type": "any", "required": False}, + {"name": "d", "type": "any", "required": False}, + {"name": "e", "type": "any", "required": False}, + ], + outputs=[ + {"name": "matrix", "type": "json"}, + {"name": "signatures", "type": "json"}, + {"name": "verdict", "type": "text"}, + ], + params_schema={"type": "object", "properties": { + "top_n": {"type": "integer", "default": 10, "minimum": 1}, + }}, + fn=_cultural_contact_matrix, + ), + AtomicNodeDef( + "ScriptFamilyClassifier", "Script Family Classifier", + "Cross-Language", + "Classify a script into writing system families (syllabary, logographic, " + "abjad, alphabet, undetermined) using bigram entropy, type-token ratio, " + "Zipf alpha, and positional bias features.", + inputs=[ + {"name": "sequences", "type": "sequences", "required": True}, + ], + outputs=[ + {"name": "classification", "type": "text"}, + {"name": "confidence", "type": "number"}, + {"name": "features", "type": "json"}, + {"name": "scores", "type": "json"}, + {"name": "verdict", "type": "text"}, + ], + params_schema={"type": "object", "properties": { + "label": {"type": "string", "default": "unknown", + "description": "Label for the corpus being classified"}, + }}, + fn=_script_family_classifier, + ), + ] diff --git a/backend/glossa_lab/experiment_ledger.json b/backend/glossa_lab/experiment_ledger.json new file mode 100644 index 00000000..9e8a20c9 --- /dev/null +++ b/backend/glossa_lab/experiment_ledger.json @@ -0,0 +1,682 @@ +[ + { + "file": "experiment_graph.py", + "phases": "core", + "category": "structural_analysis", + "purpose": "Core experiment graph engine with ~50 built-in atomic nodes (CorpusReader, FreqCounter, PositionalProfiler, EntropyCalc, SADecipher, etc.) and graph execution runtime.", + "status": "active", + "superseded_by": null, + "key_nodes": ["CorpusReader", "FreqCounter", "PositionalProfiler", "EntropyCalc", "Clusterer", "ZipfFitter", "SADecipher", "BeamDecipher", "LMBuilder", "BuiltinLM", "BuiltinCorpus", "KLDivergence", "WritingSystemClassifier", "AnchorConvergenceBenchmark", "ConsistencyScorer", "BenchmarkScorer", "TokenFilter", "ShuffleControl", "ConstraintSweep", "ComparatorAI", "CorpusLM", "AnchorSetLoader", "ReportGenerator", "SubExperiment", "CanonicalSignLoader", "ClusterMapper"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_ctt.py", + "phases": "CTT", + "category": "ctt", + "purpose": "Constraint Topology Theory nodes: IndusSignRoleClassifier, CTTAdmissibilityFilter, HoldoutWordRecall, CompoundDependencyConstraint, CTTAnchoredSADecipher.", + "status": "active", + "superseded_by": null, + "key_nodes": ["IndusSignRoleClassifier", "CTTAdmissibilityFilter", "HoldoutWordRecall", "CompoundDependencyConstraint", "CTTAnchoredSADecipher"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_indus_evidence.py", + "phases": "evidence", + "category": "misc", + "purpose": "Evidence graph nodes for literature/claims management: IndusLiteratureLoader, IndusClaimsLoader, CrossHypothesisMatrix, HiddenHypothesisGen, IndusClaimTester, IndusNullModelTest, IndusIntakeRunner.", + "status": "active", + "superseded_by": null, + "key_nodes": ["IndusLiteratureLoader", "IndusClaimsLoader", "CrossHypothesisMatrix", "HiddenHypothesisGen", "IndusClaimTester", "IndusNullModelTest", "IndusIntakeRunner"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase14.py", + "phases": "14", + "category": "structural_analysis", + "purpose": "Structural language signature analysis: block entropy, conditional entropy, Zipf-Mandelbrot, MI decay, epistatic interaction detection, and language detector verdict.", + "status": "active", + "superseded_by": null, + "key_nodes": ["BlockEntropyProfile", "ConditionalEntropyProfile", "ZipfMandelbrotFit", "MutualInformationDecay", "LanguageSignatureComparator", "ReferenceCorpusLoader", "EpistaticInteractionDetector", "LanguageDetectorVerdict"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase15.py", + "phases": "15", + "category": "structural_analysis", + "purpose": "Long-tail validity filter, cipher self-test runner, multi-hypothesis ranker, and deciphered mapping exporter for validating decipherment approach.", + "status": "active", + "superseded_by": null, + "key_nodes": ["LongTailFilter", "LongTailVerdict", "CipherSelfTestRunner", "MultiHypothesisRanker", "DecipheredMappingExporter"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase_legacy.py", + "phases": "16-19", + "category": "misc", + "purpose": "Legacy migration shims wrapping Phase 16-19 standalone scripts as atomic nodes via subprocess execution.", + "status": "legacy", + "superseded_by": "phase20+", + "key_nodes": ["LegacyPhaseScriptRunner"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase20.py", + "phases": "20", + "category": "structural_analysis", + "purpose": "Length-stratified spectral analysis, cluster archaeology, Ferrara OCR, Fuls positional classifier — follow-ups to Phase-19 findings.", + "status": "active", + "superseded_by": null, + "key_nodes": ["M77InscriptionLoader", "LengthStratifier", "BinSpectralFingerprint", "AllographDetector", "ClusterArchaeology", "PDFTextExtractor", "FulsPositionalClassifier", "Phase20Verdict"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase21.py", + "phases": "21", + "category": "structural_analysis", + "purpose": "Repetition-aware corpus segmentation, site-stratified hypothesis projection, numerical-weight regression — follow-ups to Phase-20.", + "status": "active", + "superseded_by": null, + "key_nodes": ["RepetitionCollapser", "SiteStratifier", "NumericalWeightAnalyzer", "Phase21Verdict"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase22.py", + "phases": "22", + "category": "contact_zone", + "purpose": "CDLI Meluhha-mention corpus loading, Meluhhan named-person extraction, Indus seals at Mesopotamia inventory, and name-seal matcher prototype.", + "status": "active", + "superseded_by": "phase23", + "key_nodes": ["ContactCorpusLoader", "MeluhhaCorpusReporter", "MeluhhanPersonsExtractor", "IndusSealsAtMesopotamiaLoader", "ContactZoneSummary"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase23.py", + "phases": "23", + "category": "contact_zone", + "purpose": "Refined seal sign audit, strict Meluhhan-name extraction with stoplist, bilingual readout permutation test — first quantitative bilingual analysis.", + "status": "active", + "superseded_by": "phase24", + "key_nodes": ["RefinedSealLoader", "SealSignAuditor", "RefinedMeluhhanPersonsExtractor", "EnhancedNameMatcher", "BilingualReadoutTest"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase24.py", + "phases": "24", + "category": "contact_zone", + "purpose": "Laursen 2010 Table 1 audit, seal sign-ID upgrade, persons-v2 toponym-filtered, bipartite readout test v2 with proper null model.", + "status": "active", + "superseded_by": null, + "key_nodes": ["LaursenTable1Loader", "RefinedSealLoaderV2", "SealSignUpgradeAuditor", "RefinedMeluhhanPersonsExtractorV2", "BilingualReadoutTestV2"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase25.py", + "phases": "25", + "category": "sa_variant", + "purpose": "Janabiyah phonetic readout, blind held-out phonetic test, period-stratified replication, Tamil-Brahmi cross-check.", + "status": "active", + "superseded_by": null, + "key_nodes": ["JanabiyahPhoneticReadout", "BlindHeldOutTest", "PeriodStratifiedReplication", "TamilBrahmiCrossCheck"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase26.py", + "phases": "26", + "category": "sa_variant", + "purpose": "Provenience-stratified SA, Bayesian decoder, expanded readout, find-spot analysis — overrides some Phase-25 nodes.", + "status": "active", + "superseded_by": null, + "key_nodes": ["ProvenienceStratifiedReadout", "BayesianDecoder", "ExpandedReadout", "FindSpotAnalysis"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase27.py", + "phases": "27", + "category": "sa_variant", + "purpose": "Reverse Janabiyah test, Bayesian v2 decoder, iconographic anchors, 6-bucket period stratification.", + "status": "active", + "superseded_by": null, + "key_nodes": ["ReverseJanabiyah", "BayesianV2Decoder", "IconographicAnchors"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase28.py", + "phases": "28", + "category": "archaeological", + "purpose": "CISI Vol 3 OCR via LLM vision, Mahadevan crosswalk, allograph-aware SA decipherment.", + "status": "active", + "superseded_by": null, + "key_nodes": ["CISIVol3OCR", "MahadevanCrosswalk", "AllographAwareSA"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase29.py", + "phases": "29", + "category": "archaeological", + "purpose": "Corpus 10x expansion: M77, ePSD2, Fuls, and ICIT loaders for broadening the sign inventory.", + "status": "active", + "superseded_by": null, + "key_nodes": ["M77Loader", "EPSD2Loader", "FulsLoader", "ICITLoader"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase30.py", + "phases": "30,32", + "category": "sa_variant", + "purpose": "Length-cohort reverse Janabiyah, per-bin permutation null, PermutationTest, MeluhhaCooccurrenceCheck, DravidianSyllableLM.", + "status": "active", + "superseded_by": null, + "key_nodes": ["LengthCohortReverseJanabiyah", "PermutationTest", "MeluhhaCooccurrenceCheck", "DravidianSyllableLM"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase_misc_gaps.py", + "phases": "44-47,202,209-215,254-256", + "category": "misc", + "purpose": "Previously unregistered phase scripts wrapped as subprocess runner nodes: infrastructure, fish tests, bulk mines, anchor injections, PDF reports.", + "status": "legacy", + "superseded_by": null, + "key_nodes": ["IndusPhase44Infrastructure", "IndusPhase45FishCoastal", "IndusPhase46ContactZone", "IndusPhase47PhonemeAssign", "IndusPhase202BulkMine2", "IndusPhase209AnchorM712M817", "IndusPhase210BrahuiGenomics", "IndusPhase215PDFReport"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase48_55.py", + "phases": "48-55", + "category": "sa_variant", + "purpose": "Full Indus decipherment pipeline — GPU mandatory SA runs with expanded anchor sets.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase56_61.py", + "phases": "56-61", + "category": "sa_variant", + "purpose": "Expanded Parpola corpus SA, phonotactic falsification tests — GPU mandatory.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase62_66.py", + "phases": "62-66", + "category": "sa_variant", + "purpose": "Ensemble fix, phonotactic filter, morpheme boundary detection, crosswalk, Sanskrit SA.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase67_73.py", + "phases": "67-73", + "category": "sa_variant", + "purpose": "Sanskrit normalization, formula translation, M267 validation, site stratification, crosswalk, parser.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase74_80.py", + "phases": "74-80", + "category": "lm_scoring", + "purpose": "Grammar test, Levit analysis, place formula, SA agreement, semantic cluster, gap analysis, DEDR.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase81_87.py", + "phases": "81-87", + "category": "sa_variant", + "purpose": "M293 deep-dive, seal translation, gap sprint, formula lexicon, CISI cross-validation, phonology, sprint-120.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase88_90.py", + "phases": "88-90", + "category": "misc", + "purpose": "Literature mine, DEDR systematic expansion to 120, scholarly translations.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase91_100.py", + "phases": "91-100", + "category": "sa_variant", + "purpose": "Anchor-120 SA, uncertain reduce, M293 SA, fulltext, retroflex, crosswalk, trigram, grammar, academic, full-corpus.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase101_103.py", + "phases": "101-103", + "category": "archaeological", + "purpose": "M293 iconographic analysis, PDF extraction, personal name lexicon construction.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase104_109.py", + "phases": "104-109", + "category": "sa_variant", + "purpose": "OCR pipeline, name signs, name SA, Tamil-Brahmi check, phoneme exhaustion, academic submission prep.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase110_115.py", + "phases": "110-115", + "category": "sa_variant", + "purpose": "Targeted SA, allographs, grammar inference, M→H upgrade, seal translations, significance testing.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase116_121.py", + "phases": "116-121", + "category": "sa_variant", + "purpose": "SA recalibration, grammar LOW, site semantics, arXiv prep, LOW→MED upgrade, full email.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase122_123.py", + "phases": "122-123", + "category": "cross_language", + "purpose": "Syllabic SA decipherment variant, Munda/BMAC substrate hypothesis testing.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase124_125.py", + "phases": "124-125", + "category": "structural_analysis", + "purpose": "Fish-sign polysemy analysis, Arthasastra text mining for trade vocabulary.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase126.py", + "phases": "126", + "category": "archaeological", + "purpose": "ICIT corpus integration and sign inventory alignment.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase127.py", + "phases": "127", + "category": "contact_zone", + "purpose": "Gulf corpus analysis, Roif mining, fish-sign site polysemy investigation.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase128_133.py", + "phases": "128-133", + "category": "sa_variant", + "purpose": "Continued SA refinement and anchor injection cycles.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase134_141.py", + "phases": "134-141", + "category": "structural_analysis", + "purpose": "Falsification suite, advancement testing, extended battery, master scorecard for decipherment quality.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase142_145.py", + "phases": "142-145", + "category": "sa_variant", + "purpose": "Further SA anchor injection and refinement cycles.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase146_155.py", + "phases": "146-155", + "category": "sa_variant", + "purpose": "Expanded SA parameter exploration and convergence testing.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase156_165.py", + "phases": "156-165", + "category": "sa_variant", + "purpose": "Advanced SA iterations with refined anchors and extended corpus coverage.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase166_168.py", + "phases": "166-168", + "category": "lm_scoring", + "purpose": "Sibilant validation, Meluhhan expansion, blocker SA — final pre-ICIT phase group.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase169_170.py", + "phases": "169-170", + "category": "structural_analysis", + "purpose": "Master synthesis and grammar variance analysis — computational frontier experiments.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase171_178.py", + "phases": "171-178", + "category": "structural_analysis", + "purpose": "Network centrality, betweenness stratification, and network deep-dive analysis of sign co-occurrence.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase179_180.py", + "phases": "179-180", + "category": "misc", + "purpose": "Recent literature mine and Mesopotamian contact evidence mining.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase181.py", + "phases": "181", + "category": "archaeological", + "purpose": "aDNA archaeogenetics mine — population genetics evidence for IVC language affiliation.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase182.py", + "phases": "182", + "category": "misc", + "purpose": "Deep evidence mine — comprehensive literature and evidence gathering.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase183.py", + "phases": "183", + "category": "misc", + "purpose": "Bulk mine 5000 — large-scale literature mining run.", + "status": "active", + "superseded_by": "phase184", + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase184.py", + "phases": "184", + "category": "misc", + "purpose": "Bulk mine 5000 second run with fresh topic clusters.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase185_189.py", + "phases": "185-189", + "category": "cross_language", + "purpose": "Fish-sign battery, Elamo-Dravidian gap analysis, 2026 hypotheses, commodity semantic, north Dravidian LM.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase190_192.py", + "phases": "190-192", + "category": "sa_variant", + "purpose": "Elamite anchor injection, grammar validation, anchor update proposal.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase193_195.py", + "phases": "193-195", + "category": "sa_variant", + "purpose": "SA rerun, SSRN fetch, grammar revalidation cycle.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase196_201.py", + "phases": "196-201", + "category": "sa_variant", + "purpose": "Mine3, top-8 analysis, DEDR lookup, triple-LM comparison, allograph, inscription reading.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase203_205.py", + "phases": "203-205", + "category": "cross_language", + "purpose": "E28 falsification, McAlpin extended cognates, Bayesian phylogenetics for language family testing.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase206_208.py", + "phases": "206-208", + "category": "sa_variant", + "purpose": "Anchor injection M692/M861, SA rerun 404, bulk mine fifth run.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase216_220.py", + "phases": "216-220", + "category": "sa_variant", + "purpose": "SA recalibration, site semantic analysis, arXiv preparation, Parpola/CISI alignment.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase221_225.py", + "phases": "221-225", + "category": "sa_variant", + "purpose": "P324/P122 investigation, CISI injection, slot mismatch analysis, PDF extraction.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase226_228.py", + "phases": "226-228", + "category": "sa_variant", + "purpose": "P122 phonetic analysis, P324 formula detection, CISI tripartite structure analysis.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase229.py", + "phases": "229", + "category": "sa_variant", + "purpose": "CISI anchor SA test and M122 sign upgrade.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase230_234.py", + "phases": "230-234", + "category": "contact_zone", + "purpose": "Cross-reference matrix, indirect bilingual mine/score, cultural/demographic analysis, P324 investigation.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase235_236.py", + "phases": "235-236", + "category": "cross_language", + "purpose": "Elamite–Proto-Dravidian bridge analysis, Sanskrit loanword mapping.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase237_246.py", + "phases": "237-246", + "category": "sa_variant", + "purpose": "Blocker mine, batch upgrades, synthesis, E41 DEDR, SA crossing experiments.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase248_253.py", + "phases": "248-254", + "category": "sa_variant", + "purpose": "Ceiling-breaker mine, allograph experiments, CISI allograph, semantic constraint.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase257_294.py", + "phases": "257-294", + "category": "sa_variant", + "purpose": "SA reruns, Yajnadevam corpus, DEDR resolution, final 605/605 full-corpus decipherment.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase295_297.py", + "phases": "295-297", + "category": "misc", + "purpose": "Bulk mine May 2026, mine cross-reference, gap analysis.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase298_308.py", + "phases": "298-308", + "category": "cross_language", + "purpose": "Deep Munda mine, Munda SA, substrate analysis, archaeology, anchored Munda SA, allograph, cross-researcher, semantic, DEDR, Elamite baseline.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_phase322_362.py", + "phases": "322-362", + "category": "sa_variant", + "purpose": "May 2026 decipherment advancement session — latest SA and analysis nodes.", + "status": "active", + "superseded_by": null, + "key_nodes": [], + "recommendation": "keep" + }, + { + "file": "experiment_graph_contact_zone.py", + "phases": "new", + "category": "contact_zone", + "purpose": "Contact-zone KL divergence, synthesis, and A/B comparison templates for quantifying inter-corpus contact signals.", + "status": "active", + "superseded_by": null, + "key_nodes": ["ContactZoneKLDivergence", "ContactZoneSynthesis", "ContactZoneABComparison"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_ab_language.py", + "phases": "new", + "category": "cross_language", + "purpose": "A/B language comparison templates using anchored SA: Dravidian vs Sanskrit, Munda, Hebrew, plus LM consistency matrix.", + "status": "active", + "superseded_by": null, + "key_nodes": ["AnchoredSALanguageAB", "LMConsistencyMatrix"], + "recommendation": "keep" + }, + { + "file": "experiment_graph_cross_culture.py", + "phases": "new", + "category": "cross_language", + "purpose": "Cultural contact matrix (pairwise corpus contact scores) and script family classifier (syllabary/logographic/abjad/alphabet).", + "status": "active", + "superseded_by": null, + "key_nodes": ["CulturalContactMatrix", "ScriptFamilyClassifier"], + "recommendation": "keep" + } +] diff --git a/frontend/dist/assets/index-BXsZCCru.js b/frontend/dist/assets/index-C42v41e-.js similarity index 61% rename from frontend/dist/assets/index-BXsZCCru.js rename to frontend/dist/assets/index-C42v41e-.js index c349e9f9..d8901433 100644 --- a/frontend/dist/assets/index-BXsZCCru.js +++ b/frontend/dist/assets/index-C42v41e-.js @@ -1,4 +1,4 @@ -(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={};/** +(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 ub(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var zf={exports:{}},fa={};/** * @license React * react-jsx-runtime.production.js * @@ -6,7 +6,7 @@ * * 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={};/** + */var Hx;function Xw(){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 Jw(){return Wx||(Wx=1,zf.exports=Xw()),zf.exports}var n=Jw(),Ef={exports:{}},Xe={};/** * @license React * react.production.js * @@ -14,7 +14,7 @@ * * 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={};/** + */var Gx;function Zw(){return Gx||(Gx=1,(function(t){function o(R,J){var N=R.length;R.push(J);e:for(;0>>1,Q=R[X];if(0>>1;Xc($,N))Yc(O,$)?(R[X]=O,R[Y]=N,X=Y):(R[X]=$,R[B]=N,X=B);else if(Yc(O,N))R[X]=O,R[Y]=N,X=Y;else break e}}return J}function c(R,J){var N=R.sortIndex-J.sortIndex;return N!==0?N:R.id-J.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,j=!1,_=!1,T=!1,w=typeof setTimeout=="function"?setTimeout:null,C=typeof clearTimeout=="function"?clearTimeout:null,k=typeof setImmediate<"u"?setImmediate:null;function D(R){for(var J=r(h);J!==null;){if(J.callback===null)l(h);else if(J.startTime<=R)l(h),J.sortIndex=J.expirationTime,o(g,J);else break;J=r(h)}}function H(R){if(_=!1,D(R),!j)if(r(g)!==null)j=!0,G||(G=!0,V());else{var J=r(h);J!==null&&P(H,J.startTime-R)}}var G=!1,z=-1,q=5,F=-1;function W(){return T?!0:!(t.unstable_now()-FR&&W());){var X=y.callback;if(typeof X=="function"){y.callback=null,b=y.priorityLevel;var Q=X(y.expirationTime<=R);if(R=t.unstable_now(),typeof Q=="function"){y.callback=Q,D(R),J=!0;break t}y===r(g)&&l(g),D(R)}else l(g);y=r(g)}if(y!==null)J=!0;else{var L=r(h);L!==null&&P(H,L.startTime-R),J=!1}}break e}finally{y=null,b=N,S=!1}J=void 0}}finally{J?V():G=!1}}}var V;if(typeof k=="function")V=function(){k(M)};else if(typeof MessageChannel<"u"){var I=new MessageChannel,A=I.port2;I.port1.onmessage=M,V=function(){A.postMessage(null)}}else V=function(){w(M,0)};function P(R,J){z=w(function(){R(t.unstable_now())},J)}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||125X?(R.sortIndex=N,o(h,R),r(g)===null&&R===r(h)&&(_?(C(z),z=-1):_=!0,P(H,N-X))):(R.sortIndex=Q,o(g,R),j||S||(j=!0,G||(G=!0,V()))),R},t.unstable_shouldYield=W,t.unstable_wrapCallback=function(R){var J=b;return function(){var N=b;b=J;try{return R.apply(this,arguments)}finally{b=N}}}})(Mf)),Mf}var Px;function e2(){return Px||(Px=1,Af.exports=Zw()),Af.exports}var Df={exports:{}},mn={};/** * @license React * react-dom.production.js * @@ -30,7 +30,7 @@ * * 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}/** + */var Fx;function t2(){if(Fx)return mn;Fx=1;var t=Ya();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(),Df.exports=t2(),Df.exports}/** * @license React * react-dom-client.production.js * @@ -38,41 +38,41 @@ * * 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=-1Q||(e.current=X[Q],X[Q]=null,Q--)}function $(e,i){Q++,X[Q]=e.current,e.current=i}var Y=L(null),O=L(null),K=L(null),ne=L(null);function se(e,i){switch($(K,i),$(O,e),$(Y,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}}B(Y),$(Y,e)}function pe(){B(Y),B(O),B(K)}function _e(e){e.memoizedState!==null&&$(ne,e);var i=Y.current,s=dx(i,e.type);i!==s&&($(O,e),$(Y,s))}function Se(e){O.current===e&&(B(Y),B(O)),ne.current===e&&(B(ne),la._currentValue=N)}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 +`+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"),Td=!1;if(zi)try{var Cr={};Object.defineProperty(Cr,"passive",{get:function(){Td=!0}}),window.addEventListener("test",Cr,Cr),window.removeEventListener("test",Cr,Cr)}catch{Td=!1}var eo=null,zd=null,sl=null;function dh(){if(sl)return sl;var e,i=zd,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 xS.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 xs=!1;function bS(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 vS(e,i){if(xs)return e==="compositionend"||!Dd&&yh(e,i)?(e=dh(),sl=zd=eo=null,xs=!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 Bd(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 zS=zi&&"documentMode"in document&&11>=document.documentMode,ys=null,Od=null,Dr=null,Id=!1;function Ah(e,i,s){var a=s.window===s?s.document:s.nodeType===9?s:s.ownerDocument;Id||ys==null||ys!==wt(a)||(a=ys,"selectionStart"in a&&Bd(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=Ql(Od,"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],we);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,we);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,we),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,we),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(Vw){return i(re,Vw)}),ct&&Ri(re,Qe),Ge}function _t(re,ie,le,we){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),we=f(ie,le.props.children),we.return=re,re=we;break e}}else if(ie.elementType===Ge||typeof Ge=="object"&&Ge!==null&&Ge.$$typeof===q&&Wo(Ge)===ie.type){s(re,ie.sibling),we=f(ie,le.props),$r(we,le),we.return=re,re=we;break e}s(re,ie);break}else i(re,ie);ie=ie.sibling}le.type===_?(we=Bo(le.props.children,re.mode,we,le.key),we.return=re,re=we):(we=gl(le.type,le.key,le.props,null,re.mode,we),$r(we,le),we.return=re,re=we)}return E(re);case j: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),we=f(ie,le.children||[]),we.return=re,re=we;break e}else{s(re,ie);break}else i(re,ie);ie=ie.sibling}we=Pd(le,re.mode,we),we.return=re,re=we}return E(re);case q:return le=Wo(le),_t(re,ie,le,we)}if(P(le))return Be(re,ie,le,we);if(V(le)){if(Ge=V(le),typeof Ge!="function")throw Error(l(150));return le=Ge.call(le),Fe(re,ie,le,we)}if(typeof le.then=="function")return _t(re,ie,wl(le),we);if(le.$$typeof===k)return _t(re,ie,yl(re,le),we);jl(re,le)}return typeof le=="string"&&le!==""||typeof le=="number"||typeof le=="bigint"?(le=""+le,ie!==null&&ie.tag===6?(s(re,ie.sibling),we=f(ie,le),we.return=re,re=we):(s(re,ie),we=Gd(le,re.mode,we),we.return=re,re=we),E(re)):s(re,ie)}return function(re,ie,le,we){try{Ir=0;var Ge=_t(re,ie,le,we);return Es=null,Ge}catch($e){if($e===zs||$e===vl)throw $e;var ht=Dn(29,$e,null,re.mode);return ht.lanes=we,ht.return=re,ht}finally{}}}var qo=eg(!0),tg=eg(!1),so=!1;function iu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function ou(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=hl(e),Ih(e,null,s),i}return pl(e,a,i,s),hl(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 su(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 ru=!1;function Wr(){if(ru){var e=Ts;if(e!==null)throw e}}function Ur(e,i,s,a){ru=!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===Cs&&(ru=!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,_u(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=OS(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{J.p=m,E!==null&&U.types!==null&&(E.types=U.types),R.T=E}}function qS(){}function ju(e,i,s,a){if(e.tag!==5)throw Error(l(476));var f=Ng(e).queue;Lg(e,f,i,N,s===null?qS:function(){return Bg(e),s(a)})}function Ng(e){var i=e.memoizedState;if(i!==null)return i;i={memoizedState:N,baseState:N,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Li,lastRenderedState:N},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 ku(){return un(la)}function Og(){return Xt().memoizedState}function Ig(){return Xt().memoizedState}function GS(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:Zd()},e.payload=i;return}i=i.return}}function PS(e,i,s){var a=In();s={lane:a,revertLane:0,gesture:null,action:s,hasEagerState:!1,eagerState:null,next:null},Dl(e)?Hg(i,s):(s=Ud(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(Dl(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 pl(e,i,f,0),Tt===null&&fl(),!1}catch{}finally{}if(s=Ud(e,i,f,a),s!==null)return En(s,e,a),Wg(s,i,a),!0}return!1}function _u(e,i,s,a){if(a={lane:2,revertLane:of(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Dl(e)){if(i)throw Error(l(479))}else i=Ud(e,s,a,2),i!==null&&En(i,e,2)}function Dl(e){var i=e.alternate;return e===Ke||i!==null&&i===Ke}function Hg(e,i){As=Cl=!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:El,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:El,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,Al(4194308,4,Eg.bind(null,i,e),s)},useLayoutEffect:function(e,i){return Al(4194308,4,e,i)},useInsertionEffect:function(e,i){Al(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=PS.bind(null,Ke,e),[a.memoizedState,e]},useRef:function(e){var i=vn();return e={current:e},i.memoizedState=e},useState:function(e){e=yu(e);var i=e.queue,s=$g.bind(null,Ke,i);return i.dispatch=s,[e.memoizedState,s]},useDebugValue:Su,useDeferredValue:function(e,i){var s=vn();return wu(s,e,i)},useTransition:function(){var e=yu(!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,Ds(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=Tl++,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),$u(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=K.current,ks(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=Zl(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=ks(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=Xd(),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=ks(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=Xd(),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),Il(i,i.updateQueue),Lt(i),null);case 4:return pe(),e===null&&lf(i.stateNode.containerInfo),Lt(i),null;case 10:return Mi(i.type),Lt(i),null;case 19:if(B(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=_l(e),m!==null){for(i.flags|=128,Vr(a,!1),e=m.updateQueue,i.updateQueue=e,Il(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()>ql&&(i.flags|=128,f=!0,Vr(a,!1),i.lanes=4194304)}else{if(!f)if(e=_l(m),e!==null){if(i.flags|=128,f=!0,e=e.updateQueue,i.updateQueue=e,Il(i,e),Vr(a,!0),a.tail===null&&a.tailMode==="hidden"&&!m.alternate&&!ct)return Lt(i),null}else 2*Oe()-a.renderingStartTime>ql&&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),lu(),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&&Il(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&&B(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 JS(e,i){switch(Yd(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 Se(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 B(Vt),null;case 4:return pe(),null;case 10:return Mi(i.type),null;case 22:case 23:return Nn(i),lu(),e!==null&&B(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(Yd(i),i.tag){case 3:Mi(Zt),pe();break;case 26:case 27:case 5:Se(i);break;case 4:pe();break;case 31:i.memoizedState!==null&&Nn(i);break;case 13:Nn(i);break;case 19:B(Vt);break;case 10:Mi(i.type);break;case 22:case 23:Nn(i),lu(),e!==null&&B(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 Hu(e,i,s){try{var a=e.stateNode;yw(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 Wu(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 Uu(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(Uu(e,i,s),e=e.sibling;e!==null;)Uu(e,i,s),e=e.sibling}function $l(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($l(e,i,s),e=e.sibling;e!==null;)$l(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,qu=!1,ym=typeof WeakSet=="function"?WeakSet:Set,ln=null;function KS(e,i){if(e=e.containerInfo,uf=rc,e=Rh(e),Bd(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(ff={focusedElem:e,selectionRange:s},rc=!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=Ju,Ju=null;var m=go,E=Ui;if(sn=0,Is=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{J.p=f,R.T=a,Ym(e,i)}}function Xm(e,i,s){i=qn(s,i),i=Eu(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 ef(e,i,s){var a=e.pingCache;if(a===null){a=e.pingCache=new ew;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)||(Fu=!0,f.add(s),e=sw.bind(null,e,i,s),i.then(e,e))}function sw(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()-Ul?(xt&2)===0&&$s(e,0):Yu|=s,Os===st&&(Os=0)),yi(e)}function Jm(e,i){i===0&&(i=Ne()),e=No(e,i),e!==null&&(mt(e,i),yi(e))}function rw(e){var i=e.memoizedState,s=0;i!==null&&(s=i.retryLane),Jm(e,s)}function aw(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 lw(e,i){return Ve(e,i)}var Xl=null,Ws=null,tf=!1,Jl=!1,nf=!1,xo=0;function yi(e){e!==Ws&&e.next===null&&(Ws===null?Xl=Ws=e:Ws=Ws.next=e),Jl=!0,tf||(tf=!0,dw())}function na(e,i){if(!nf&&Jl){nf=!0;do for(var s=!1,a=Xl;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);nf=!1}}function cw(){Km()}function Km(){Jl=tf=!1;var e=0;xo!==0&&vw()&&(e=xo);for(var i=Oe(),s=null,a=Xl;a!==null;){var f=a.next,m=Qm(a,i);m===0?(a.next=null,s===null?Xl=f:s.next=f,f===null&&(Ws=s)):(s=a,(e!==0||(m&3)!==0)&&(Jl=!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=Us;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 Ew(e){qi.D(e),vx("dns-prefetch",e,null)}function Rw(e,i){qi.C(e,i),vx("preconnect",e,i)}function Aw(e,i,s){qi.L(e,i,s);var a=Us;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=qs(e);break;case"script":m=Gs(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 Mw(e,i){qi.m(e,i);var s=Us;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=Gs(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 Dw(e,i,s){qi.S(e,i,s);var a=Us;if(a&&e){var f=pi(a).hoistableStyles,m=qs(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))&&bf(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,tc(E,i,a)}E={type:"stylesheet",instance:E,count:1,state:U},f.set(m,E)}}}function Lw(e,i){qi.X(e,i);var s=Us;if(s&&e){var a=pi(s).hoistableScripts,f=Gs(e),m=a.get(f);m||(m=s.querySelector(aa(f)),m||(e=y({src:e,async:!0},i),(i=Xn.get(f))&&vf(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 Nw(e,i){qi.M(e,i);var s=Us;if(s&&e){var a=pi(s).hoistableScripts,f=Gs(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))&&vf(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=K.current)?ec(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=qs(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=qs(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||Bw(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=Gs(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 qs(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 Bw(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 Gs(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),tc(a,s.precedence,e),i.instance=a;case"stylesheet":f=qs(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))&&bf(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,tc(m,s.precedence,e),i.instance=m;case"script":return m=Gs(s.src),(f=e.querySelector(aa(m)))?(i.instance=f,Bt(f),f):(a=s,(f=Xn.get(m))&&(a=y({},s),vf(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,tc(a,s.precedence,e));return i.instance}function tc(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 Ow(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 Iw(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=qs(a.href),m=i.querySelector(ra(f));if(m){i=m._p,i!==null&&typeof i=="object"&&typeof i.then=="function"&&(e.count++,e=ic.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))&&bf(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=ic.bind(e),i.addEventListener("load",s),i.addEventListener("error",s))}}var Sf=0;function $w(e,i){return e.stylesheets&&e.count===0&&sc(e,e.stylesheets),0Sf?50:800)+i);return e.unsuspend=s,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(f)}}:null}function ic(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)sc(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var oc=null;function sc(e,i){e.stylesheets=null,e.unsuspend!==null&&(e.count++,oc=new Map,i.forEach(Hw,e),oc=null,ic.call(e))}function Hw(e,i){if(!(i.state.loading&4)){var s=oc.get(e);if(s)var a=s.get(null);else{s=new Map,oc.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(),Rf.exports=n2(),Rf.exports}var o2=i2();const us="/api/v1";function s2(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 pb(t,o,r,l,c){const d=s2(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(`${us}${o}`,c);if(!d.ok){const u=await d.text().catch(()=>"");throw pb(t,o,d.status,d.statusText,u)}return d.json()}const r2={sequences:"#059669",freq_map:"#2563eb",profiles:"#7c3aed",clusters:"#d97706",number:"#dc2626",text:"#0d9488",json:"#4f46e5",any:"#64748b",claims:"#b45309",papers:"#0891b2"},a2=()=>me("GET","/experiment-graphs/catalog"),hb=()=>me("GET","/experiment-graphs"),Jx=t=>me("GET",`/experiment-graphs/${t}`),Lf=t=>me("POST","/experiment-graphs",t),l2=(t,o)=>me("PUT",`/experiment-graphs/${t}`,o),c2=t=>me("DELETE",`/experiment-graphs/${t}`),Ba=()=>me("GET","/health"),d2=()=>me("GET","/status"),ld=()=>me("GET","/texts"),u2=t=>me("GET",`/texts/${t}`),f2=t=>me("POST","/texts",t),p2=(t,o)=>me("PUT",`/texts/${t}`,o),h2=t=>me("DELETE",`/texts/${t}`),g2=(t,o,r=!0)=>me("POST",`/texts/${t}/detect-direction`,{words:null,update_field:r}),Oa=()=>me("GET","/jobs"),Fc=t=>me("POST","/jobs",t),fp=t=>me("DELETE",`/jobs/${t}`),pp=(t=!1)=>me("DELETE",t?"/jobs?finished_only=true":"/jobs"),gb=t=>me("POST",`/jobs/${t}/pause`),mb=t=>me("POST",`/jobs/${t}/resume`),xb=()=>me("POST","/jobs/pause-all"),yb=()=>me("POST","/jobs/resume-all"),m2=()=>me("POST","/jobs/clear-cache");function x2(){localStorage.removeItem("geb_run_cache"),localStorage.removeItem("glossa_seq_run_queue"),localStorage.removeItem("glossa_dashboard_insight_v2")}const bb=t=>me("GET",`/jobs/${t}/results`),cd=()=>me("GET","/settings"),y2=(t,o)=>me("POST","/settings/verify-key",{key_name:t,key_value:null}),sr=t=>me("PUT","/settings",t),b2=()=>me("GET","/catalog"),vb=()=>me("GET","/catalog/pipelines"),v2=t=>me("GET",`/reports${t?`?project_id=${t}`:""}`),S2=t=>me("DELETE",`/reports/${t}`),Nf=t=>`/api/v1/reports/${t}/download`,w2=()=>me("GET","/reports/templates"),j2=t=>me("POST","/reports/generate",{template_id:t}),k2=t=>me("POST",`/reports/${t}/open-folder`),_2=(t,o)=>me("POST",`/pipelines/${t}/duplicate`,{new_id:o}),C2=t=>me("DELETE",`/pipelines/${t}`),T2=t=>me("POST","/pipelines/import",{source_path:t}),Ip=()=>me("GET","/studies");async function*z2(t,o){if(!t.ok){const d=await t.text().catch(()=>"");throw pb("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(`${us}/experiment-graphs/${t}/run`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({kwargs:o,notify:l}),signal:r});yield*z2(c,r)}const E2=()=>me("GET","/experiments/metadata"),$p=()=>me("GET","/experiments"),Bc=t=>me("GET",`/texts/${t}/entropy`),R2=(t,o=2,r=50)=>me("GET",`/texts/${t}/ngrams?n=${o}&limit=${r}`),A2=(t,o,r=5)=>me("GET",`/texts/${t}/concordance?q=${encodeURIComponent(o)}&w=${r}`),Kx=(t,o)=>`/api/v1/texts/${t}/export?fmt=${o}`,M2=t=>me("GET",`/hypotheses${t?`?project_id=${t}`:""}`),za=t=>me("POST","/hypotheses",t),ka=(t,o)=>me("PUT",`/hypotheses/${t}`,o),D2=t=>me("DELETE",`/hypotheses/${t}`),L2=t=>me("GET",`/notebooks${t?`?project_id=${t}`:""}`),N2=t=>me("POST","/notebooks",t),B2=(t,o)=>me("PUT",`/notebooks/${t}`,o),O2=t=>me("DELETE",`/notebooks/${t}`),I2=()=>me("GET","/citations"),Qx=t=>me("POST","/citations",t),$2=(t,o)=>me("PUT",`/citations/${t}`,o),H2=t=>me("DELETE",`/citations/${t}`),gp=(t,o)=>me("POST","/ai/chat",t,o),Sb=t=>me("POST","/ai/execute-action",t),W2=t=>me("POST","/ai/decipher",t),U2=t=>me("POST","/ai/draft-section",t),wb=t=>me("POST","/ai/hypotheses/generate",t),jb=t=>me("POST","/ai/experiment-chain",t),q2=t=>me("POST","/ai/synthesize",t),kb=t=>me("POST","/ai/sign-reading",t),G2=()=>me("GET","/ai/research-context"),_b=t=>me("POST","/ai/report-synthesis",t),P2=()=>me("POST","/system/peaks/clear"),F2=()=>"/api/v1/system/metrics/stream",Y2=()=>me("GET","/ollama/library"),V2=()=>me("GET","/ollama/recommend"),X2=t=>me("DELETE",`/ollama/models/${encodeURIComponent(t)}`),J2="glossa_ollama_ctx",K2=()=>parseInt(localStorage.getItem(J2)??"4096",10)||4096,Q2=()=>me("GET","/report-templates"),Z2=t=>me("POST","/report-templates",t),ej=t=>me("DELETE",`/report-templates/${t}`),tj=t=>me("GET","/anchor-sets"),nj=t=>me("POST","/anchor-sets",t),ij=t=>me("DELETE",`/anchor-sets/${t}`),oj=t=>{const r=new URLSearchParams().toString();return me("GET",`/corpus-catalogue${r?`?${r}`:""}`)},sj=t=>me("POST",`/corpus-catalogue/${t}/import`),Cb=()=>me("GET","/env/status"),rj=()=>me("GET","/env/packages"),aj=()=>fetch(`${us}/env/setup`,{method:"POST"}),lj=()=>fetch(`${us}/env/rebuild`,{method:"POST"}),cj=()=>fetch(`${us}/env/upgrade`,{method:"POST"}),dj=()=>"/api/v1/terminal/log/stream",uj=()=>me("POST","/terminal/log/purge"),fj=(t,o)=>fetch(`${us}/terminal/run`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({command:t,cwd:o,use_venv:!0})});function pj(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 hj=(t={})=>me("GET",`/discovery/items${pj(t)}`),gj=(t,o,r)=>me("POST",`/discovery/items/${encodeURIComponent(t)}/status`,{status:o,notes:r}),Tb=()=>me("GET","/discovery/topics"),zb=()=>me("GET","/discovery/sources"),Bf=(t="status")=>me("GET",`/discovery/stats?group=${t}`),Yc=t=>me("POST","/discovery/fetch",t),Hp=t=>me("POST","/discovery/mine",t),mj=(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:""}`)},xj=(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:""}`)},yj=()=>me("GET","/dashboard/decipherment"),bj=()=>me("GET","/dashboard/latest-insight"),vj=()=>me("GET","/notifications/recipients"),Sj=t=>me("POST","/notifications/recipients",t),Zx=(t,o)=>me("PATCH",`/notifications/recipients/${encodeURIComponent(t)}`,o),wj=t=>me("DELETE",`/notifications/recipients/${encodeURIComponent(t)}`),Eb=()=>me("GET","/notifications/status"),jj=(t=100)=>me("GET",`/notifications/log?limit=${t}`),kj=()=>me("POST","/notifications/test"),_j=()=>me("POST","/notifications/graph/start"),Cj=t=>me("POST","/notifications/graph/poll",{session_id:t}),Tj=()=>me("POST","/notifications/graph/disconnect"),Rb=()=>me("GET","/discovery/scheduler/status"),Ab=()=>me("POST","/discovery/scheduler/start"),Mb=()=>me("POST","/discovery/scheduler/stop"),Db=()=>me("GET","/projects"),zj=()=>me("GET","/projects/active"),pc=(t,o)=>me("PUT",`/projects/${t}`,o),Lb=t=>me("POST",`/projects/${t}/activate`),Ej=t=>me("DELETE",`/projects/${t}`),Rj=t=>me("GET",`/correspondences${t?`?project_id=${t}`:""}`),ey=t=>me("POST","/correspondences",t),ty=(t,o)=>me("PUT",`/correspondences/${t}`,o),Aj=t=>me("DELETE",`/correspondences/${t}`),Mj=t=>me("POST","/correspondences/parse",t),Nb=(t=!1,o)=>{const r=new URLSearchParams;t&&r.set("enabled_only","true");const l=r.toString();return me("GET",`/providers${l?`?${l}`:""}`)},Dj=t=>me("POST","/providers",t),ny=(t,o)=>me("PATCH",`/providers/${t}`,o),Lj=t=>me("DELETE",`/providers/${t}`),Nj=t=>me("POST",`/providers/${t}/test`),Bj=()=>me("GET","/providers/detect-ollama"),Oj=()=>me("GET","/providers/cloud-providers"),Ij=()=>me("GET","/model-assignments"),$j=(t,o)=>me("PUT",`/model-assignments/${t}`,o),Hj=(t="mixed")=>me("POST",`/model-assignments/auto-configure?profile=${t}`),Bb=t=>me("GET","/model-intelligence/scores"),Ob=()=>me("POST","/model-intelligence/sync"),Wj=()=>me("POST","/model-intelligence/test-hf"),Of=[{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."}],Uj=(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}`:""}`)},qj=(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}`:""}`)},Gj=()=>me("GET","/indus-evidence/hypotheses"),Pj=()=>me("GET","/indus-evidence/sweep/config"),Fj=t=>me("PUT","/indus-evidence/sweep/config",t),Yj=()=>me("POST","/indus-evidence/sweep/run"),Vj=()=>me("GET","/indus-evidence/sweep/candidates"),Ib=t=>me("POST","/indus-evidence/sweep/intake",t),Xj=t=>me("POST","/indus-evidence/import-url",t),Jj=()=>me("POST","/indus-evidence/intake/run"),Kj=t=>{const o=new FormData;return o.append("file",t),fetch(`${us}/indus-evidence/upload`,{method:"POST",body:o})},$b=x.createContext({toast:()=>{},notifications:[],unreadCount:0,markAllRead:()=>{},clearNotification:()=>{},clearAllNotifications:()=>{}});let Qj=0;function Zj({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 j=d.current.get(S);j&&(clearTimeout(j),d.current.delete(S))},[]),p=x.useCallback((S,j="info",_=3500)=>{const T=++Qj;r(C=>[...C.slice(-5),{id:T,message:S,type:j}]),c(C=>[{id:T,message:S,type:j,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(j=>({...j,read:!0}))),[]),h=x.useCallback(S=>c(j=>j.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($b.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($b)}const ek=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 Fs({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 tk({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 nk(){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,j]=x.useState(!1),_=x.useRef({cpu:[],ram:[],gpu:[],disk_read:[],disk_write:[],net_send:[],net_recv:[]}),T=x.useCallback((q,F)=>{const W=_.current[q]??[];W.push(F),W.length>ek&&W.shift(),_.current[q]=W},[]);x.useEffect(()=>{const q=async()=>{try{const[W,M]=await Promise.all([Ba(),d2()]);r(W),c(M),b(null),b2().then(u).catch(()=>{}),Ip().then(V=>g(V.length)).catch(()=>{})}catch(W){b(W instanceof Error?W.message:"Connection failed")}};q();const F=setInterval(q,8e3);return()=>clearInterval(F)},[]);const w=x.useRef(null),[C,k]=x.useState(!1),D=x.useCallback(()=>{if(w.current)return;const q=new EventSource(F2());w.current=q,k(!0),q.onmessage=F=>{var W;try{const M=JSON.parse(F.data);v(M),T("cpu",M.cpu.percent),T("ram",M.ram.percent),T("gpu",((W=M.gpu[0])==null?void 0:W.utilization_pct)??0),T("disk_read",M.disk.read_mbps),T("disk_write",M.disk.write_mbps),T("net_send",M.network.send_mbps*1e3),T("net_recv",M.network.recv_mbps*1e3)}catch{}},q.onerror=()=>{q.close(),w.current=null,k(!1),setTimeout(D,3e3)}},[T]);x.useEffect(()=>(D(),()=>{var q;(q=w.current)==null||q.close(),w.current=null}),[D]);const H=async()=>{j(!0);try{await P2(),t("Peaks cleared","success")}catch{t("Failed to clear peaks","error")}finally{j(!1)}},G=(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:H,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 ${G?"#bbf7d0":"#fca5a5"}`,background:G?"#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:G?"#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(([q,F])=>n.jsxs("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:6,background:"#f3f4f6",color:"#374151"},children:[q,": ",F]},q))}),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:Ys,children:[n.jsx("span",{style:Vs,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(tk,{values:z.cpu.per_core_pct})]}),n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Ys,children:[n.jsx("span",{style:Vs,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(Fs,{label:"Available",current:z.ram.available_gb.toString(),unit:" GB",color:"#16a34a"}),n.jsx(Fs,{label:"Used",current:z.ram.used_gb.toString(),unit:" GB"})]})]}),z.gpu.length>0&&n.jsxs("section",{style:Jo,children:[n.jsxs("div",{style:Ys,children:[n.jsx("span",{style:Vs,children:"GPU"}),n.jsx("span",{style:{fontSize:11,color:"#6b7280"},children:z.gpu[0].name})]}),z.gpu.map((q,F)=>n.jsx("div",{style:{marginBottom:10},children:n.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:10},children:[n.jsx(Vo,{value:q.utilization_pct,label:"GPU Util",color:"#16a34a",peak:z.gpu_peaks.utilization_pct,sub:`${q.temperature_c!==null?q.temperature_c+"°C":""}`}),n.jsx(Vo,{value:q.memory_utilization_pct,label:"VRAM %",color:"#d97706",peak:z.gpu_peaks.memory_utilization_pct,sub:`${q.memory_used_mb} / ${q.memory_total_mb} MB`}),n.jsx(Vo,{value:q.memory_used_mb/q.memory_total_mb*100,label:"VRAM Used",color:"#d97706",sub:`${(q.memory_used_mb/1024).toFixed(1)} / ${(q.memory_total_mb/1024).toFixed(1)} GB`})]})},F)),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:Ys,children:[n.jsx("span",{style:Vs,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(Fs,{label:"Read",current:z.disk.read_mbps.toFixed(2),unit:" MB/s",color:"#2563eb",peak:z.disk.peak_read_mbps.toFixed(2)}),n.jsx(Fs,{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:Ys,children:[n.jsx("span",{style:Vs,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(Fs,{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(Fs,{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:Ys,children:n.jsx("span",{style:Vs,children:"Registered Pipelines"})}),n.jsx("ul",{style:{columnCount:2,paddingLeft:"1.2rem",margin:0,fontSize:12},children:l.pipelines.map(q=>n.jsx("li",{style:{fontFamily:"monospace",marginBottom:2},children:q},q))})]})]}),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},Ys={display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12},Vs={fontSize:12,fontWeight:700,color:"#374151",textTransform:"uppercase",letterSpacing:.5};function ik(){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 ok({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 sk(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 Hb=x.createContext({isOpen:!1,request:null,openChat:()=>{},closeChat:()=>{},toggleChat:()=>{},isDocked:!1,setDocked:()=>{}});function rk({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(Hb.Provider,{value:{isOpen:o,request:l,openChat:p,closeChat:g,toggleChat:h,isDocked:d,setDocked:u},children:t})}function fs(){return x.useContext(Hb)}const Wb=["linguistic","ancient","dna","code","random","other"],Ub=[{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"}},If=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 ak({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 Xs({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 lk(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 ck={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 dk({tokens:t}){const o={numeric:0,latin:0,ancient:0,punctuation:0,mixed:0};for(const u of t)o[lk(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=ck[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 uk({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,j]=x.useState(t.name),[_,T]=x.useState(t.corpus_type),[w,C]=x.useState(t.content.join(" ")),[k,D]=x.useState("space"),[H,G]=x.useState(t.reading_direction??"unknown"),[z,q]=x.useState(!1),[F,W]=x.useState(!1),[M,V]=x.useState(2),[I,A]=x.useState(null),[P,R]=x.useState(!1),[J,N]=x.useState(""),[X,Q]=x.useState(null),[L,B]=x.useState(!1),[$,Y]=x.useState(null),[O,K]=x.useState(!1),[ne,se]=x.useState("analyze"),[pe,_e]=x.useState(""),[Se,ke]=x.useState(null),[te,de]=x.useState(null),[Ce,ze]=x.useState(!1),ve=x.useRef(null),{menu:De,show:Me,close:Ve}=ik(),{openChat:Le}=fs(),Ae=y?t.content.filter(fe=>fe.toLowerCase().includes(y.toLowerCase())):t.content,Ue=Math.ceil(Ae.length/If),Oe=Ae.slice(h*If,(h+1)*If),dt=async()=>{W(!0);try{let fe;k==="line"?fe=w.split(` +`).map(Et=>Et.trim()).filter(Boolean):k==="char"?fe=w.replace(/\s/g,"").split(""):fe=w.trim().split(/\s+/).filter(Boolean);const ft=await p2(t.id,{name:S.trim(),corpus_type:_,content:fe,reading_direction:H});o(ft),c("Corpus updated","success")}catch(fe){c(fe instanceof Error?fe.message:"Save failed","error")}finally{W(!1)}},it=async()=>{q(!0);try{const fe=await g2(t.id);G(fe.inferred_direction);const ft=await u2(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{q(!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 R2(t.id,M))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{R(!1)}},zt=async()=>{if(J.trim()){B(!0);try{Q(await A2(t.id,J.trim()))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{B(!1)}}},ae=x.useCallback(async()=>{if(!$){K(!0);try{Y(await Bc(t.id))}catch(fe){c(fe instanceof Error?fe.message:"Error","error")}finally{K(!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([Bc(t.id),Bc(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 h2(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,[...sk(Oe.join(" "),"Copy page"),{label:"Copy all tokens",icon:"📄",action:()=>navigator.clipboard.writeText(t.content.join(" ")).catch(()=>{})}]),children:Oe.join(" ")}),n.jsx(ok,{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=>j(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:Wb.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:H,onChange:fe=>G(fe.target.value),style:{...hn,flex:1},children:Ub.map(fe=>n.jsx("option",{value:fe.value,children:fe.label},fe.value))}),n.jsx("button",{onClick:it,disabled:z,style:{...Oc,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:k,onChange:fe=>D(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:F,style:ts,children:F?"Saving…":"Save"}),n.jsx("button",{onClick:yt,style:Oc,children:"Copy All"}),n.jsx("button",{onClick:()=>{var fe;return(fe=ve.current)==null?void 0:fe.click()},style:Oc,children:"Import File"})]})]}),p==="stats"&&n.jsxs("div",{children:[O&&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(Xs,{label:"H1 (bits)",value:$.h1,color:"#2563eb"}),n.jsx(Xs,{label:"H2/H1",value:$.h2_h1_ratio??"—",color:"#7c3aed"}),n.jsx(Xs,{label:"Cond H",value:$.conditional_h,color:"#d97706"}),n.jsx(Xs,{label:"TTR",value:$.type_token_ratio.toFixed(3),color:"#16a34a"}),n.jsx(Xs,{label:"Zipf ρ",value:$.zipf_correlation.toFixed(3),color:"#6b7280"}),n.jsx(Xs,{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(ak,{values:$.zipf_table.map(fe=>fe.log_freq),color:"#7c3aed"})]})]}),n.jsx(dk,{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:()=>V(fe),style:{...xn,background:M===fe?"#1e3a5f":"#f3f4f6",color:M===fe?"#fff":"#374151"},children:fe},fe)),n.jsx("button",{onClick:rn,disabled:P,style:ts,children:P?"Loading…":"Load"})]}),I&&n.jsxs(n.Fragment,{children:[n.jsx(oy,{data:I.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:Js,children:"N-gram"}),n.jsx("th",{style:Js,children:"Count"})]})}),n.jsx("tbody",{children:I.slice(0,50).map(fe=>n.jsxs("tr",{children:[n.jsx("td",{style:Ks,children:n.jsx("code",{children:fe.ngram})}),n.jsx("td",{style:Ks,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:J,onChange:fe=>N(fe.target.value),onKeyDown:fe=>{fe.key==="Enter"&&zt()},style:{...hn,flex:1}}),n.jsx("button",{onClick:zt,disabled:L,style:ts,children:L?"…":"Search"})]}),X&&n.jsxs("div",{children:[n.jsxs("div",{style:{fontSize:12,color:"#6b7280",marginBottom:8},children:[X.total.toLocaleString()," occurrences of ",n.jsxs("code",{children:['"',X.query,'"']})]}),n.jsx("div",{style:{maxHeight:300,overflowY:"auto"},children:X.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:{...ts,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:ts,children:Ce?"Loading…":"Compare"})]}),te&&Se&&(()=>{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:Js,children:"Metric"}),n.jsx("th",{style:Js,children:t.name.slice(0,20)}),n.jsx("th",{style:Js,children:(fe==null?void 0:fe.name.slice(0,20))??pe}),n.jsx("th",{style:Js,children:"Δ"})]})}),n.jsx("tbody",{children:ft.map(([Et,qt])=>{const Gt=te[qt]??0,Ct=Se[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:{...Ks,fontWeight:600},children:Et}),n.jsx("td",{style:Ks,children:typeof Gt=="number"?Number.isInteger(Gt)?Gt.toLocaleString():Gt.toFixed(3):"—"}),n.jsx("td",{style:Ks,children:typeof Ct=="number"?Number.isInteger(Ct)?Ct.toLocaleString():Ct.toFixed(3):"—"}),n.jsx("td",{style:{...Ks,color:Ne?oe>0?"#16a34a":"#dc2626":"#9ca3af",fontWeight:Ne?700:400},children:oe!==null?(oe>0?"+":"")+oe.toFixed(3):"—"})]},qt)})})]})})()]})]})]})]})}function fk({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),j=x.useRef(null),_=C=>u==="char"?C.replace(/\s+/g,"").split(""):u==="line"?C.split(` +`).map(k=>k.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 k=await f2({name:r.trim(),corpus_type:c,content:C,reading_direction:g});t(k),l(""),y(""),h("unknown"),o("Corpus created","success")}catch(k){o(k instanceof Error?k.message:"Upload failed","error")}finally{S(!1)}},w=C=>{var H;const k=(H=C.target.files)==null?void 0:H[0];if(!k)return;r||l(k.name.replace(/\.[^.]+$/,""));const D=new FileReader;D.onload=G=>{var q;const z=(q=G.target)==null?void 0:q.result;if(k.name.endsWith(".json"))try{const F=JSON.parse(z);y(Array.isArray(F)?F.join(" "):(F.content??[]).join(" ")||z)}catch{y(z)}else y(z)},D.readAsText(k),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:Wb.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:Ub.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:ts,children:b?"Uploading…":"Upload"}),n.jsx("button",{onClick:()=>{var C;return(C=j.current)==null?void 0:C.click()},style:Oc,children:"↑ Import File (.txt/.csv/.json)"}),n.jsx("input",{ref:j,type:"file",accept:".txt,.csv,.json",style:{display:"none"},onChange:w})]})]})]})}function pk({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"),[j,_]=x.useState("all"),T=async()=>{d(!0);try{l(await oj())}catch(F){o(F instanceof Error?F.message:"Failed to load catalogue","error")}finally{d(!1)}},w=async F=>{var W;if(!F.local_module){o(`No bundled module for '${F.name}'. Download from the source URL and upload manually via + Upload / import corpus.`,"warning");return}p(F.id);try{const M=await sj(F.id);M.imported?(l(V=>V.map(I=>I.id===F.id?{...I,already_imported:!0}:I)),o(`Imported '${M.name}' (${(W=M.tokens)==null?void 0:W.toLocaleString()} tokens)`,"success"),t()):o(`'${M.name}' already in your corpora`,"info")}catch(M){o(M instanceof Error?M.message:"Import failed","error")}finally{p(null)}},C=Array.from(new Set(r.map(F=>F.script_type).filter(Boolean))).sort(),k=r.filter(F=>{const W=!g||F.name.toLowerCase().includes(g.toLowerCase())||F.language.toLowerCase().includes(g.toLowerCase())||F.language_family.toLowerCase().includes(g.toLowerCase()),M=v==="all"||(v==="undeciphered"?!!F.is_undeciphered:!F.is_undeciphered),V=b==="all"||F.script_type===b,I=j==="all"||(j==="bundled"?!!F.local_module:!F.local_module);return W&&M&&V&&I}),D={};for(const F of k){const W=F.language_family||"Other";(D[W]=D[W]||[]).push(F)}const H={abjad:"#7c3aed",syllabary:"#059669",logosyllabic:"#d97706",logographic:"#dc2626",alphabet:"#2563eb",unknown:"#6b7280"},G={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"}},q=F=>F>0?`~${F>=1e3?`${(F/1e3).toFixed(F>=1e4?0:1)}K`:F.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:F=>h(F.target.value),style:{...hn,width:220}}),["all","undeciphered","deciphered"].map(F=>n.jsx("button",{onClick:()=>y(F),style:{...xn,background:v===F?"#059669":void 0,color:v===F?"#fff":void 0},children:F==="all"?"All":F==="undeciphered"?"🔓 Undeciphered":"✓ Deciphered"},F)),n.jsx("div",{style:{display:"flex",gap:4},children:["all","bundled","manual"].map(F=>n.jsx("button",{onClick:()=>_(F),style:{...xn,background:j===F?"#2563eb":void 0,color:j===F?"#fff":void 0},title:F==="bundled"?"One-click import available":F==="manual"?"Manual upload required":"All",children:F==="all"?"⬇ Any":F==="bundled"?"⬇ 1-click":"✎ Manual"},F))}),n.jsx("button",{onClick:()=>void T(),style:xn,title:"Reload catalogue",children:"⟳"}),n.jsxs("span",{style:{fontSize:11,color:"#6b7280",marginLeft:"auto"},children:[k.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(F=>{const W=H[F]??"#6b7280";return n.jsx("button",{onClick:()=>S(b===F?"all":F),style:{...xn,padding:"2px 8px",fontSize:10,background:b===F?W:W+"15",color:b===F?"#fff":W,border:`1px solid ${W}40`,fontWeight:b===F?700:400},children:G[F]??F},F)})]}),c&&n.jsx("p",{style:{color:"#6b7280",fontSize:13},children:"Loading catalogue…"}),Object.entries(D).sort(([F],[W])=>F.localeCompare(W)).map(([F,W])=>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:[F," ",n.jsxs("span",{style:{fontWeight:400,opacity:.6},children:["(",W.length,")"]})]}),W.map(M=>{const V=H[M.script_type]??"#6b7280",I=!!M.local_module,A=q(M.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:M.is_undeciphered?"#7c2d12":"#1e3a5f"},children:M.name}),n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:V+"18",color:V,fontWeight:700},children:G[M.script_type]??M.script_type}),(()=>{const P=M.reading_direction??"unknown",R=z[P]??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})})(),M.is_undeciphered&&n.jsx("span",{style:{fontSize:9,color:"#dc2626",fontWeight:700},children:"🔓"}),I&&!M.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:[M.language," · ",M.period," · ",A," · ",M.license]})]}),n.jsx("div",{style:{display:"flex",gap:4,flexShrink:0},children:M.already_imported?n.jsx("span",{style:{fontSize:10,color:"#059669",fontWeight:700},children:"✓ Imported"}):I?n.jsx("button",{onClick:()=>void w(M),disabled:u===M.id,style:{...xn,background:u===M.id?"#d1d5db":"#059669",color:"#fff",border:"none",fontSize:10},children:u===M.id?"⏳":"↓ Import"}):n.jsx("a",{href:M.source_url,target:"_blank",rel:"noopener noreferrer",style:{...xn,textDecoration:"none",fontSize:10,color:"#374151"},title:`Source: ${M.source_url}`,children:"Source ↗"})})]},M.id)})]},F)),!c&&k.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 hk(){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 tj())}catch(w){t(w instanceof Error?w.message:"Failed to load","error")}finally{c(!1)}},j=w=>w.split(` +`).map(C=>C.trim()).filter(Boolean).map(C=>{const[k,D,H,...G]=C.split(/\s+|\t/);return{cipher:k??"",target:D??"",confidence:H??"high",note:G.join(" ")}}).filter(C=>C.cipher&&C.target),_=async()=>{if(!p.trim()){t("Name required","warning");return}try{const w=await nj({name:p.trim(),language:h.trim(),pairs:j(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 ij(w),r(C=>C.filter(k=>k.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} +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,k)=>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]},k)),w.pairs.length>8&&n.jsxs("span",{style:{fontSize:10,color:"#9ca3af"},children:["+",w.pairs.length-8," more"]})]})]},w.id))]})]})}function gk({onSelect:t}){const[o,r]=x.useState([]),[l,c]=x.useState(!0),[d,u]=x.useState(null),p=async()=>{c(!0);try{r(await ld()),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:{...ts,background:"#6b7280",padding:"4px 12px",fontSize:12},children:"⟳ Refresh"})]}),n.jsx(fk,{onCreated:g=>r(h=>[g,...h])}),n.jsx(pk,{onImported:()=>void p()}),n.jsx(hk,{}),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(uk,{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},ts={background:"#2563eb",color:"#fff",border:"none",borderRadius:4,padding:"6px 14px",fontSize:12,cursor:"pointer",fontWeight:600,whiteSpace:"nowrap"},Oc={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"},Js={textAlign:"left",padding:"4px 10px 4px 0",borderBottom:"2px solid #e5e7eb",color:"#374151"},Ks={padding:"3px 10px 3px 0",borderBottom:"1px solid #f3f4f6",verticalAlign:"top"};function mk(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 Vc(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 Ea(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 xk=new Set(["node_count","nodes_done","stall_reason"]);function yk(t){return Object.fromEntries(Object.entries(t).filter(([o])=>!o.startsWith("_")&&!xk.has(o)))}function bk(t){return t.replace(/_/g," ").replace(/\b\w/g,o=>o.toUpperCase())}function vk(t){return t==null?"—":typeof t=="boolean"?t?"Yes":"No":typeof t=="object"?JSON.stringify(t):String(t)}function Sk(t){if(!t)return null;try{const o=JSON.parse(t);return typeof o=="object"&&o!==null?o:null}catch{return null}}function wk(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 qb({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(` +`+r:""}`,[g,h]=x.useState(!1),[v,y]=x.useState(!1),b=()=>{navigator.clipboard.writeText(p).then(()=>{h(!0),setTimeout(()=>h(!1),1500)})},S=Sk(o),j=S?S.error??S.message??JSON.stringify(S,null,2):o,_=wk(j||""),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:j||"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:bk(w)}),n.jsx("td",{style:{padding:"4px 0",color:"#111827",wordBreak:"break-all",fontFamily:typeof C=="string"?"inherit":"monospace"},children:vk(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 jk(){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),[j,_]=x.useState(new Set),T=x.useRef(new Map),[w,C]=x.useState(""),[k,D]=x.useState("block_entropy"),[H,G]=x.useState('{"text_id": ""}'),[z,q]=x.useState(!1),[F,W]=x.useState(null),[M,V]=x.useState(null),I=x.useCallback(async(O=!1)=>{O&&d(!0);try{const K=await Oa();o(K.sort((ne,se)=>se.created_at.localeCompare(ne.created_at))),p(new Date),h(null)}catch(K){h(K instanceof Error?K.message:"Failed to load jobs")}finally{l(!1),O&&d(!1)}},[]);x.useEffect(()=>{I();const O=setInterval(I,3e3);return vb().then(y).catch(()=>{}),()=>clearInterval(O)},[I]);const A=x.useCallback(O=>async()=>{try{await Fc({name:`${O.name} (retry)`,pipeline:O.pipeline,params:yk(O.params??{})}),await I()}catch(K){alert(K instanceof Error?K.message:"Retry failed")}},[I]),P=async()=>{if(confirm("Delete all jobs and results?")){S(!0);try{await pp(),await I()}finally{S(!1)}}},R=async()=>{if(!w.trim()){W("Job name is required");return}let O;try{O=JSON.parse(H)}catch{W("Params must be valid JSON");return}try{q(!0),W(null),await Fc({name:w.trim(),pipeline:k,params:O}),C(""),await I()}catch(K){W(K instanceof Error?K.message:"Submit failed")}finally{q(!1)}},J=async O=>{var pe,_e;const K=((pe=O.params)==null?void 0:pe.exp_id)??"",ne=((_e=O.params)==null?void 0:_e.result_file)??"",se=K?`${K}.json`:ne;if(O.status==="failed"){const Se={};for(const[ke,te]of Object.entries(O.params??{}))!ke.startsWith("_")&&ke!=="traceback"&&(Se[ke]=te);try{const te=await bb(O.id),de=te.error??te.message??te.detail??JSON.stringify(te).slice(0,300),Ce=te.traceback??null;V({title:O.name,message:de||"Unknown error — see stack trace below.",detail:Ce??void 0,params:Object.keys(Se).length?Se:null,job:O,onRetry:A(O)})}catch{V({title:O.name,message:"Job failed — no error details stored in the database.",detail:void 0,params:Object.keys(Se).length?Se:null,job:O,onRetry:A(O)})}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)},N=async O=>{try{await fp(O),await I()}catch(K){alert(K instanceof Error?K.message:"Cancel failed")}},X=async O=>{_(K=>new Set([...K,O]));try{await gb(O),await I()}catch(K){alert(K instanceof Error?K.message:"Pause failed")}finally{_(K=>{const ne=new Set(K);return ne.delete(O),ne})}},Q=async O=>{_(K=>new Set([...K,O]));try{await mb(O),await I()}catch(K){alert(K instanceof Error?K.message:"Resume failed")}finally{_(K=>{const ne=new Set(K);return ne.delete(O),ne})}},L=async()=>{try{await xb(),await I()}catch(O){alert(O instanceof Error?O.message:"Pause all failed")}},B=async()=>{try{await yb(),await I()}catch(O){alert(O instanceof Error?O.message:"Resume all failed")}},$=O=>O==="completed"?"#16a34a":O==="failed"?"#dc2626":O==="running"?"#2563eb":O==="pending"?"#d97706":O==="paused"?"#92400e":"#6b7280",Y=O=>O==="completed"?"#dcfce7":O==="failed"?"#fee2e2":O==="running"?"#dbeafe":O==="pending"||O==="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 ",mk(u)]})]}),n.jsxs("div",{style:{display:"flex",gap:6},children:[n.jsx("button",{onClick:()=>I(!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:L,disabled:t.filter(O=>O.status==="pending"||O.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:B,disabled:t.filter(O=>O.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:P,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($f,{label:"Job name",children:n.jsx("input",{value:w,onChange:O=>C(O.target.value),placeholder:"e.g. Entropy analysis — English",style:Hf})}),n.jsx($f,{label:"Pipeline",children:n.jsx("select",{value:k,onChange:O=>{D(O.target.value);const K=v.find(ne=>ne.id===O.target.value);G(K?JSON.stringify(K.default_params,null,2):'{"text_id": ""}')},style:Hf,children:(v.length>0?v.map(O=>O.id):[k]).map(O=>n.jsx("option",{value:O,children:O},O))})}),n.jsx($f,{label:"Parameters (JSON)",children:n.jsx("textarea",{value:H,onChange:O=>G(O.target.value),rows:4,style:{...Hf,fontFamily:"monospace",resize:"vertical"}})}),F&&n.jsx("p",{style:{color:"#dc2626",margin:"4px 0"},children:F}),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(O=>n.jsx(kk,{children:O},O))})}),n.jsx("tbody",{children:t.map(O=>{var Oe,dt,it,lt,Je,yt,Jt;const K=((Oe=O.params)==null?void 0:Oe.compute_device)??"",ne=((dt=O.params)==null?void 0:dt.compute_device_label)??"",se=K==="gpu",pe=((it=O.params)==null?void 0:it.source)==="cli",_e=((lt=O.params)==null?void 0:lt.source)==="ai_action",Se=K?{bg:se?"#dbeafe":"#f3f4f6",color:se?"#1e40af":"#374151",text:se?`⚡ ${ne||"GPU"}`:`⚙️ ${ne||"CPU"}`}:null,ke=((Je=O.params)==null?void 0:Je.node_count)??0,te=((yt=O.params)==null?void 0:yt.nodes_done)??0,de=ke>0?Math.round(te/ke*100):null,Ce=O.pipeline==="exp_run",ze=((Jt=O.params)==null?void 0:Jt.resource_wait)??null,ve=O.status==="running"?Math.round((Date.now()-new Date(O.created_at).getTime())/1e3):null,De=(()=>{const rn=t.filter(ae=>ae.status==="completed"&&ae.pipeline===O.pipeline&&ae.id!==O.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(O.id);(!Le||Le.done!==te)&&T.current.set(O.id,{done:te,since:Ve});const Ae=Le&&Le.done===te?Ve-Le.since:0,Ue=Ce&&O.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(Qs,{children:[n.jsx("div",{style:{fontWeight:500},children:O.name}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",fontFamily:"monospace"},children:[O.id.slice(0,8),"…"]}),O.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})]}),O.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&&` · ${Ea(ve)}`,Ue?` · ${Ue}`:Me!==null?` · ~${Ea(Me)} left`:""]})]})]}),n.jsx(Qs,{children:n.jsx("code",{style:{fontSize:12},children:O.pipeline})}),n.jsx(Qs,{children:n.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:3},children:[Se&&n.jsx("span",{style:{fontSize:11,padding:"2px 7px",borderRadius:6,background:Se.bg,color:Se.color,fontWeight:600,whiteSpace:"nowrap"},children:Se.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"}),!Se&&!pe&&!_e&&n.jsx("span",{style:{fontSize:11,color:"#9ca3af"},children:"—"})]})}),n.jsxs(Qs,{children:[n.jsx("span",{style:{display:"inline-block",padding:"1px 7px",borderRadius:10,background:Y(O.status),color:$(O.status),fontWeight:700,fontSize:11},children:O.status}),O.status==="running"&&ve!==null&&!Ce&&n.jsxs("div",{style:{fontSize:10,color:"#9ca3af"},children:[Ea(ve??0)," elapsed"]})]}),n.jsx(Qs,{children:Vc(O.created_at)}),n.jsx(Qs,{children:n.jsxs("span",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:[O.status==="completed"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#059669"},onClick:()=>J(O),title:"Open result in Reports → Data tab",children:"📂 View in Reports"}),O.status==="failed"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#dc2626"},onClick:()=>J(O),title:"View error details",children:"⚠ Error Details"}),O.status==="cancelled"&&n.jsx("span",{style:{fontSize:11,color:"#6b7280",fontStyle:"italic"},children:"cancelled"}),(O.status==="pending"||O.status==="running")&&n.jsxs(n.Fragment,{children:[n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#d97706"},onClick:()=>X(O.id),disabled:j.has(O.id),title:"Pause this job",children:j.has(O.id)?"…":"⏸ Pause"}),n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:O.status==="running"?"#ea580c":"#6b7280"},onClick:()=>N(O.id),title:O.status==="running"?"Abort this running job":"Cancel this queued job",children:O.status==="running"?"❌ Abort":"⏸ Cancel"})]}),O.status==="paused"&&n.jsx("button",{style:{...bi,padding:"2px 10px",fontSize:12,background:"#059669"},onClick:()=>Q(O.id),disabled:j.has(O.id),title:"Resume this paused job",children:j.has(O.id)?"…":"▶ Resume"})]})})]},O.id)})})]}),M&&n.jsx(qb,{title:M.title,message:M.message,detail:M.detail,params:M.params,job:M.job,onRetry:M.onRetry,onClose:()=>V(null)})]})}function $f({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 kk({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 Qs({children:t}){return n.jsx("td",{style:{padding:"5px 12px 5px 0",borderBottom:"1px solid #f3f4f6",fontSize:13,verticalAlign:"top"},children:t})}const Hf={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"},_k=[{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}],Gb={"Statistical (no LM)":"#16a34a","Language Model Required":"#dc2626"};function Ck(){const[t,o]=x.useState("all"),[r,l]=x.useState(null),[c,d]=x.useState(_k),[u,p]=x.useState([]),[g,h]=x.useState(""),[v,y]=x.useState(!1),[b,S]=x.useState(null),[j,_]=x.useState(!1),T=H=>d(G=>G.filter(z=>z.id!==H)),w=async()=>{if(g.trim()){y(!0),S(null);try{const H=await T2(g.trim());S({ok:!0,text:`Imported: ${H.file??g}`}),h(""),C()}catch(H){S({ok:!1,text:H instanceof Error?H.message:String(H)})}finally{y(!1)}}},C=()=>{vb().then(H=>d(H.map(G=>({...G,needsLM:G.needs_lm,defaultParams:JSON.stringify(G.default_params,null,2),custom:!G.registered})))).catch(()=>{})};x.useEffect(()=>{C(),ld().then(p).catch(()=>{})},[]);const k=["all",...Array.from(new Set(c.map(H=>H.group)))],D=t==="all"?c:c.filter(H=>H.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:()=>{_(H=>!H),S(null)},style:{padding:"5px 12px",border:"1px solid #d1d5db",borderRadius:5,cursor:"pointer",fontSize:12,background:j?"#f3f4f6":"#fff",color:"#374151"},children:j?"× Cancel":"+ Import"})]}),j&&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:H=>h(H.target.value),onKeyDown:H=>{H.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:k.map(H=>{const G=Gb[H]??"#1e3a5f";return n.jsx("button",{onClick:()=>o(H),style:{padding:"4px 14px",border:"1px solid",borderRadius:20,cursor:"pointer",fontSize:12,fontWeight:t===H?600:400,background:t===H?G:"#fff",borderColor:t===H?G:"#d1d5db",color:t===H?"#fff":"#374151"},children:H==="all"?`All (${c.length})`:`${H} (${c.filter(z=>z.group===H).length})`},H)})}),n.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(320px, 1fr))",gap:"0.75rem"},children:D.map(H=>n.jsx(Tk,{pipeline:H,expanded:r===H.id,onToggle:()=>l(r===H.id?null:H.id),onDeleted:T,onDuplicated:C,corpora:u},H.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 Tk({pipeline:t,expanded:o,onToggle:r,onDeleted:l,onDuplicated:c,corpora:d}){const u=Gb[t.group]??"#6b7280",[p,g]=x.useState(!1),[h,v]=x.useState(!1),[y,b]=x.useState(!1),[S,j]=x.useState(null),[_,T]=x.useState(!1),[w,C]=x.useState(""),[k,D]=x.useState(""),[H,G]=x.useState(""),[z,q]=x.useState(!1),[F,W]=x.useState(null),M=async A=>{var P;if(A.stopPropagation(),!w&&!H.trim()){W({ok:!1,text:"Select a corpus or enter a job name"});return}q(!0),W(null);try{const R={...JSON.parse(t.defaultParams||"{}")};w&&(R.text_id=w),k&&(R.target_text_id=k);const J=await Fc({name:H.trim()||`${t.label} — ${((P=d.find(N=>N.id===w))==null?void 0:P.name)??(w||"quick run")}`,pipeline:t.id,params:R});W({ok:!0,text:`Job submitted: ${J.id.slice(0,8)}… — check Jobs panel`}),window.dispatchEvent(new CustomEvent("glossa:running",{detail:{builder:"study",running:!0}}))}catch(R){W({ok:!1,text:R instanceof Error?R.message:"Submit failed"})}finally{q(!1)}},V=async A=>{A.stopPropagation(),g(!0);try{await _2(t.id),c()}catch(P){j(P instanceof Error?P.message:String(P))}finally{g(!1)}},I=async A=>{if(A.stopPropagation(),!y){b(!0);return}v(!0);try{await C2(t.id),l(t.id)}catch(P){j(P instanceof Error?P.message:String(P)),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:V,disabled:p,title:"Duplicate pipeline",style:ry,children:p?"…":"⎘"}),t.custom&&n.jsx("button",{onClick:I,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:Zs,children:"Inputs:"}),n.jsx("code",{style:zk,children:t.inputs})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsx("span",{style:Zs,children:"Outputs:"}),n.jsx("span",{style:{fontSize:12,color:"#374151"},children:t.outputs})]}),n.jsxs("div",{style:{marginBottom:10},children:[n.jsx("span",{style:Zs,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(P=>!P),W(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:Zs,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:Zs,children:"Target corpus (target_text_id)"}),n.jsxs("select",{value:k,onChange:A=>D(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:Zs,children:"Job name (optional)"}),n.jsx("input",{value:H,onChange:A=>G(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 M(A),disabled:z||!w&&!H.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"}),F&&n.jsx("div",{style:{fontSize:11,padding:"4px 8px",borderRadius:4,background:F.ok?"#f0fdf4":"#fef2f2",color:F.ok?"#16a34a":"#b91c1c"},children:F.text})]})]})]})]})}const Zs={fontSize:11,fontWeight:600,color:"#6b7280",display:"block",marginBottom:2,textTransform:"uppercase",letterSpacing:"0.05em"},zk={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",Wf="onboarding@resend.dev",Ek="onboarding@resend.dev";function Rk(){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,j]=x.useState(""),[_,T]=x.useState(""),[w,C]=x.useState(()=>localStorage.getItem(ay)??"outlook365_oauth"),k=x.useMemo(()=>Of.find(ae=>ae.id===w)??Of[0],[w]),[D,H]=x.useState(""),[G,z]=x.useState(587),[q,F]=x.useState(""),[W,M]=x.useState(""),[V,I]=x.useState(""),[A,P]=x.useState(!0),[R,J]=x.useState(""),[N,X]=x.useState(Wf),[Q,L]=x.useState(!0),[B,$]=x.useState(null),[Y,O]=x.useState(!1),[K,ne]=x.useState(""),[se,pe]=x.useState(""),[_e,Se]=x.useState("common"),ke=x.useRef(!1),te=x.useCallback(async()=>{v(!0);try{const[ae,He,Ze,ut,Ut]=await Promise.all([Eb(),vj(),jj(20),Rb().catch(()=>null),cd().catch(()=>null)]);r(ae),c(He.recipients),u(Ze.entries),g(ut),H(ae.host||""),z(ae.port||587),I(ae.from||""),P(ae.use_tls??!0),Se(ae.graph_tenant||"common"),Ut&&!ae.graph_client_id_set&&pe(""),X(ae.resend_from||Wf),L(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,k.id),k.category==="smtp"&&(k.smtp_host!==void 0&&H(k.smtp_host),k.smtp_port!==void 0&&z(k.smtp_port),k.smtp_use_tls!==void 0&&P(k.smtp_use_tls))},[k.id]);const de=async()=>{const ae=S.trim();if(ae){b(!0);try{await Sj({email:ae,label:_.trim(),active:!0}),j(""),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 wj(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 kj();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=N.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"),J(""),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:D.trim(),smtp_port:String(G||587),smtp_from:V.trim(),smtp_use_tls:A?"1":"0"};q.trim()&&(ae.smtp_username=q.trim()),W&&(ae.smtp_password=W),await sr(ae),t("SMTP settings saved","success"),M(""),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 _j();$(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=>{O(!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 Cj(ae.session_id);if(Ze.status==="success"){t("Outlook 365 connected","success"),$(null),O(!1),await te();return}if(Ze.status==="failed"||Ze.status==="expired"){ne(Ze.error||Ze.status),O(!1);return}}catch(Ze){ne(Ze instanceof Error?Ze.message:"poll failed"),O(!1);return}O(!1)},dt=()=>{ke.current=!0,$(null),O(!1)},it=async()=>{if(window.confirm("Disconnect Outlook 365? You can reconnect anytime.")){b(!0);try{await Tj(),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 Ab():await Mb();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=k.category==="oauth",zt=k.category==="api";return n.jsxs("section",{style:Mk,children:[n.jsx("h3",{style:Dk,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:{...hc,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:qf,children:"1 · Mail provider"}),n.jsx("select",{value:w,onChange:ae=>C(ae.target.value),style:{...Jn,fontSize:13},children:Of.map(ae=>n.jsxs("option",{value:ae.id,children:[ae.label,ae.recommended?" ⭐":""]},ae.id))}),n.jsx("p",{style:{...ly,marginTop:6},children:k.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)||Y,title:o!=null&&o.graph_client_id_set?"Start the device-code OAuth flow":"Set the Application (client) ID first",style:{...hc,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=>Se(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."})]})]}),B&&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:B.verification_uri,target:"_blank",rel:"noopener noreferrer",style:{color:"#4338ca"},children:B.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:B.user_code}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:6},children:[Y?"Waiting for approval…":"Polling stopped"," ","· Code expires in ",Math.round(B.expires_in/60)," min.",n.jsx("button",{onClick:dt,style:{...cy,marginLeft:8},children:"Cancel"})]})]}),K&&n.jsxs("div",{style:{marginTop:8,fontSize:11,color:"#b91c1c"},children:["⚠ ",K]})]}),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)||Wf}.`:"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=N.match(/<([^>]+)>/))==null?void 0:Ze[1])??N).trim().toLowerCase()===Ek&&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=>J(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:N,onChange:ae=>X(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=N.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:{...hc,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:{...qf,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:D,placeholder:"SMTP host (e.g. smtp.gmail.com)",onChange:ae=>H(ae.target.value),style:Jn}),n.jsx("input",{value:G||"",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:q,placeholder:"Username (usually your full email address)",onChange:ae=>F(ae.target.value),style:Jn,autoComplete:"off"}),n.jsx("input",{value:W,type:"password",placeholder:o!=null&&o.password_set?"●●●●●●●● (paste new app password)":"App password / SMTP password",onChange:ae=>M(ae.target.value),style:Jn,autoComplete:"off"})]}),n.jsx("input",{value:V,placeholder:'From address (e.g. "Glossa Lab " or just an email)',onChange:ae=>I(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=>P(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:hc,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:qf,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:Uf(ae.active?"#f59e0b":"#22c55e"),children:ae.active?"⏸":"▶"}),n.jsx("button",{onClick:()=>void ze(ae),title:"Edit label",style:Uf("#6b7280"),children:"✎"}),n.jsx("button",{onClick:()=>void ve(ae),title:"Remove",style:Uf("#dc2626"),children:"🗑"})]},ae.id))}),n.jsxs("div",{style:{display:"flex",gap:6,marginTop:8,flexWrap:"wrap"},children:[n.jsx("input",{value:S,onChange:ae=>j(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:{...Lk,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," · ",Ak(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 Uf(t){return{border:"1px solid "+t+"40",borderRadius:4,background:"none",color:t,cursor:"pointer",fontSize:11,padding:"2px 7px"}}function Ak(t){if(!t)return"";const o=new Date(t);return Number.isNaN(o.getTime())?t:o.toLocaleString()}const Mk={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #e5e7eb",borderRadius:8},Dk={margin:"0 0 0.5rem 0",fontSize:15,fontWeight:600,color:"#111827"},ly={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},qf={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"},hc={padding:"5px 12px",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},Lk={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"},Nk=[{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."}],Bk=[{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 Ok(){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,j]=x.useState({}),[_,T]=x.useState(!1),[w,C]=x.useState(!1),[k,D]=x.useState(!1),H=x.useCallback(async()=>{try{const[I,A,P,R,J]=await Promise.all([cd(),zb(),Tb(),Rb().catch(()=>null),Eb().catch(()=>null)]);r(I),c(A.sources),u(P.topics),g(R),v(J)}catch(I){t(I instanceof Error?I.message:"Failed to load discovery state","error")}},[t]);x.useEffect(()=>{H()},[H]);const G=async I=>{const A=(y[I]??"").trim();if(!A){t("Paste a value first","warning");return}T(!0);try{await sr({[I]:A}),b(P=>({...P,[I]:""})),t(`${I} saved`,"success"),await H()}catch(P){t(P instanceof Error?P.message:"Save failed","error")}finally{T(!1)}},z=async I=>{j(A=>({...A,[I]:"loading"}));try{const A=await y2(I);j(P=>({...P,[I]:A}))}catch(A){j(P=>({...P,[I]:{valid:!1,provider:I,message:A instanceof Error?A.message:"verify failed"}}))}},q=async I=>{T(!0);try{const A=I?await Ab():await Mb();g(A),t(I?`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)}},F=async()=>{C(!0);try{const I=await Yc({});t(`Fetch started · job ${I.job_id.slice(0,8)}`,"info")}catch(I){t(I instanceof Error?I.message:"Fetch failed to start","error")}finally{C(!1)}},W=async()=>{D(!0);try{const I=await Hp({limit:50});t(`Mine started · job ${I.job_id.slice(0,8)} · limit 50`,"info")}catch(I){t(I instanceof Error?I.message:"Mine failed to start","error")}finally{D(!1)}},M=l.filter(I=>I.configured).length,V=l.length;return n.jsxs("section",{style:Ik,children:[n.jsx("h3",{style:$k,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:[M,"/",V," 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 q(!(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:gc,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 F(),disabled:w,style:{...Wk,opacity:w?.5:1,cursor:w?"not-allowed":"pointer"},children:w?"⏳ Fetching…":"▶ Fetch now"}),n.jsx("button",{onClick:()=>void W(),disabled:k,style:{...Uk,opacity:k?.5:1,cursor:k?"not-allowed":"pointer"},children:k?"⏳ Mining…":"✨ Mine now (50)"}),n.jsx("span",{style:{flex:1}}),n.jsx("a",{href:"#",onClick:I=>{I.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:gc,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:Nk.map(I=>n.jsx(dy,{k:I,settings:o,pendingKeys:y,setPendingKeys:b,verify:S,onSaveKey:G,onVerifyKey:z,busy:_},I.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:Bk.map(I=>n.jsx(dy,{k:I,settings:o,pendingKeys:y,setPendingKeys:b,verify:S,onSaveKey:G,onVerifyKey:z,busy:_},I.id))})]}),n.jsxs("div",{style:{marginTop:14},children:[n.jsx("div",{style:gc,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:gc,children:"4 · Sources detected by the backend"}),n.jsx("div",{style:{display:"flex",gap:6,flexWrap:"wrap",marginTop:6},children:l.map(I=>{const A=I,P=A.rate_limit,R=P==null?void 0:P.rate_limited,J=Number((P==null?void 0:P.errors_429)??0),N=Number((P==null?void 0:P.requests)??0),X=A.upgrade_hint,Q=A.upgrade_url,L=R?"#fef2f2":I.configured?"#f0fdf4":"#fafafa",B=R?"#fca5a5":I.configured?"#86efac":"#e5e7eb",$=R?"#b91c1c":I.configured?"#15803d":"#9ca3af";return n.jsxs("span",{title:R?`⚠ Rate limited (${J}/${N} requests returned 429)${X?`. ${X}`:""}`:N>0?`${N} requests, ${J} rate-limited`:I.disabled_reason||`${I.source} ready`,style:{padding:"3px 9px",borderRadius:12,border:"1px solid",background:L,borderColor:B,color:$,fontSize:11,fontWeight:500,cursor:Q?"pointer":"default"},onClick:()=>Q&&window.open(Q,"_blank"),children:[R?"⚠ ":I.configured?"✓ ":"✗ ",I.source,N>0&&n.jsxs("span",{style:{fontSize:9,marginLeft:4,opacity:.7},children:[N,"req",J>0?` · ${J}×429`:""]})]},I.source)})})]})]})}function dy({k:t,settings:o,pendingKeys:r,setPendingKeys:l,verify:c,onSaveKey:d,onVerifyKey:u,busy:p}){var y,b,S,j,_;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:Hk}),n.jsx("button",{onClick:()=>void d(t.id),disabled:p||!((S=r[t.id])!=null&&S.trim()),style:{...Gk,opacity:p||!((j=r[t.id])!=null&&j.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:{...qk,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 Ik={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #e5e7eb",borderRadius:8},$k={margin:"0 0 0.5rem 0",fontSize:15,fontWeight:600,color:"#111827"},ga={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},gc={fontSize:11,fontWeight:700,color:"#7c3aed",textTransform:"uppercase",letterSpacing:.5,marginBottom:6},uy={fontSize:11,fontWeight:600,color:"#374151"},Hk={flex:1,padding:"6px 10px",border:"1px solid #d1d5db",borderRadius:5,fontSize:13,boxSizing:"border-box",outline:"none"},Wk={padding:"6px 14px",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},Uk={padding:"6px 14px",border:"1px solid #7c3aed",borderRadius:6,background:"#7c3aed",color:"#fff",fontSize:12,fontWeight:600,cursor:"pointer"},qk={padding:"5px 10px",border:"1px solid #d1d5db",borderRadius:5,background:"#fff",cursor:"pointer",fontSize:12},Gk={padding:"5px 12px",border:"1px solid #c7d2fe",borderRadius:6,background:"#fff",color:"#4338ca",fontSize:12,fontWeight:600,cursor:"pointer"},Pk={cloud:"☁️",ollama:"🦙",byoe:"🔌",huggingface:"🤗"},fy={reachable:"#16a34a",unreachable:"#dc2626",untested:"#9ca3af"};function Fk(){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,j]=x.useState({}),[_,T]=x.useState({}),[w,C]=x.useState("cloud"),[k,D]=x.useState(""),[H,G]=x.useState(""),[z,q]=x.useState(""),[F,W]=x.useState(""),[M,V]=x.useState(!1),I=async()=>{u(!0);try{const B=await Nb();r(B.providers)}catch{}finally{u(!1)}};x.useEffect(()=>{I(),Oj().then(B=>c(B.providers)).catch(()=>{})},[]);const A=async B=>{var Y;const $=((Y=o.find(O=>O.id===B))==null?void 0:Y.name)??"provider";g(O=>({...O,[B]:!0})),t(`Testing '${$}'...`,"info");try{const O=await Nj(B);t(O.message,O.valid?"success":"error"),await I()}catch(O){t(O instanceof Error?O.message:"Test failed","error")}g(O=>({...O,[B]:!1}))},P=async(B,$)=>{if(window.confirm(`Delete provider "${$}"?`))try{await Lj(B),t(`${$} deleted`,"success"),b(null),await I()}catch(Y){t(Y instanceof Error?Y.message:"Delete failed","error")}},R=async(B,$)=>{try{await ny(B,{enabled:$?1:0}),await I()}catch{}},J=async(B,$,Y)=>{if($==="name"&&!Y.trim()){t("Provider name cannot be empty","error");return}T(O=>({...O,[`${B}_${$}`]:!0}));try{await ny(B,{[$]:Y}),t(`${$} updated`,"success"),j(O=>{const K={...O};return delete K[`${B}_${$}`],K}),await I()}catch(O){t(O instanceof Error?O.message:"Save failed","error")}T(O=>({...O,[`${B}_${$}`]:!1}))},N=async()=>{if(!H.trim()){t("Name is required","error");return}V(!0);try{const B=l.find($=>$.id===k);await Dj({name:H,provider_type:w,provider_id:w==="cloud"?k:w,base_url:z||((B==null?void 0:B.base_url)??""),api_key:F}),t(`${H} added`,"success"),v(!1),G(""),q(""),W(""),D(""),await I()}catch(B){t(B instanceof Error?B.message:"Add failed","error")}V(!1)},X=async()=>{t("Scanning for Ollama...","info");try{const B=await Bj();if(B.detected.length===0){t("No Ollama instances found","error");return}const $=B.detected[0];C("ollama"),G("Ollama"),q($.url),v(!0),t(`Found Ollama at ${$.url} with ${$.models.length} model(s)`,"success")}catch{t("Detection failed","error")}},Q=(B,$,Y,O="text",K="")=>{const ne=`${B.id}_${$}`,se=ne in S,pe=S[ne]??"",_e=_[ne],Se=$==="api_key"?"":B[$]||"",ke=se?pe:$==="api_key"?"":Se,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:Y}),n.jsxs("div",{style:{display:"flex",gap:4},children:[n.jsx("input",{type:O,value:ke,onChange:de=>j(Ce=>({...Ce,[ne]:de.target.value})),placeholder:$==="api_key"?B.api_key_set?"•••••••• (paste new to replace)":"Paste API key...":K||Se,style:{flex:1,padding:"4px 8px",fontSize:12,borderRadius:4,border:`1px solid ${te?"#f87171":"#d1d5db"}`,fontFamily:O==="password"?"monospace":void 0}}),se&&n.jsx("button",{onClick:()=>J(B.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"})]})},L={border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"};return n.jsxs("section",{style:L,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:X,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(B=>{const $=y===B.id;return n.jsxs("div",{style:{border:"1px solid #e5e7eb",borderRadius:6,overflow:"hidden",background:B.enabled?"#f0fdf4":"#fafafa"},children:[n.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"8px 12px",cursor:"pointer"},onClick:()=>b($?null:B.id),children:[n.jsx("span",{style:{fontSize:16},children:Pk[B.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:B.name}),n.jsx("span",{style:{fontSize:10,padding:"1px 5px",borderRadius:3,background:`${fy[B.status]||"#9ca3af"}20`,color:fy[B.status]||"#9ca3af",fontWeight:700},children:B.status}),B.api_key_set&&n.jsx("span",{style:{fontSize:9,padding:"1px 4px",borderRadius:3,background:"#dcfce7",color:"#166534"},children:"key set"}),B.available_models.length>0&&n.jsxs("span",{style:{fontSize:10,color:"#6b7280"},children:[B.available_models.length," model(s)"]})]}),n.jsxs("div",{style:{fontSize:11,color:"#6b7280",marginTop:1},children:[(()=>{var K;const Y=B.provider_type==="cloud"?((K=l.find(ne=>ne.id===B.provider_id))==null?void 0:K.label)??B.provider_id:B.provider_id,O=Y&&Y!==B.provider_type;return n.jsxs(n.Fragment,{children:[B.provider_type,O?` · ${Y}`:""]})})(),B.base_url&&n.jsxs("span",{children:[" · ",B.base_url.replace(/https?:\/\//,"").slice(0,40)]})]})]}),n.jsx("input",{type:"checkbox",checked:!!B.enabled,onChange:Y=>{Y.stopPropagation(),R(B.id,Y.target.checked)},style:{width:14,height:14,cursor:"pointer"}}),n.jsx("button",{onClick:Y=>{Y.stopPropagation(),A(B.id)},disabled:p[B.id],style:{padding:"3px 8px",fontSize:10,border:"1px solid #d1d5db",borderRadius:3,cursor:"pointer",background:"#fff"},children:p[B.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(B,"name","Name","text","Provider name"),Q(B,"base_url","Base URL","text","https://api.openai.com/v1"),Q(B,"api_key","API Key","password","sk-..."),B.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:[B.available_models.slice(0,20).map(Y=>n.jsx("span",{style:{fontSize:10,padding:"2px 6px",background:"#e0f2fe",color:"#0369a1",borderRadius:3,fontFamily:"monospace"},children:Y},Y)),B.available_models.length>20&&n.jsxs("span",{style:{fontSize:10,color:"#9ca3af"},children:["+",B.available_models.length-20," more"]})]})]}),n.jsxs("div",{style:{display:"flex",gap:6,marginTop:8},children:[n.jsx("button",{onClick:()=>A(B.id),disabled:p[B.id],style:{padding:"4px 12px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:"#fff"},children:p[B.id]?"Testing...":"↻ Refresh Models"}),n.jsx("button",{onClick:()=>P(B.id,B.name),style:{padding:"4px 12px",fontSize:11,border:"1px solid #fca5a5",borderRadius:4,cursor:"pointer",background:"#fef2f2",color:"#dc2626",marginLeft:"auto"},children:"Delete Provider"})]})]})]},B.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:B=>B.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:B=>{C(B.target.value),D(""),q("")},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:k,onChange:B=>{const $=B.target.value;D($);const Y=l.find(O=>O.id===$);Y&&(G(Y.label),q(Y.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(B=>n.jsx("option",{value:B.id,children:B.label},B.id))]})]}),n.jsx("label",{style:{fontSize:11,fontWeight:600,display:"block",marginBottom:4},children:"Name"}),n.jsx("input",{value:H,onChange:B=>G(B.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:B=>q(B.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:F,onChange:B=>W(B.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:N,disabled:M,style:{padding:"6px 14px",borderRadius:4,border:"none",cursor:"pointer",background:"#2563eb",color:"#fff",fontSize:12,fontWeight:600},children:M?"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 Yk(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 Vk={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 Xk(){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,j]=x.useState(!1),[_,T]=x.useState(!1),[w,C]=x.useState(!1),[k,D]=x.useState(()=>localStorage.getItem("glossa_assignment_filter")||"mixed"),H=Y=>{D(Y),localStorage.setItem("glossa_assignment_filter",Y)},[G,z]=x.useState({}),q=[];for(const Y of o)for(const O of Y.available_models||[])q.push({providerId:Y.id,providerName:Y.name,model:O,providerType:Yk(Y.provider_type,Y.base_url),baseUrl:Y.base_url});const F=q.filter(Y=>k==="cloud"?Y.providerType==="cloud":k==="local"?Y.providerType==="ollama"||Y.providerType==="byoe":!0),W=Y=>{const O={};for(const K of Y)O[`${K.bucket}_primary`]=Gi(K.primary),O[`${K.bucket}_fallback`]=Gi(K.fallback);return O},M=async()=>{g(!0);try{const[Y,O,K]=await Promise.all([Nb(!0),Ij(),Bb()]);r(Y.providers),c(O.assignments),u(K.scores),z(W(O.assignments))}catch{}g(!1)};x.useEffect(()=>{M()},[]);const V=(Y,O)=>{const K=l.find(ne=>ne.bucket===Y);return O==="primary"?K==null?void 0:K.primary:K==null?void 0:K.fallback},I=Y=>{const O=[Y];if(Y.includes("/")&&O.push(Y.split("/").slice(1).join("/")),Y.includes(":")){const K=Y.split(":")[0],ne=Y.split(":")[1];O.push(`${K}-${ne}`),O.push(K)}O.push(Y.replace(/\./g,"-").replace(/:/,"-")),O.push(Y.replace(/\./g,"").replace(/:/,"-"));for(const K of O){const ne=d.find(se=>se.model_name===K||K.toLowerCase().includes(se.model_name.toLowerCase())||se.model_name.toLowerCase().includes(K.toLowerCase()));if(ne)return ne}},A=(()=>{for(const Y of l){const O=`${Y.bucket}_primary`,K=`${Y.bucket}_fallback`;if(G[O]!==Gi(Y.primary)||G[K]!==Gi(Y.fallback))return!0}for(const Y of Object.keys(G))if(G[Y]){const[O,K]=Y.split("_"),ne=l.find(pe=>pe.bucket===O),se=Gi(K==="primary"?ne==null?void 0:ne.primary:ne==null?void 0:ne.fallback);if(G[Y]!==se)return!0}return!1})(),P=(Y,O,K)=>{z(ne=>({...ne,[`${Y}_${O}`]:K}))},R=async()=>{v(!0);const Y=["reasoning","conversational","longform","global"];let O=!1;for(const K of Y){const ne=G[`${K}_primary`]??"",se=G[`${K}_fallback`]??"",[pe,..._e]=ne.split("|"),Se=_e.join("|"),[ke,...te]=se.split("|"),de=te.join("|"),Ce=l.find(De=>De.bucket===K),ze=Gi(Ce==null?void 0:Ce.primary),ve=Gi(Ce==null?void 0:Ce.fallback);if(!(ne===ze&&se===ve))try{await $j(K,{primary_provider_id:pe||"",primary_model:Se||"",fallback_provider_id:ke||"",fallback_model:de||""})}catch(De){t(`${K}: ${De instanceof Error?De.message:"Save failed"}`,"error"),O=!0}}await M(),O||t("Model assignments saved","success"),v(!1)},J=()=>{z(W(l)),t("Changes reverted","info")},N=async()=>{T(!0);try{const Y=await Hj(k);Y.configured?(t(`Auto-configured (${k}) model assignments`,"success"),await M()):t(Y.message||"No models available","error")}catch(Y){t(Y instanceof Error?Y.message:"Auto-configure failed","error")}T(!1)},X=Y=>{const O=`${Y}_primary`,K=`${Y}_fallback`,ne=G[O]??"",se=G[K]??"";!ne&&!se||(z(pe=>({...pe,[O]:se,[K]:ne})),t(`${Y} primary ↔ fallback swapped (not saved yet)`,"info"))},Q=async()=>{b(!0),t("🔄 Syncing model scores from HuggingFace...","info");try{const Y=await Ob();t(Y.message,Y.message.includes("unreachable")||Y.message.includes("static")?"info":"success"),await M()}catch(Y){t(Y instanceof Error?Y.message:"Sync failed","error")}b(!1)},L=async()=>{j(!0);try{const Y=await Wj();t(Y.message,Y.valid?"success":"error")}catch(Y){t(Y instanceof Error?Y.message:"HF test failed","error")}j(!1)},B={section:{border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"}},$=(Y,O)=>{const K=G[`${Y}_${O}`]??"",ne=Gi(V(Y,O)),se=K!==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:O==="primary"?"#2563eb":"#9ca3af",width:55,flexShrink:0},children:[O==="primary"?"⚡ Primary":"⚠️ Fallback",se&&n.jsx("span",{style:{color:"#f59e0b",marginLeft:2},children:"●"})]}),n.jsxs("select",{value:K,onChange:_e=>P(Y,O,_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 —"}),F.map(_e=>{const Se=I(_e.model),te=Se?Se[Y==="conversational"?"conversational_score":Y==="longform"?"longform_score":"reasoning_score"]??0:0;return{..._e,scoreVal:te,hasScore:!!Se}}).filter(_e=>!w||_e.hasScore).sort((_e,Se)=>Se.scoreVal-_e.scoreVal).map(_e=>{var Se;return n.jsxs("option",{value:`${_e.providerId}|${_e.model}`,children:[((Se=py[_e.providerType])==null?void 0:Se.icon)??"🔌"," ",_e.scoreVal>0?`★${_e.scoreVal.toFixed(0)} `:_e.hasScore?"☆0 ":"",_e.providerName," · ",_e.model]},`${_e.providerId}|${_e.model}`)})]})]})};return n.jsxs("section",{style:B.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:L,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:k,onChange:Y=>H(Y.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:N,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..."}),q.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(Y=>{const O=Vk[Y],K=!!(G[`${Y}_primary`]||V(Y,"primary"))&&!!(G[`${Y}_fallback`]||V(Y,"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:O.icon}),n.jsxs("div",{style:{flex:1,minWidth:0},children:[n.jsx("div",{style:{fontWeight:700,fontSize:13},children:O.label}),n.jsx("div",{style:{fontSize:10,color:"#6b7280"},children:O.desc})]}),K&&n.jsx("button",{onClick:()=>X(Y),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:"⇅"})]}),$(Y,"primary"),$(Y,"fallback")]},Y)})}),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:J,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:Y=>C(Y.target.checked)}),"Scored models only"]}),n.jsx("div",{style:{display:"flex",gap:4,marginLeft:"auto",flexWrap:"wrap"},children:Object.values(py).map(Y=>n.jsxs("span",{style:{fontSize:10,padding:"2px 6px",borderRadius:3,background:Y.bg,color:Y.color,fontWeight:600},children:[Y.icon," ",Y.label]},Y.label))})]})]})}const Ko=new Map,Jk=[{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}],Kk={excellent:"#16a34a",great:"#2563eb",good:"#ca8a04"};function Qk(){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,j]=x.useState(()=>{const V={};for(const[I,A]of Ko)V[I]={pct:A.pct,status:A.status};return V}),[_,T]=x.useState({set:!1,editing:!1,value:""}),w=async()=>{g(!0);try{const[V,I,A]=await Promise.all([Y2(),V2().catch(()=>null),Bb()]);r(V.models),v(V.running),c(I),u(A.scores);try{const P=await cd();T(R=>{var J,N;return{...R,set:((N=(J=P.keys)==null?void 0:J.hf_api_token)==null?void 0:N.set)??!1}})}catch{}I&&I.vram_gb>0&&y===-1?b(-1):y===-1&&b(999)}catch{}g(!1)};x.useEffect(()=>{w()},[]);const C=V=>d.find(I=>I.model_name===V||V.includes(I.model_name)||I.model_name.includes(V)),k=V=>{if(Ko.has(V))return;const I={pct:0,status:"connecting…"},A=new EventSource(`/api/v1/ollama/pull/${encodeURIComponent(V)}`);Ko.set(V,{es:A,...I}),j(P=>({...P,[V]:I})),A.onmessage=P=>{try{const R=JSON.parse(P.data);if(R.error){t(`Pull failed: ${R.error}`,"error"),Ko.delete(V),j(Q=>{const L={...Q};return delete L[V],L}),A.close();return}if(R.status==="success"){t(`${V} downloaded`,"success"),Ko.delete(V),j(Q=>{const L={...Q};return delete L[V],L}),A.close(),w();return}const J=R.total&&R.completed?Math.round(R.completed/R.total*100):0,N=R.status||"downloading…",X=Ko.get(V);X&&(X.pct=J,X.status=N),j(Q=>({...Q,[V]:{pct:J,status:N}}))}catch{}},A.onerror=()=>{Ko.delete(V),j(P=>{const R={...P};return delete R[V],R}),A.close()}},D=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(V){t(V instanceof Error?V.message:"Save failed","error")}},H=async()=>{try{const V=await Ob();t(V.message,"success"),w()}catch(V){t(V instanceof Error?V.message:"Sync failed","error")}},G=async V=>{if(confirm(`Delete ${V}?`))try{await X2(V),t(`${V} deleted`,"success"),w()}catch(I){t(I instanceof Error?I.message:"Delete failed","error")}},z=(l==null?void 0:l.vram_gb)??0,q=y===-1?z:y,F=y!==999&&!(y===-1&&z===0),W=o.slice().sort((V,I)=>{if(F){const A=V.min_vram_gb<=q?0:1,P=I.min_vram_gb<=q?0:1;if(A!==P)return A-P}return I.glossa_score-V.glossa_score||V.min_vram_gb-I.min_vram_gb}),M={section:{border:"1px solid #e5e7eb",borderRadius:8,padding:16,marginBottom:16,background:"#fff"}};return n.jsxs("section",{style:M.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:V=>T(I=>({...I,value:V.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:D,style:{padding:"2px 8px",fontSize:10,border:"none",borderRadius:4,background:"#2563eb",color:"#fff",cursor:"pointer"},children:"Save"}),n.jsx("button",{onClick:()=>T(V=>({...V,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(V=>({...V,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:H,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)"]}),Jk.map(V=>n.jsx("button",{onClick:()=>b(V.max),style:{padding:"3px 10px",fontSize:11,border:"1px solid #d1d5db",borderRadius:4,cursor:"pointer",background:y===V.max?"#2563eb":"#fff",color:y===V.max?"#fff":"#374151",fontWeight:y===V.max?700:400},children:V.label},V.max)),n.jsxs("span",{style:{fontSize:10,color:"#9ca3af",alignSelf:"center",marginLeft:4},children:[W.length," model",W.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&&W.map(V=>{const I=C(V.name),A=S[V.name],P=!F||V.min_vram_gb<=q,R=F&&!P;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:V.display}),n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:Kk[V.quality]||"#6b7280",color:"#fff",fontWeight:600},children:V.quality}),V.installed&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#16a34a",color:"#fff",fontWeight:600},children:"installed"}),V.tags.includes("top-pick")&&n.jsx("span",{style:{fontSize:9,padding:"1px 5px",borderRadius:8,background:"#f59e0b",color:"#78350f",fontWeight:700},children:"⭐ TOP PICK"}),V.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 ≥",V.min_vram_gb," GB"]})]}),n.jsx("div",{style:{fontSize:11,color:"#6b7280",marginTop:2},children:V.desc}),n.jsxs("div",{style:{display:"flex",gap:10,marginTop:3,fontSize:10,color:"#9ca3af"},children:[n.jsxs("span",{children:[V.param_b,"B params"]}),n.jsxs("span",{children:[V.size_gb," GB"]}),n.jsxs("span",{children:["≥",V.min_vram_gb," GB VRAM"]}),I&&n.jsxs(n.Fragment,{children:[n.jsxs("span",{title:"Reasoning",children:["🧠",I.reasoning_score.toFixed(0)]}),n.jsxs("span",{title:"Conversational",children:["💬",I.conversational_score.toFixed(0)]}),n.jsxs("span",{title:"Long-form",children:["📝",I.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:V.installed?n.jsx("button",{onClick:()=>G(V.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:()=>k(V.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"})})]},V.name)}),h&&n.jsx(Zk,{onPull:k,pulling:S})]})}function Zk({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 e3(){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,j]=x.useState(!0),_=x.useRef(null),T=async()=>{c(!0);try{r(await Cb())}catch{}finally{c(!1)}};x.useEffect(()=>{T()},[]),x.useEffect(()=>{const z=_.current;z&&(z.scrollTop=z.scrollHeight)},[p]);const w=async(z,q)=>{u(!0),g([{text:`Running: ${q}…`,type:"info"}]);try{const F=await z();if(!F.body){g(I=>[...I,{text:"No response body",type:"error"}]);return}const W=F.body.getReader(),M=new TextDecoder;let V="";for(;;){const{done:I,value:A}=await W.read();if(I)break;V+=M.decode(A,{stream:!0});const P=V.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(`
    +`);V=P.pop()??"";for(const R of P)for(const J of R.split(` +`))if(J.startsWith("data: "))try{const N=JSON.parse(J.slice(6));if(N.text){const X=N.text.toLowerCase().includes("error")||N.text.startsWith("⚠"),Q=N.text.startsWith("✓");g(L=>[...L,{text:N.text,type:X?"error":Q?"success":"output"}])}}catch{}else J.startsWith("event: done")||J.startsWith("event: error")}await T(),t(`${q} complete`,"success")}catch(F){g(W=>[...W,{text:`Failed: ${F instanceof Error?F.message:String(F)}`,type:"error"}]),t(`${q} failed`,"error")}finally{u(!1)}},C=async()=>{if(h!==null){v(null);return}const z=await rj();v(z.packages),j(!0)},k=o==null?void 0:o.venv_exists,D=l?"#9ca3af":k?"#16a34a":"#ef4444",H=l?"checking…":k?`Active · Python ${(o==null?void 0:o.python_version)??"?"}`:"Not found",G=(z,q)=>({padding:"5px 12px",border:"none",borderRadius:5,background:q?"#e5e7eb":z,color:q?"#9ca3af":"#fff",cursor:q?"not-allowed":"pointer",fontSize:12,fontWeight:600});return n.jsxs("section",{style:s3,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:k?"#f0fdf4":"#fef2f2",border:`1px solid ${k?"#86efac":"#fca5a5"}`,borderRadius:7},children:[n.jsx("span",{style:{width:9,height:9,borderRadius:"50%",background:D,flexShrink:0}}),n.jsxs("div",{style:{flex:1},children:[n.jsx("div",{style:{fontSize:13,fontWeight:600,color:"#111827"},children:H}),(o==null?void 0:o.venv_path)&&n.jsx("div",{style:{fontSize:10,color:"#6b7280",fontFamily:"monospace",marginTop:1},children:o.venv_path}),k&&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:"⟳"})]}),!k&&!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(aj,"Setup venv"),disabled:d,style:G("#16a34a",d),children:"⬇ Setup venv"}),n.jsx("button",{onClick:()=>w(lj,"Rebuild venv"),disabled:d,style:G("#ea580c",d),children:"↺ Rebuild venv"}),n.jsx("button",{onClick:()=>w(cj,"Upgrade deps"),disabled:d||!k,style:G("#2563eb",d||!k),children:"↑ Upgrade deps"}),n.jsx("button",{onClick:C,disabled:!k,style:G("#7c3aed",!k),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,q)=>n.jsx("div",{style:{color:z.type==="error"?"#f87171":z.type==="success"?"#86efac":"#e2e8f0",lineHeight:1.6},children:z.text},q))})]}),h&&n.jsxs("div",{children:[n.jsxs("button",{onClick:()=>j(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 t3(){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([cd(),Ba()]);c(b.data_dir),u(S.version??"");const j=S.uptime_seconds??0,_=Math.floor(j/60),T=Math.floor(_/60);g(T>0?`${T}h ${_%60}m`:_>0?`${_}m`:`${Math.round(j)}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:{...o3,background:"#fef2f2",borderColor:"#fca5a5",color:"#991b1b"},children:h}),t==="ai"&&n.jsxs(n.Fragment,{children:[n.jsx(Fk,{}),n.jsx(Xk,{}),n.jsx(Qk,{}),n.jsxs("section",{style:mp,children:[n.jsx("h3",{style:xp,children:"AI Behavior"}),n.jsx("p",{style:os,children:"Control how Glossa AI handles action proposals during chat."}),n.jsx(i3,{})]})]}),t==="discovery"&&n.jsx(Ok,{}),t==="notifications"&&n.jsx(Rk,{}),t==="system"&&n.jsxs(n.Fragment,{children:[n.jsx(e3,{}),n.jsx(n3,{}),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(Gf,{label:"Data directory",value:l||"—",mono:!0}),d&&n.jsx(Gf,{label:"Backend version",value:d}),p&&n.jsx(Gf,{label:"Backend uptime",value:p})]})}),n.jsx("p",{style:{...os,marginTop:10,color:"#9ca3af"},children:"Corpus, sign mapping, and pipeline settings are project-specific. Open or create a project to configure them."})]})]})]})}function n3(){const{toast:t}=et(),[o,r]=x.useState(!1),l=async()=>{r(!0);try{const c=await m2();x2(),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:os,children:"Removes all non-running jobs from the database (completed, failed, paused, queued) and clears all run-related browser state:"}),n.jsxs("ul",{style:{...os,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:{...os,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 i3(){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:{...os,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:{...os,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 Gf({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"},os={margin:0,fontSize:12,color:"#6b7280",lineHeight:1.5},o3={padding:"10px 14px",borderRadius:6,border:"1px solid",marginBottom:"1rem",fontSize:13},s3={marginBottom:"2rem",padding:"1.25rem",border:"1px solid #d1fae5",borderRadius:8,background:"#fafffe"},ma="glossa_active_project",xy="__global__",Pb=x.createContext({activeProject:null,projects:[],setActiveProject:async()=>{},refreshProjects:async()=>{},loading:!0});function r3({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 Db();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 zj();y=h.find(j=>j.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 Lb(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(Pb.Provider,{value:{activeProject:l,projects:o,setActiveProject:g,refreshProjects:p,loading:d},children:t})}function zo(){return x.useContext(Pb)}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=j=>{h.current&&!h.current.contains(j.target)&&u(!1)};return document.addEventListener("mousedown",S),()=>document.removeEventListener("mousedown",S)},[d]);const v=S=>{const j=new Set(r);j.has(S)?j.delete(S):j.add(S),l(j)},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 j=(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:_?j+"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 ${_?j:"#d1d5db"}`,background:_?j:"#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:_?j:"#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 a3(){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),[j,_]=x.useState(new Set),[T,w]=x.useState("updated_at"),[C,k]=x.useState("desc"),[D,H]=x.useState(!0),[G,z]=x.useState(null),[q,F]=x.useState(!1),[W,M]=x.useState([]),[V,I]=x.useState(""),[A,P]=x.useState(!1),[R,J]=x.useState(null),N=async()=>{J(null),F(!0);try{const oe=await w2();M(oe),oe.length>0&&I(oe[0].id)}catch{M([])}},X=async()=>{if(V){P(!0),J(null);try{const oe=await j2(V);J(oe.message),setTimeout(()=>{F(!1),J(null),de()},3e3)}catch(oe){J(oe instanceof Error?oe.message:"Generation failed")}finally{P(!1)}}},[Q,L]=x.useState(!1),[B,$]=x.useState(new Set),[Y,O]=x.useState(!1),[K,ne]=x.useState(null),se=async()=>{const oe=r.filter(Ne=>B.has(Ne.id));if(oe.length){O(!0);try{const Ne=await Promise.all(oe.map(async mt=>{const St=Nf(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 _b({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{O(!1)}}},pe=oe=>$(Ne=>{const We=new Set(Ne);return We.has(oe)?We.delete(oe):We.add(oe),We}),[_e,Se]=x.useState(()=>{try{return new Set(JSON.parse(localStorage.getItem("glossa_starred_reports")??"[]"))}catch{return new Set}}),ke=oe=>{Se(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=>B.has(St.id));if(!oe.length)return;const We=(await Promise.all(oe.map(async St=>{const Ht=Nf(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/package-lock.json b/frontend/package-lock.json index bb001ba5..643ad8f3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1273,7 +1273,7 @@ "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -1427,7 +1427,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/d3-color": { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index d84a51dc..cd574cf8 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -701,6 +701,20 @@ export interface ExperimentMeta { export const getNodeSchema = (nodeType: string, refId: string): Promise> => request("GET", `/node-registry/${nodeType}/${refId}`); +export interface ExperimentLedgerEntry { + id: string; + display_name: string; + category: string; + phase: string; + description: string; + status: "active" | "superseded" | "legacy" | "scaffold"; + superseded_by: string | null; + source_file: string; +} + +export const getExperimentMetadata = (): Promise => + request("GET", "/experiments/metadata"); + export const listExperiments = (): Promise => request("GET", "/experiments"); diff --git a/frontend/src/components/DashboardView.tsx b/frontend/src/components/DashboardView.tsx index 9b5bfaee..a42e0533 100644 --- a/frontend/src/components/DashboardView.tsx +++ b/frontend/src/components/DashboardView.tsx @@ -44,6 +44,7 @@ import { useAIChat } from "../hooks/useAIChat"; import { useProject } from "../hooks/useProject"; import { useToast } from "../hooks/useToast"; import { DeciphermentPanel } from "./DeciphermentPanel"; +import ExperimentRegistry from "./ExperimentRegistry"; import { ResearchLoopPanel } from "./ResearchLoopPanel"; // ── Insight persistence ────────────────────────────────────────────────── @@ -769,6 +770,9 @@ export function DashboardView() { marginBottom: 12 }}>{error} )} + {/* Experiment Registry */} + + {/* Decipherment Progress Panel */} applyAction({ diff --git a/frontend/src/components/ExperimentRegistry.tsx b/frontend/src/components/ExperimentRegistry.tsx new file mode 100644 index 00000000..f1a2d349 --- /dev/null +++ b/frontend/src/components/ExperimentRegistry.tsx @@ -0,0 +1,190 @@ +import { useCallback, useEffect, useState } from "react"; +import type { ExperimentLedgerEntry } from "../api"; +import { getExperimentMetadata } from "../api"; + +const CATEGORIES = [ + "structural_analysis", "lm_scoring", "sa_variant", "ctt", + "contact_zone", "cross_language", "archaeological", "misc", +] as const; + +const CATEGORY_LABELS: Record = { + structural_analysis: "Structural", + lm_scoring: "LM Scoring", + sa_variant: "SA Variant", + ctt: "CTT", + contact_zone: "Contact Zone", + cross_language: "Cross-Language", + archaeological: "Archaeological", + misc: "Misc", +}; + +const STATUS_COLORS: Record = { + active: { bg: "#dcfce7", fg: "#166534" }, + superseded: { bg: "#fef9c3", fg: "#854d0e" }, + legacy: { bg: "#f3f4f6", fg: "#6b7280" }, + scaffold: { bg: "#ede9fe", fg: "#6d28d9" }, +}; + +export default function ExperimentRegistry() { + const [entries, setEntries] = useState([]); + const [loading, setLoading] = useState(true); + const [open, setOpen] = useState(false); + const [activeFilter, setActiveFilter] = useState(null); + const [showAll, setShowAll] = useState(false); + + const load = useCallback(async () => { + try { + const data = await getExperimentMetadata(); + setEntries(data); + } catch { /* ignore */ } + setLoading(false); + }, []); + + useEffect(() => { void load(); }, [load]); + + const filtered = entries.filter((e) => { + if (activeFilter && e.category !== activeFilter) return false; + if (!showAll && e.status !== "active") return false; + return true; + }); + + const byCategory = new Map(); + for (const e of filtered) { + const cat = e.category || "misc"; + if (!byCategory.has(cat)) byCategory.set(cat, []); + byCategory.get(cat)!.push(e); + } + + const totalActive = entries.filter((e) => e.status === "active").length; + + return ( +
    +
    setOpen(!open)} + > + 🧪 + + Experiment Registry ({totalActive}) + + + {open ? "▾" : "▸"} + +
    + + {open && ( +
    + {/* Category filter chips */} +
    + + {CATEGORIES.map((cat) => { + const count = entries.filter( + (e) => e.category === cat && (showAll || e.status === "active") + ).length; + if (count === 0) return null; + return ( + + ); + })} + + +
    + + {loading &&
    Loading…
    } + + {!loading && filtered.length === 0 && ( +
    No experiments match the filter.
    + )} + + {/* Experiments grouped by category */} + {Array.from(byCategory.entries()).map(([cat, items]) => ( +
    +
    + {CATEGORY_LABELS[cat] || cat} ({items.length}) +
    +
    + {items.slice(0, 20).map((e) => { + const sc = STATUS_COLORS[e.status] || STATUS_COLORS.active; + return ( +
    + + {e.status} + + {e.display_name} + {e.phase && ( + + ph {e.phase} + + )} + {e.superseded_by && ( + + → {e.superseded_by} + + )} +
    + ); + })} + {items.length > 20 && ( +
    + + {items.length - 20} more +
    + )} +
    +
    + ))} +
    + )} +
    + ); +}