Skip to content

feat(portal): manga page translation pipeline, portal dashboard & studio - #3

Merged
deckyfx merged 5 commits into
masterfrom
feat/portal
Jul 27, 2026
Merged

feat(portal): manga page translation pipeline, portal dashboard & studio#3
deckyfx merged 5 commits into
masterfrom
feat/portal

Conversation

@deckyfx

@deckyfx deckyfx commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Extension (v1.2.0): Element-selector OCR mode (click any image → OCR + translate), popup activity log via SSE, Re-scan button
  • Server: Full manga page translation pipeline — bubble detection (RT-DETR/YOLOv8 ONNX), per-bubble OCR + translation, SkiaSharp typesetting, inpaint/bubble model support; configurable model repos; persistent job storage under data/jobs/{id}/; portal REST API (/api/portal/) for job/bubble/volume/chapter CRUD and re-detect/re-translate/re-render actions; EF Core migrations; startup banner
  • Portal frontend (SolidJS + HashRouter): Jobs list, Studio page (SVG bubble canvas with move/resize/draw, editor panel, toolbar actions), Library page, Volume page with chapter reorder, Chapter page with job assignment

Portal features

Page What it does
/jobs Paginated job grid with status badges, search, filter
/jobs/:id (Studio) SVG canvas with drag/move/resize handles, draw new bubbles, original/result/side-by-side toggle, re-detect/re-translate/re-render
/library Volume + standalone chapter grid with full CRUD modals
/library/:volumeId Chapter list with up/down reorder, CRUD
/library/chapters/:id Page grid with assign-jobs modal, per-page reorder + unassign

Test plan

  • Build extension: cd extension && bun run build
  • Run server: cd server && dotnet run — verify startup banner shows IP:port
  • Navigate to http://localhost:3579 — check dashboard loads
  • Process a manga page via extension — verify job appears in /jobs
  • Open job in Studio — verify bubbles render on canvas
  • Test drag/move/resize/draw on canvas bubbles
  • Test Re-detect / Re-translate / Re-render actions
  • Create volume + chapter in Library, assign jobs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a browser-extension popup with region scan and translate-image modes.
    • Added an in-page image translation picker with staged progress, translated-image replacement, and rescan flow.
    • Expanded the translation portal with job browsing, volumes/chapters management, and an interactive bubble studio editor.
    • Added desktop “Re-scan” to clear prior results and start a new capture.
  • Server Improvements
    • Upgraded readiness/health reporting to include per-model status, plus new translate-page job endpoints with SSE progress.
    • Added new portal REST APIs (jobs, bubbles, volumes, chapters) and background reprocessing actions.
  • Documentation
    • Refreshed README for the C# self-hosted server and added new architecture + pipeline/environ docs.
  • Packaging
    • Bumped the extension version and switched non-dev packaging to a ZIP bundle.

decky and others added 4 commits July 15, 2026 08:40
…ings API

- ModelSettingsStore: runtime-configurable model settings (env → JSON → defaults)
  with GET/PUT /api/settings endpoints for dashboard reconfiguration
- BootState: per-model readiness flags (InpaintReady, BubbleReady, InpaintEnabled,
  BubbleEnabled); inpaint/bubble download infrastructure with TODO stubs for service init
- Generic DownloadHfModelAsync driven by ModelEntry.FileList; URL subdir paths stored
  flat on disk via Path.GetFileName()
- HealthRoutes: injected ModelSettingsStore; exposes inpaint/bubble status with
  Enabled flag; ModelStatus record gains optional Enabled parameter
- Config: PORT/SOCKET_PATH/DATABASE_URL/DEEPL_API_KEY env vars; Kestrel explicit bind
- 503 guards in OCR/Translate/Analyze routes check BootState before enqueuing jobs
- SolidJS frontend replaces React: solid-app.tsx, AppBridge.mount/unmount, Vite
  watch loop fix (build.watch.exclude), tsconfig vite/client types
- Blazor Index.razor mounts SolidJS app via AppBridge
- CLAUDE.md, .env.example, README updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
app.js + app.css are checked in so the server can serve the SolidJS
frontend without a separate build step on deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicking Re-scan closes the result panel and immediately opens the
draw-to-select overlay — no need to click the extension icon again.

- extension: 1.1.2 → 1.2.0
- server: (unversioned) → 1.2.0; fix stale React comment in csproj

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clears current results and immediately opens the region-capture flow,
mirroring the Re-scan button added to the browser extension.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@deckyfx, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c63aca03-ffde-4fed-81dd-ccddfc94f12b

📥 Commits

Reviewing files that changed from the base of the PR and between 1739119 and 500c1a6.

📒 Files selected for processing (54)
  • .gitignore
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/.stylelintignore
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
📝 Walkthrough

Walkthrough

The PR adds asynchronous manga image translation, a persisted translation portal, a SolidJS frontend, browser-extension image mode, expanded server model readiness/configuration, and a desktop rescan command. Documentation, migrations, packaging, and generated web assets are updated.

Changes

OCR platform and translation workflows

Layer / File(s) Summary
Server foundation
server/src/..., server/Migrations/..., server/Program.cs
Adds model settings, readiness tracking, translation entities, migrations, startup configuration, health reporting, and service registration.
Translation pipeline
server/src/Services/..., server/src/Routes/TranslatePage.cs, server/src/Jobs/...
Implements bubble detection, OCR/translation orchestration, typesetting, persisted artifacts, in-memory jobs, polling, and SSE progress events.
Portal backend and client API
server/src/Routes/PortalRoutes.cs, server/ClientApp/src/api.ts, server/ClientApp/src/types.ts
Adds CRUD and action endpoints for jobs, bubbles, volumes, and chapters, plus typed frontend API helpers.
SolidJS portal UI
server/ClientApp/src/components/*, server/ClientApp/src/pages/*
Adds dashboard, job list, translation studio, bubble editing, library, volume, and chapter management interfaces.
Extension image mode
extension/src/*, extension/static/*, extension/build.ts
Adds popup mode selection, image picking, cross-origin fetching, translation progress streaming, rescan controls, and ZIP packaging.
Integration and supporting updates
server/ClientApp/src/solid-app.tsx, server/Components/*, server/vite.config.ts, desktop/*, README.md, docs/*
Replaces the React bridge with SolidJS, updates generated assets and documentation, and adds the desktop rescan command.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ExtensionPopup
  participant ContentScript
  participant TranslationAPI
  participant TranslationService
  participant InferenceQueue

  User->>ExtensionPopup: choose Region scan or Translate image
  ExtensionPopup->>ContentScript: start selected mode
  ContentScript->>TranslationAPI: submit image translation job
  TranslationAPI->>TranslationService: run asynchronous pipeline
  TranslationService->>InferenceQueue: enqueue OCR and translation
  TranslationAPI-->>ContentScript: stream progress and completion
  ContentScript-->>User: show progress and replace translated image
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main additions: manga page translation pipeline plus the portal dashboard and studio UI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/portal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
extension/src/background.ts (1)

30-34: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Require a server URL for image mode regardless of ocrEngine.

Image translation always posts to the server, but this check only opens settings when ocrEngine === "server". A Tesseract-configured user with no serverUrl can enter image mode and only fails after selecting an image. Gate mode === "image" on settings.serverUrl too.

Proposed fix
-  if (settings.ocrEngine === "server" && !settings.serverUrl) {
+  if ((settings.ocrEngine === "server" || mode === "image") && !settings.serverUrl) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/src/background.ts` around lines 30 - 34, Update the configuration
guard in the image-mode flow to open options whenever mode is "image" and
settings.serverUrl is missing, regardless of settings.ocrEngine. Preserve the
existing server-engine check for non-image modes and return after opening the
options page.
🟡 Minor comments (11)
extension/static/content.css-267-284 (1)

267-284: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore a visible keyboard focus indicator.

all: initial clears the default outline, so the Re-scan button has no visible focus state for keyboard users. Add a :focus-visible outline.

Proposed fix
 .socr-rescan:hover {
   background: `#45475a` !important;
 }
+
+.socr-rescan:focus-visible {
+  outline: 2px solid `#89dceb` !important;
+  outline-offset: 2px !important;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/static/content.css` around lines 267 - 284, Update the .socr-rescan
styles to add a visible :focus-visible outline for keyboard-focused Re-scan
buttons, while preserving the existing reset and hover styling.
server/src/ModelSettingsStore.cs-82-93 (1)

82-93: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Same empty-vs-null pitfall in dataRoot fallback.

Path.GetDirectoryName returns "" (not null) for a bare filename with no directory component (e.g. DATABASE_URL=ocr.db). In that case ?? Path.Combine(...) never triggers, and model-settings.json would be written to the current working directory instead of the intended data folder.

🛠️ Proposed fix
-        var dataRoot = Path.GetDirectoryName(config.DatabasePath)
-                    ?? Path.Combine(Directory.GetCurrentDirectory(), "data");
+        var dirName  = Path.GetDirectoryName(config.DatabasePath);
+        var dataRoot = string.IsNullOrEmpty(dirName)
+                    ? Path.Combine(Directory.GetCurrentDirectory(), "data")
+                    : dirName;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/ModelSettingsStore.cs` around lines 82 - 93, Update
ModelSettingsStore.Create so the dataRoot fallback also applies when
Path.GetDirectoryName(config.DatabasePath) returns an empty string, using the
existing current-directory “data” path for both null and empty results. Keep the
subsequent model-settings.json path construction unchanged.
server/Program.cs-60-88 (1)

60-88: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Startup banner prints a TCP dashboard URL even in Unix-socket mode.

listenInfo (Lines 72-74) correctly distinguishes socket vs port, but the "Dashboard" line and LAN IP loop (Lines 81-83) unconditionally use port/http://, even though no TCP listener exists when SOCKET_PATH is set. This gives operators a nonfunctional URL when running behind a socket-based reverse proxy.

🛠️ Proposed fix
     Console.WriteLine($"│  Listening on  {listenInfo,-51}│");
-    Console.WriteLine($"│  Dashboard     http://localhost:{port,-35}│");
-    foreach (var ip in lanIps)
-        Console.WriteLine($"│                http://{ip}:{port,-41}│");
+    if (string.IsNullOrEmpty(socketPath))
+    {
+        Console.WriteLine($"│  Dashboard     http://localhost:{port,-35}│");
+        foreach (var ip in lanIps)
+            Console.WriteLine($"│                http://{ip}:{port,-41}│");
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/Program.cs` around lines 60 - 88, Update the startup banner registered
by ApplicationStarted so the Dashboard URL and LAN IP entries are emitted only
when TCP port mode is active, such as when socketPath is empty; omit these
nonfunctional HTTP URLs in Unix-socket mode while preserving the existing
listenInfo and banner formatting.
server/src/Routes/HealthRoutes.cs-14-33 (1)

14-33: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Health payload misreports OCR/Translate enabled state and ignores their readiness in degraded calc.

Enabled: true is hardcoded for ocr/translate (Lines 16-17) instead of reflecting ms.Ocr.Enabled/ms.Translate.Enabled, and optionalsMissing (30-33) never checks OCR/Translate readiness. If either required model is disabled or fails to become ready, /health still reports Enabled: true and can report "ok" overall, hiding a broken core feature.

🛠️ Proposed fix
             var models = new Dictionary<string, ModelStatus>
             {
-                ["ocr"]        = new(ms.Ocr.Repo,       boot.OcrReady,        Enabled: true),
-                ["translate"]  = new(ms.Translate.Repo,  boot.TranslateReady,  Enabled: true),
+                ["ocr"]        = new(ms.Ocr.Repo,       boot.OcrReady,       Enabled: ms.Ocr.Enabled),
+                ["translate"]  = new(ms.Translate.Repo, boot.TranslateReady, Enabled: ms.Translate.Enabled),
                 ["dictionary"] = new("stephenmk/Jitendex", boot.DictionaryReady, Enabled: true),
                 ...
             };

             // "degraded" if any enabled optional model hasn't finished loading
             bool optionalsMissing =
                 !boot.DictionaryReady ||
+                (ms.Ocr.Enabled       && !boot.OcrReady) ||
+                (ms.Translate.Enabled && !boot.TranslateReady) ||
                 (boot.InpaintEnabled && !boot.InpaintReady) ||
                 (boot.BubbleEnabled  && !boot.BubbleReady);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Routes/HealthRoutes.cs` around lines 14 - 33, Update the health
payload’s OCR and Translate entries in the models dictionary to use
ms.Ocr.Enabled and ms.Translate.Enabled instead of hardcoded true values. Extend
the optionalsMissing calculation to include each enabled OCR/Translate model
that is not ready, using boot.OcrReady and boot.TranslateReady, so the overall
health status reflects disabled or failed core models.
server/src/ServiceExtensions.cs-7-23 (1)

7-23: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Publish readiness state safely.

BootBackgroundService writes BootState properties from the hosted service while /health and queued API handlers read them from request handlers without synchronization. Return an immutable snapshot atomically, or make the backing fields synchronized/volatile before reading.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/ServiceExtensions.cs` around lines 7 - 23, Update BootState and
its access paths so BootBackgroundService publishes readiness changes through
synchronized or volatile backing fields, and /health plus queued request
handlers read a consistent state without data races. Prefer exposing an
immutable atomically replaced snapshot while preserving the existing readiness
properties and semantics.

Source: Coding guidelines

server/src/Services/PageTranslationService.cs-285-297 (1)

285-297: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

jobId[..8] throws for short job ids.

If TranslationJobStore.Create() ever yields an id shorter than 8 characters (or a caller supplies one), this raises ArgumentOutOfRangeException; the surrounding catch swallows it and the job row is never created, so the portal shows nothing for a job that is actively running.

🐛 Proposed fix
-                    Title             = $"Job {jobId[..8]}",
+                    Title             = $"Job {jobId[..Math.Min(8, jobId.Length)]}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/PageTranslationService.cs` around lines 285 - 297, Update
the PageTranslationJob creation logic to make the Title expression safe for job
IDs shorter than eight characters, while retaining the existing eight-character
truncation for longer IDs. Use the existing jobId value without allowing title
formatting to throw, so SaveChangesAsync can still create the active job row.
extension/src/content.ts-664-674 (1)

664-674: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard against a zero-sized canvas.

If the image hasn't finished loading, naturalWidth/width are 0, toDataURL returns "data:,", and the empty string is happily POSTed — the user sees an opaque server error rather than "image not loaded yet".

🐛 Proposed fix
   const canvas = document.createElement("canvas");
   canvas.width = img.naturalWidth || img.width;
   canvas.height = img.naturalHeight || img.height;
+  if (!canvas.width || !canvas.height) throw new Error("Image not loaded yet");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/src/content.ts` around lines 664 - 674, Update imageElementToBase64
to validate the computed canvas dimensions before creating or encoding the
canvas. When either width or height is zero, reject with a clear “image not
loaded yet” error instead of calling toDataURL or returning an empty payload;
preserve the existing encoding behavior for valid dimensions.
extension/src/content.ts-676-701 (1)

676-701: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Second invocation orphans the previous panel.

showImageTranslateLoading overwrites imageTranslateOverlay without removing the existing node, so a rapid second image pick leaves a dead panel in the DOM permanently.

🐛 Proposed fix
 function showImageTranslateLoading(): void {
+  imageTranslateOverlay?.remove();
+  imageTranslateOverlay = null;
+  imageTranslateLogList = null;
   const panel = document.createElement("div");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/src/content.ts` around lines 676 - 701, Update
showImageTranslateLoading to remove any existing imageTranslateOverlay from the
DOM before creating and assigning the new loading panel, while preserving the
current initialization of imageTranslateLogList and the upload log entry.
server/src/Routes/AnalyzeRoutes.cs-19-20 (1)

19-20: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Gate /analyze on dictionary/tokenizer readiness instead of global readiness

boot.IsReady is set only after OCR and translate init complete, while /analyze depends only on NMeCab tokenization and DictionaryService. Use the existing boot.DictionaryReady flag or another tokenizer/dictionary readiness surface so /analyze is available while model downloads are in progress.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Routes/AnalyzeRoutes.cs` around lines 19 - 20, Update the
readiness guard for the `/analyze` route to use `boot.DictionaryReady` (or the
existing tokenizer/dictionary-specific readiness surface) instead of
`boot.IsReady`, preserving the 503 response until dictionary/tokenizer
initialization completes while allowing requests during OCR and translation
model downloads.
server/ClientApp/src/pages/StudioPage.tsx-35-58 (1)

35-58: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Missing default branch — badge silently renders nothing.

Same gap as StatusBadge in server/ClientApp/src/pages/JobsListPage.tsx; also ReturnType<typeof Show> is not a meaningful return type here (JSX.Element is).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/pages/StudioPage.tsx` around lines 35 - 58, Update
StatusBadge to return a fallback badge for any unrecognized or missing status,
matching the established behavior in JobsListPage. Replace ReturnType<typeof
Show> with JSX.Element and ensure every switch path returns a valid JSX element.
server/ClientApp/src/components/BubbleEditor.tsx-69-84 (1)

69-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Synchronize fields when the selected bubble is externally updated.

This effect tracks only bubbleIndex. Dragging a selected bubble updates and refetches it with the same index, so the editor continues showing stale values. Track the bubble object or its editable fields instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/components/BubbleEditor.tsx` around lines 69 - 84,
Update the createEffect/on synchronization in BubbleEditor so it reacts when the
selected bubble’s object or editable fields change, not only when bubbleIndex
changes. Preserve the existing setX, setY, setW, setH, setSourceText,
setTranslatedText, and setIsExcluded updates while ensuring externally refreshed
values replace stale editor state.
🧹 Nitpick comments (13)
server/src/Services/PageTranslationService.cs (3)

208-209: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Prefer ExecuteDeleteAsync over load-then-RemoveRange.

RemoveRange on the IQueryable materialises and tracks every non-manual bubble just to delete it. await db.PageTranslationLogs.Where(...).ExecuteDeleteAsync(ct) issues a single DELETE (EF Core 7+).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/PageTranslationService.cs` around lines 208 - 209, Update
the deletion flow in PageTranslationService to replace the PageTranslationLogs
query and RemoveRange call with ExecuteDeleteAsync, preserving the JobId and
!IsManuallyAdded filters and passing the existing cancellation token. Await the
bulk delete directly without materializing or tracking entities.

142-142: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Per-bubble LogBubbleAsync creates a scope + SaveChanges per bubble, unawaited.

Each bubble opens its own DI scope and DbContext and races the others on the SQLite file; nothing awaits them, so FinalizeJobRowAsync can mark the job done before the last logs land and the Studio opens on an incomplete bubble set. Buffering the entries and writing them once per job (or at least awaiting each call) is both faster and ordered.

Also applies to: 327-352

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/PageTranslationService.cs` at line 142, Update the
bubble-processing flow around LogBubbleAsync and FinalizeJobRowAsync to avoid
fire-and-forget per-bubble database writes: buffer all bubble log entries and
persist them once per job, or await each LogBubbleAsync call sequentially.
Ensure persistence completes before FinalizeJobRowAsync marks the job done,
preserving bubble order and preventing concurrent SQLite access.

98-98: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

CropBubble re-decodes the entire page PNG once per bubble.

SKBitmap.Decode(imagePng) runs inside the per-bubble loop, so a 30-bubble page decodes a multi-megapixel PNG 30 times before OCR even starts. Decode once before the loop and pass the SKBitmap into the crop helper.

Also applies to: 354-377

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/PageTranslationService.cs` at line 98, Update the page
translation flow around the per-bubble loop and CropBubble so imagePng is
decoded into a single SKBitmap before iterating bubbles, then pass that bitmap
into each crop operation. Change CropBubble to accept and reuse the decoded
bitmap instead of calling SKBitmap.Decode per bubble, and dispose the shared
bitmap after all crops complete.
server/src/Services/BubbleDetectionService.cs (2)

118-123: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Positional input binding is fragile for the RT-DETR graph.

inputNames[0]/[1] assumes InputMetadata.Keys enumerates as images, then orig_target_sizes. Any export that reorders (or exposes a single input) yields a shape-mismatch failure or ArgumentOutOfRangeException. Bind by the documented names with a positional fallback.

🛡️ Proposed fix
-        var inputNames = _session!.InputMetadata.Keys.ToList();
+        var inputNames = _session!.InputMetadata.Keys.ToList();
+        if (inputNames.Count < 2)
+            throw new InvalidOperationException(
+                $"RT-DETR model expects 2 inputs, found {inputNames.Count}");
+        var imgName  = inputNames.FirstOrDefault(k => k.Contains("image")) ?? inputNames[0];
+        var sizeName = inputNames.FirstOrDefault(k => k.Contains("size"))  ?? inputNames[1];
         var inputs = new List<NamedOnnxValue>
         {
-            NamedOnnxValue.CreateFromTensor(inputNames[0], imgTensor),
-            NamedOnnxValue.CreateFromTensor(inputNames[1], sizeTensor),
+            NamedOnnxValue.CreateFromTensor(imgName,  imgTensor),
+            NamedOnnxValue.CreateFromTensor(sizeName, sizeTensor),
         };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/BubbleDetectionService.cs` around lines 118 - 123, Update
the input construction in the RT-DETR inference flow to bind tensors by the
documented input names images and orig_target_sizes when those metadata entries
exist. Add a positional fallback only for supported reordered two-input graphs,
and handle missing or single-input metadata without indexing inputNames blindly;
preserve the existing imgTensor and sizeTensor values.

102-110: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Replace per-pixel GetPixel fills with raw RGBA span reads.

Both detect paths create 640×640 SKColorType.Rgba8888 bitmaps for ONNX inputs, so the nested 409 600 GetPixel calls dominate preprocessing before the actual inference. Read the bitmap buffer once and write the RGB planes in order.

SKAlphaType is Premul, so the raw pixel bytes are premultiplied; keep that when switching to packed RGBA reads if downstream consumers depend on the current input semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/BubbleDetectionService.cs` around lines 102 - 110,
Replace the nested per-pixel GetPixel loop in the image-tensor construction used
by both detection paths with a single raw RGBA buffer/span read from the
SKColorType.Rgba8888 bitmap. Populate the RGB tensor planes in the existing
order while preserving premultiplied-alpha byte semantics, and reuse the
resulting approach across both detect paths.
server/src/Routes/TranslatePage.cs (1)

57-59: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Job is uncancellable.

CancellationToken.None means a cancelled/evicted job keeps consuming InferenceQueue slots to completion, and IHostApplicationLifetime shutdown won't drain it. Storing a CancellationTokenSource on the job record (cancelled by TranslationJobStore eviction and on shutdown) would let TranslatePageAsync's existing ct.ThrowIfCancellationRequested() do its job.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Routes/TranslatePage.cs` around lines 57 - 59, Replace the
CancellationToken.None argument in the TranslatePageAsync call with a per-job
cancellation token sourced from the job record. Add and persist a
CancellationTokenSource for each job, have TranslationJobStore cancel it when
evicting jobs and during IHostApplicationLifetime shutdown, and pass its token
so the existing cancellation checks can stop processing.
server/src/Data/AppDbContext.cs (1)

69-95: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider an index (and FK) on PageTranslationLog.JobId.

Every studio/portal read path filters PageTranslationLogs by JobId (e.g. PageTranslationService.RedetectAsync, RerenderAsync, PortalRoutes), but JobId is a bare string with no relationship to PageTranslationJob and no index — full scans as the table grows, plus orphaned rows when a job is deleted. Configuring it as a FK with cascade delete in OnModelCreating and committing the matching migration would fix both.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Data/AppDbContext.cs` around lines 69 - 95, The
PageTranslationLog.JobId property lacks a relationship and index, causing
inefficient lookups and orphaned records. In AppDbContext.OnModelCreating,
configure PageTranslationLog.JobId as a foreign key to PageTranslationJob with
an index and cascade delete behavior, then add and commit the corresponding EF
Core migration.
server/src/Services/TypesettingService.cs (1)

58-70: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Clip drawing to the bubble rect.

Nothing constrains the drawn glyphs to box; when the best-fit search bottoms out at minSize and still doesn't fit, text is painted over neighbouring art. canvas.Save() + ClipRect(box) + Restore() around the text loop bounds the damage.

Also applies to: 94-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/TypesettingService.cs` around lines 58 - 70, Update
RenderTextInBubble to save the canvas state and clip drawing to the bubble
rectangle before the text-rendering loop. Restore the canvas state after the
loop so glyphs cannot paint over neighboring art while preserving the existing
fill and layout behavior.
server/ClientApp/src/components/BubbleCanvas.tsx (1)

372-381: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Layout only recomputes on window resize — overlay drifts when the container resizes.

Layout.tsx's sidebar animates w-14 → w-48 on hover, which changes this container's width without firing a window resize. The SVG overlay stays mapped to the old scale/offset until the window itself is resized. A ResizeObserver on containerRef covers both cases.

♻️ Proposed refactor
   onMount(() => {
     computeLayout();
-    window.addEventListener("resize", computeLayout);
+    const ro = new ResizeObserver(() => computeLayout());
+    ro.observe(containerRef);
     onCleanup(() => {
-      window.removeEventListener("resize", computeLayout);
+      ro.disconnect();
       // safety cleanup if drag was in progress
       window.removeEventListener("mousemove", onWindowMouseMove);
       window.removeEventListener("mouseup", onWindowMouseUp);
     });
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/components/BubbleCanvas.tsx` around lines 372 - 381,
Update the onMount lifecycle in BubbleCanvas to observe containerRef with
ResizeObserver and call computeLayout whenever the container changes size,
including sidebar hover transitions. Disconnect the observer during onCleanup
while preserving the existing window resize listener and drag-handler cleanup.
server/ClientApp/src/components/Layout.tsx (1)

38-38: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Use the Tailwind v4 postfix important modifier.

The project uses Tailwind v4, where !text-white is legacy/deprecated syntax. Use text-white! so the active nav link explicitly overrides the inherited text color.

🐛 Proposed fix
-            activeClass="bg-slate-800 !text-white"
+            activeClass="bg-slate-800 text-white!"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/components/Layout.tsx` at line 38, Update the
activeClass value in the Layout navigation styling to replace the legacy
!text-white utility with Tailwind v4’s postfix important modifier text-white!,
preserving the existing background class and override behavior.
server/ClientApp/src/pages/ChapterPage.tsx (1)

159-173: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Sequential updateJob awaits in the assignment loop.

Each selected job is assigned one at a time via a for loop with await inside; this serializes N round trips. Parallelizing with Promise.all reduces latency for multi-select assignment.

⚡ Suggested fix
-      const ids = [...selectedJobIds()];
-      const baseOrder = (jobs()?.length ?? 0);
-      for (let i = 0; i < ids.length; i++) {
-        await updateJob(ids[i], { chapterId: chapterId(), pageOrder: baseOrder + i });
-      }
+      const ids = [...selectedJobIds()];
+      const baseOrder = (jobs()?.length ?? 0);
+      await Promise.all(
+        ids.map((id, i) => updateJob(id, { chapterId: chapterId(), pageOrder: baseOrder + i })),
+      );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/pages/ChapterPage.tsx` around lines 159 - 173, Update
assignJobs to run the selected jobs’ updateJob calls concurrently with
Promise.all instead of awaiting each request sequentially in the loop, while
preserving the existing pageOrder assignments and post-assignment state updates.
server/ClientApp/src/components/ConfirmDialog.tsx (1)

3-36: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Confirm button has no pending/disabled guard against double-submit.

Unlike the Save buttons in LibraryPage/VolumePage (which disable while saving()), the confirm button here has no loading/disabled state. A fast double-click fires the destructive onConfirm (delete) callback twice before the dialog closes. The confirmClass default already ships disabled:opacity-50 styling, suggesting a disabled state was intended but never wired up.

🔒 Suggested fix: add an optional `loading` prop
 interface ConfirmDialogProps {
   open: boolean;
   title: string;
   message: string;
   confirmLabel?: string;
   confirmClass?: string;
+  loading?: boolean;
   onConfirm: () => void;
   onCancel: () => void;
 }
...
         <button
           class={...}
           onClick={props.onConfirm}
+          disabled={props.loading}
         >
-          {props.confirmLabel ?? "Delete"}
+          {props.loading ? "Deleting…" : (props.confirmLabel ?? "Delete")}
         </button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/components/ConfirmDialog.tsx` around lines 3 - 36,
Update ConfirmDialogProps and ConfirmDialog so the confirm button accepts an
optional loading state, disables itself while loading, and preserves the
existing disabled styling. Ensure the onConfirm callback cannot be triggered by
repeated clicks during loading, while retaining current behavior when loading is
unset or false.
server/ClientApp/src/components/Modal.tsx (1)

19-44: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Modal lacks keyboard dismissal and focus management.

No Escape key handler, no role="dialog"/aria-modal, and focus isn't moved into the panel on open or restored on close. Keyboard-only users can't dismiss the modal without a pointer.

♿ Suggested improvements
 export function Modal(props: ModalProps) {
   createEffect(() => {
     document.body.style.overflow = props.open ? "hidden" : "";
+    if (!props.open) return;
+    const onKeyDown = (e: KeyboardEvent) => {
+      if (e.key === "Escape") props.onClose();
+    };
+    document.addEventListener("keydown", onKeyDown);
     return () => {
       document.body.style.overflow = "";
+      document.removeEventListener("keydown", onKeyDown);
     };
   });
...
       <div
         class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
+        role="dialog"
+        aria-modal="true"
         onClick={...}
       >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/components/Modal.tsx` around lines 19 - 44, Update the
Modal component to support keyboard dismissal and focus management: add an
Escape-key handler, apply role="dialog" and aria-modal="true" to the panel, move
focus into the panel when props.open becomes true, and restore focus to the
previously focused element when closing. Use the existing panel and
props.onClose flow, preserving backdrop and close-button behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extension/build.ts`:
- Line 122: Update the archive creation step in the extension build flow to use
a platform-independent, repository-managed implementation instead of invoking
the host-installed zip binary. Preserve the existing selfhost-ocr.zip output and
inclusion of all dist contents without requiring CI or developer machine package
installation.

In `@extension/src/background.ts`:
- Around line 256-270: Update fetchImageAsBase64 to use an AbortController
timeout for the fetch, require an image/* response Content-Type, and reject
responses whose Content-Length or downloaded blob size exceeds a defined maximum
before creating the Uint8Array and base64 string. Preserve the existing
error-result contract and ensure the timeout signal is passed to fetch and
cleaned up after completion.

In `@extension/src/content.ts`:
- Around line 623-651: Hoist the EventSource created in the image-translation
flow into the module-level activeEventSource handle, replacing any existing
stream before opening a new one. Update exitImageMode() to close and clear
activeEventSource so cancellation, navigation, rescans, and image changes stop
the old stream and prevent its handlers from mutating current UI state.
- Around line 599-604: Update the response guard in the image-fetch flow around
chrome.runtime.sendMessage to handle an undefined result and treat any truthy
error or missing/empty base64 as a failure. Preserve the intended fallback
message “Failed to fetch image” when no usable error is provided, and only
assign result.base64 after validation.

In `@server/ClientApp/src/api.ts`:
- Around line 90-94: Update updateJob and the related bubble, volume, and
chapter mutation functions to serialize request bodies with snake_case field
names, including converting chapterId and pageOrder before calling apiFetch.
Apply the same transformation consistently to every mutation payload while
preserving the existing endpoints and methods.

In `@server/ClientApp/src/pages/ChapterPage.tsx`:
- Around line 138-148: Update openAssignModal so it retrieves all available job
pages, or otherwise uses the listJobs API’s supported unassigned-job filtering,
before applying the !j.chapterId eligibility check. Ensure setUnassignedJobs
includes eligible jobs beyond the first 50 while preserving the existing loading
and modal state behavior.

In `@server/ClientApp/src/pages/JobsListPage.tsx`:
- Around line 17-49: The duplicated status badges assume only three server
status values and can access an undefined configuration. In
server/ClientApp/src/pages/JobsListPage.tsx#L17-L49, add a fallback branch to
StatusBadge’s cfg switch, export the shared component, and use a safe fallback
display. In server/ClientApp/src/pages/StudioPage.tsx#L35-L58, remove the local
badge implementation, import the shared StatusBadge, and remove the incorrect
ReturnType<typeof Show> annotation.

In `@server/ClientApp/src/pages/LibraryPage.tsx`:
- Line 1: Update the listed mutation handlers in LibraryPage.tsx,
VolumePage.tsx, and ChapterPage.tsx—saveVolume, confirmDeleteVolume,
saveChapter, confirmDeleteChapter, openAssignModal, assignJobs, moveJob, and
unassignJob—to catch portal API failures and surface each caught error through
the existing user-facing toast or inline error mechanism. Preserve successful
dialog, refresh, and navigation behavior while ensuring failures do not remain
silent.
- Around line 94-156: Add user-visible error handling to saveVolume,
confirmDeleteVolume, saveChapter, and confirmDeleteChapter: catch failures from
their create, update, and delete API calls, preserve the modal/target and
existing state on failure, and show an appropriate error notification using the
page’s established UI mechanism. Apply the same handling to the corresponding
operations in VolumePage and ChapterPage, while keeping success-only closing and
refetch behavior.

In `@server/src/BootExtensions.cs`:
- Around line 62-82: Update the OCR and Translate initialization paths in the
boot flow to derive model filenames from their configured FileList values,
matching the filenames used by DownloadHfModelAsync instead of hardcoding
encoder_model.onnx, decoder_model.onnx, vocab.txt, or tokenizer.json. Preserve
the existing directory and readiness behavior while ensuring each
InitializeAsync call uses the configured file ordering expected by its model.

In `@server/src/ModelSettingsStore.cs`:
- Around line 191-209: Update MergeEntry so empty persisted string values are
treated as unset: normalize file.Repo, file.Dir, and file.Files before applying
the existing environment → file → env/default fallback, allowing empty values to
reach env.Repo, env.Dir, or env.Files. Apply the same unset semantics to Enabled
so an absent or empty persisted entry falls back to the computed
environment/default value rather than false, while preserving explicit
environment overrides.

In `@server/src/Routes/PortalRoutes.cs`:
- Around line 170-260: Update the redetect, retranslate, and rerender handlers
around their Task.Run fire-and-forget flows to set the job status to processing
and persist it before returning Accepted, then set the appropriate completed or
error status in the background task and persist failures rather than only
logging them. Add per-job concurrency protection so concurrent RedetectAsync,
retranslation, or RerenderAsync executions cannot interleave updates to the same
job or bubble rows.
- Around line 113-134: Update the POST /jobs/{id}/bubbles handler to validate
that the requested job exists before querying or inserting PageTranslationLog
records. Return the endpoint’s established not-found response for an unknown id,
and preserve the current bubble creation flow for existing jobs.

In `@server/src/Routes/TranslatePage.cs`:
- Around line 24-25: Update the readiness gate in the translate-page route to
require both OCR and translation models to be ready before accepting a request.
Include the existing translation readiness symbol from the boot state alongside
boot.OcrReady, while preserving the current 503 response and success path.
- Around line 134-137: Update the response header setup in the TranslatePage
route to assign "text/event-stream" through ctx.Response.ContentType rather than
Response.Headers["Content-Type"], and remove the Connection keep-alive header.
Preserve the existing Cache-Control and X-Accel-Buffering headers.

In `@server/src/Services/BubbleDetectionService.cs`:
- Around line 39-47: Protect the shared _session lifecycle in
BubbleDetectionService with synchronization: update LoadModel and Dispose to
acquire exclusive access while replacing or disposing the session, and update
Detect to acquire shared access, validate and snapshot _session under that
protection, then hold the read lock through inference completion. Eliminate the
separate null-check/usage TOCTOU so reload or shutdown cannot dispose the
session during an in-flight Detect call.
- Around line 244-260: Update ToPixelBox to clamp the computed origin within the
original image bounds before calculating width and height, ensuring returned
dimensions are never negative. In DetectYolo, filter out boxes with zero or
negative area before passing them to Nms, matching the existing DetectRtDetr
guard.

In `@server/src/Services/PageTranslationService.cs`:
- Line 59: Ensure PageTranslationService awaits CreateJobRowAsync at
server/src/Services/PageTranslationService.cs#L59-L59, persists bubble entries
before completion at server/src/Services/PageTranslationService.cs#L142-L142,
and awaits FinalizeJobRowAsync before returning at
server/src/Services/PageTranslationService.cs#L162-L162, preserving ordering so
the row exists, all logs are committed, and jobs cannot remain permanently
processing.

In `@server/src/Services/TypesettingService.cs`:
- Around line 105-125: Update BestFitFontSize and TextFits to use the same
render font/typeface created by RenderTextInBubble instead of
SKTypeface.Default, and validate both wrapped width and total height against the
bubble bounds. Enhance WordWrap so tokens that exceed maxWidth are split at
character boundaries, ensuring long unspaced or oversized words wrap without
horizontal overflow.

In `@server/wwwroot/js/app.js`:
- Line 1: The committed app.js bundle is stale and lacks the new Studio bubble
editor and mutation API client. Regenerate the production Vite outputs from the
current portal source, ensuring the bundle loaded by App.razor contains the
implemented Studio functionality and enabled actions, then commit the updated
generated assets.

---

Outside diff comments:
In `@extension/src/background.ts`:
- Around line 30-34: Update the configuration guard in the image-mode flow to
open options whenever mode is "image" and settings.serverUrl is missing,
regardless of settings.ocrEngine. Preserve the existing server-engine check for
non-image modes and return after opening the options page.

---

Minor comments:
In `@extension/src/content.ts`:
- Around line 664-674: Update imageElementToBase64 to validate the computed
canvas dimensions before creating or encoding the canvas. When either width or
height is zero, reject with a clear “image not loaded yet” error instead of
calling toDataURL or returning an empty payload; preserve the existing encoding
behavior for valid dimensions.
- Around line 676-701: Update showImageTranslateLoading to remove any existing
imageTranslateOverlay from the DOM before creating and assigning the new loading
panel, while preserving the current initialization of imageTranslateLogList and
the upload log entry.

In `@extension/static/content.css`:
- Around line 267-284: Update the .socr-rescan styles to add a visible
:focus-visible outline for keyboard-focused Re-scan buttons, while preserving
the existing reset and hover styling.

In `@server/ClientApp/src/components/BubbleEditor.tsx`:
- Around line 69-84: Update the createEffect/on synchronization in BubbleEditor
so it reacts when the selected bubble’s object or editable fields change, not
only when bubbleIndex changes. Preserve the existing setX, setY, setW, setH,
setSourceText, setTranslatedText, and setIsExcluded updates while ensuring
externally refreshed values replace stale editor state.

In `@server/ClientApp/src/pages/StudioPage.tsx`:
- Around line 35-58: Update StatusBadge to return a fallback badge for any
unrecognized or missing status, matching the established behavior in
JobsListPage. Replace ReturnType<typeof Show> with JSX.Element and ensure every
switch path returns a valid JSX element.

In `@server/Program.cs`:
- Around line 60-88: Update the startup banner registered by ApplicationStarted
so the Dashboard URL and LAN IP entries are emitted only when TCP port mode is
active, such as when socketPath is empty; omit these nonfunctional HTTP URLs in
Unix-socket mode while preserving the existing listenInfo and banner formatting.

In `@server/src/ModelSettingsStore.cs`:
- Around line 82-93: Update ModelSettingsStore.Create so the dataRoot fallback
also applies when Path.GetDirectoryName(config.DatabasePath) returns an empty
string, using the existing current-directory “data” path for both null and empty
results. Keep the subsequent model-settings.json path construction unchanged.

In `@server/src/Routes/AnalyzeRoutes.cs`:
- Around line 19-20: Update the readiness guard for the `/analyze` route to use
`boot.DictionaryReady` (or the existing tokenizer/dictionary-specific readiness
surface) instead of `boot.IsReady`, preserving the 503 response until
dictionary/tokenizer initialization completes while allowing requests during OCR
and translation model downloads.

In `@server/src/Routes/HealthRoutes.cs`:
- Around line 14-33: Update the health payload’s OCR and Translate entries in
the models dictionary to use ms.Ocr.Enabled and ms.Translate.Enabled instead of
hardcoded true values. Extend the optionalsMissing calculation to include each
enabled OCR/Translate model that is not ready, using boot.OcrReady and
boot.TranslateReady, so the overall health status reflects disabled or failed
core models.

In `@server/src/ServiceExtensions.cs`:
- Around line 7-23: Update BootState and its access paths so
BootBackgroundService publishes readiness changes through synchronized or
volatile backing fields, and /health plus queued request handlers read a
consistent state without data races. Prefer exposing an immutable atomically
replaced snapshot while preserving the existing readiness properties and
semantics.

In `@server/src/Services/PageTranslationService.cs`:
- Around line 285-297: Update the PageTranslationJob creation logic to make the
Title expression safe for job IDs shorter than eight characters, while retaining
the existing eight-character truncation for longer IDs. Use the existing jobId
value without allowing title formatting to throw, so SaveChangesAsync can still
create the active job row.

---

Nitpick comments:
In `@server/ClientApp/src/components/BubbleCanvas.tsx`:
- Around line 372-381: Update the onMount lifecycle in BubbleCanvas to observe
containerRef with ResizeObserver and call computeLayout whenever the container
changes size, including sidebar hover transitions. Disconnect the observer
during onCleanup while preserving the existing window resize listener and
drag-handler cleanup.

In `@server/ClientApp/src/components/ConfirmDialog.tsx`:
- Around line 3-36: Update ConfirmDialogProps and ConfirmDialog so the confirm
button accepts an optional loading state, disables itself while loading, and
preserves the existing disabled styling. Ensure the onConfirm callback cannot be
triggered by repeated clicks during loading, while retaining current behavior
when loading is unset or false.

In `@server/ClientApp/src/components/Layout.tsx`:
- Line 38: Update the activeClass value in the Layout navigation styling to
replace the legacy !text-white utility with Tailwind v4’s postfix important
modifier text-white!, preserving the existing background class and override
behavior.

In `@server/ClientApp/src/components/Modal.tsx`:
- Around line 19-44: Update the Modal component to support keyboard dismissal
and focus management: add an Escape-key handler, apply role="dialog" and
aria-modal="true" to the panel, move focus into the panel when props.open
becomes true, and restore focus to the previously focused element when closing.
Use the existing panel and props.onClose flow, preserving backdrop and
close-button behavior.

In `@server/ClientApp/src/pages/ChapterPage.tsx`:
- Around line 159-173: Update assignJobs to run the selected jobs’ updateJob
calls concurrently with Promise.all instead of awaiting each request
sequentially in the loop, while preserving the existing pageOrder assignments
and post-assignment state updates.

In `@server/src/Data/AppDbContext.cs`:
- Around line 69-95: The PageTranslationLog.JobId property lacks a relationship
and index, causing inefficient lookups and orphaned records. In
AppDbContext.OnModelCreating, configure PageTranslationLog.JobId as a foreign
key to PageTranslationJob with an index and cascade delete behavior, then add
and commit the corresponding EF Core migration.

In `@server/src/Routes/TranslatePage.cs`:
- Around line 57-59: Replace the CancellationToken.None argument in the
TranslatePageAsync call with a per-job cancellation token sourced from the job
record. Add and persist a CancellationTokenSource for each job, have
TranslationJobStore cancel it when evicting jobs and during
IHostApplicationLifetime shutdown, and pass its token so the existing
cancellation checks can stop processing.

In `@server/src/Services/BubbleDetectionService.cs`:
- Around line 118-123: Update the input construction in the RT-DETR inference
flow to bind tensors by the documented input names images and orig_target_sizes
when those metadata entries exist. Add a positional fallback only for supported
reordered two-input graphs, and handle missing or single-input metadata without
indexing inputNames blindly; preserve the existing imgTensor and sizeTensor
values.
- Around line 102-110: Replace the nested per-pixel GetPixel loop in the
image-tensor construction used by both detection paths with a single raw RGBA
buffer/span read from the SKColorType.Rgba8888 bitmap. Populate the RGB tensor
planes in the existing order while preserving premultiplied-alpha byte
semantics, and reuse the resulting approach across both detect paths.

In `@server/src/Services/PageTranslationService.cs`:
- Around line 208-209: Update the deletion flow in PageTranslationService to
replace the PageTranslationLogs query and RemoveRange call with
ExecuteDeleteAsync, preserving the JobId and !IsManuallyAdded filters and
passing the existing cancellation token. Await the bulk delete directly without
materializing or tracking entities.
- Line 142: Update the bubble-processing flow around LogBubbleAsync and
FinalizeJobRowAsync to avoid fire-and-forget per-bubble database writes: buffer
all bubble log entries and persist them once per job, or await each
LogBubbleAsync call sequentially. Ensure persistence completes before
FinalizeJobRowAsync marks the job done, preserving bubble order and preventing
concurrent SQLite access.
- Line 98: Update the page translation flow around the per-bubble loop and
CropBubble so imagePng is decoded into a single SKBitmap before iterating
bubbles, then pass that bitmap into each crop operation. Change CropBubble to
accept and reuse the decoded bitmap instead of calling SKBitmap.Decode per
bubble, and dispose the shared bitmap after all crops complete.

In `@server/src/Services/TypesettingService.cs`:
- Around line 58-70: Update RenderTextInBubble to save the canvas state and clip
drawing to the bubble rectangle before the text-rendering loop. Restore the
canvas state after the loop so glyphs cannot paint over neighboring art while
preserving the existing fill and layout behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f15fe657-24b0-48d1-858d-7ed83a6d873f

📥 Commits

Reviewing files that changed from the base of the PR and between c450949 and b838ea1.

📒 Files selected for processing (66)
  • .gitignore
  • CLAUDE.md
  • README.md
  • desktop/ViewModels/MainViewModel.cs
  • desktop/Views/MainWindow.axaml
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Dashboard.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/react-app.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Components/App.razor
  • server/Components/Pages/Index.razor
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Models/ResponseModels.cs
  • server/Program.cs
  • server/Properties/launchSettings.json
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/OcrRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/SettingsRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/Routes/TranslateRoutes.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/tsconfig.json
  • server/vite.config.ts
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
💤 Files with no reviewable changes (1)
  • server/ClientApp/src/react-app.tsx

Comment thread extension/build.ts

const archiveFiles: Record<string, Uint8Array> = {};
const glob = new Bun.Glob("**/*");
await Bun.$`rm -f selfhost-ocr.zip && cd dist && zip -rq ../selfhost-ocr.zip .`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Build/package scripts:\n'
node -e 'const p=require("./extension/package.json"); console.log(p.scripts)' 2>/dev/null || true

printf '\nCI references to extension builds or zip:\n'
rg -n -i '(\bzip\b|bun .*build|extension/.*build|selfhost-ocr\.zip)' .github extension 2>/dev/null || true

Repository: deckyfx/web-ocr

Length of output: 957


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'extension/build.ts archive section:\n'
sed -n '100,135p' extension/build.ts

printf '\nPackage metadata relevant deps/scripts:\n'
node - <<'NODE'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('extension/package.json', 'utf8'));
console.log(JSON.stringify({ scripts: pkg.scripts, dependencies: pkg.dependencies, devDependencies: pkg.devDependencies, bin: pkg.bin }, null, 2));
NODE

printf '\nRepository files mentioning bun-zipper/zip-stream/fs.zip/ziputil:\n'
rg -n -i 'bun[-_]zip|zip-stream|fs\.zip|jszip|node[-_]archiver|archiver|selfhost-ocr\.zip|zip -r|ZipArchive|createWritingStream' extension package.json bun.lockb bun.lock extension/package.json .github 2>/dev/null || true

printf '\nLockfile package entries for bun-zipper/zip-stream/archiver if present:\n'
if [ -f bun.lock ]; then rg -n 'bun-zipper|zip-stream|archiver|jszip|native-node-zip' bun.lock; else true; fi

Repository: deckyfx/web-ocr

Length of output: 2039


🌐 Web query:

Bun archive ZipArchive createZipArchive documentation

💡 Result:

Bun does not provide a public API named ZipArchive. Instead, Bun includes a native class called Bun.Archive that is primarily designed for working with tar archives [1][2][3]. While the internal implementation of Bun utilizes libarchive—which supports ZIP files—the documented Bun.Archive API is officially focused on tar archives with optional gzip compression [1][2][4]. As of July 2026, the official documentation for Bun.Archive covers the following functionality [1][3]: 1. Creating archives from in-memory data (keys are file paths, values are file contents) [1][3]. 2. Extracting archives to disk [1][2]. 3. Reading archive contents without extraction using.files [1][2]. 4. Writing archives directly to disk using the static method Bun.Archive.write [2][3]. There is currently no stable, documented, or supported public API for creating ZIP files directly through the Bun.Archive class [1][2][3]. Although development activity exists in the Bun repository regarding potential zip support and streaming features, users should rely on the documented tar functionality or third-party packages for ZIP file operations [5][4].

Citations:


Don’t make the extension build depend on a host-installed zip binary.

extension/build.ts now calls zip -rq for selfhost-ocr.zip without adding a package dependency or CI install step, which can break extension releases on Windows or minimal CI runners.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/build.ts` at line 122, Update the archive creation step in the
extension build flow to use a platform-independent, repository-managed
implementation instead of invoking the host-installed zip binary. Preserve the
existing selfhost-ocr.zip output and inclusion of all dist contents without
requiring CI or developer machine package installation.

Comment thread extension/src/background.ts
Comment thread extension/src/content.ts
Comment thread extension/src/content.ts
Comment thread server/ClientApp/src/api.ts
Comment on lines +39 to +47
public void LoadModel(string modelPath)
{
_session?.Dispose();
var opts = new Microsoft.ML.OnnxRuntime.SessionOptions();
opts.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL;
opts.ExecutionMode = ExecutionMode.ORT_PARALLEL;
opts.InterOpNumThreads = Environment.ProcessorCount;
opts.IntraOpNumThreads = Environment.ProcessorCount;
_session = new InferenceSession(modelPath, opts);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

LoadModel/Dispose can race with in-flight Detect calls.

BubbleDetectionService is a shared singleton-style service: PageTranslationService.TranslatePageAsync and RedetectAsync both call Detect from Task.Run, while LoadModel disposes and replaces _session. A reload (or shutdown) concurrent with detection dereferences a disposed InferenceSessionObjectDisposedException at best, native crash at worst. _session is null checked at line 67 is also a TOCTOU against the assignment at line 47.

A ReaderWriterLockSlim (or simply snapshotting the session under a lock and holding it for the duration of the run) removes the hazard.

Also applies to: 65-76, 293-293

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/BubbleDetectionService.cs` around lines 39 - 47, Protect
the shared _session lifecycle in BubbleDetectionService with synchronization:
update LoadModel and Dispose to acquire exclusive access while replacing or
disposing the session, and update Detect to acquire shared access, validate and
snapshot _session under that protection, then hold the read lock through
inference completion. Eliminate the separate null-check/usage TOCTOU so reload
or shutdown cannot dispose the session during an in-flight Detect call.

Comment thread server/src/Services/BubbleDetectionService.cs
Comment thread server/src/Services/PageTranslationService.cs Outdated
Comment on lines +105 to +125
private static float BestFitFontSize(
string text, float maxW, float maxH, float minSize, float maxSize)
{
float lo = minSize, hi = maxSize, best = minSize;
for (int iter = 0; iter < 14; iter++)
{
float mid = (lo + hi) / 2f;
if (TextFits(text, mid, maxW, maxH)) { best = mid; lo = mid; }
else hi = mid;
if (hi - lo < 0.5f) break;
}
return best;
}

private static bool TextFits(string text, float fontSize, float maxW, float maxH)
{
using var font = new SKFont(SKTypeface.Default, fontSize);
var lines = WordWrap(text, font, maxW);
float totalH = lines.Count * fontSize * 1.25f;
return totalH <= maxH;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fit is measured with a different typeface than the one used to draw.

TextFits measures with SKTypeface.Default at the candidate size, but RenderTextInBubble draws with a bold sans-serif face (line 75). Bold advances are wider, so the chosen size regularly overflows the bubble. Pass the render SKFont/typeface into the search.

Height-only validation compounds this: WordWrap never breaks a word that is itself wider than maxW, so a single long token (or the Japanese source text used as the translation fallback in PageTranslationService line 135, which has no spaces) renders as one line spilling far outside the bubble.

🐛 Suggested direction
-    private static bool TextFits(string text, float fontSize, float maxW, float maxH)
+    private static bool TextFits(SKTypeface typeface, string text, float fontSize, float maxW, float maxH)
     {
-        using var font   = new SKFont(SKTypeface.Default, fontSize);
+        using var font   = new SKFont(typeface, fontSize);
         var       lines  = WordWrap(text, font, maxW);
         float     totalH = lines.Count * fontSize * 1.25f;
-        return totalH <= maxH;
+        return totalH <= maxH && lines.All(l => font.MeasureText(l) <= maxW);
     }

and add character-level breaking in WordWrap for tokens wider than maxWidth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Services/TypesettingService.cs` around lines 105 - 125, Update
BestFitFontSize and TextFits to use the same render font/typeface created by
RenderTextInBubble instead of SKTypeface.Default, and validate both wrapped
width and total height against the bubble bounds. Enhance WordWrap so tokens
that exceed maxWidth are split at character boundaries, ensuring long unspaced
or oversized words wrap without horizontal overflow.

Comment thread server/wwwroot/js/app.js Outdated
@@ -0,0 +1 @@
(function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};function r(e){let t=String(e),n=t.length-1;return N.context.id+(n?String.fromCharCode(96+n):``)+t}function i(e){N.context=e}function a(){return{...N.context,id:N.getNextContextId(),count:0}}function o(e,t){let n=z,r=F,i=e.length===0,a=t===void 0?r:t,o=i?Me:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(()=>h(()=>O(o)));F=o,z=null;try{return D(s,!0)}finally{z=n,F=r}}function s(e,t){t=t?Object.assign({},Oe,t):Oe;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[re.bind(n),e=>(typeof e==`function`&&(e=I&&I.running&&I.sources.has(n)?e(n.tValue):e(n.value)),S(n,e))]}function c(e,t,n){let r=T(e,t,!0,P);L&&I&&I.running?B.push(r):C(r)}function l(e,t,n){let r=T(e,t,!1,P);L&&I&&I.running?B.push(r):C(r)}function u(e,t,n){Ae=se;let r=T(e,t,!1,P),i=Le&&ne(Le);i&&(r.suspense=i),(!n||!n.render)&&(r.user=!0),V?V.push(r):C(r)}function d(e,t,n){n=n?Object.assign({},Oe,n):Oe;let r=T(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,L&&I&&I.running?(r.tState=P,B.push(r)):C(r),re.bind(r)}function f(e){return e&&typeof e==`object`&&`then`in e}function p(e,t,n){let r,i,a;typeof t==`function`?(r=e,i=t,a=n||{}):(r=!0,i=e,a=t||{});let o=null,l=Ne,u=null,p=!1,m=!1,g=`initialValue`in a,_=typeof r==`function`&&d(r),v=new Set,[y,ee]=(a.storage||s)(a.initialValue),[te,x]=s(void 0),[re,S]=s(void 0,{equals:!1}),[C,w]=s(g?`ready`:`unresolved`);N.context&&(u=N.getNextContextId(),a.ssrLoadFrom===`initial`?l=a.initialValue:N.load&&N.has(u)&&(l=N.load(u)));function T(e,t,n,r){return o===e&&(o=null,r!==void 0&&(g=!0),(e===l||t===l)&&a.onHydrated&&queueMicrotask(()=>a.onHydrated(r,{value:t})),l=Ne,I&&e&&p?(I.promises.delete(e),p=!1,D(()=>{I.running=!0,E(t,n)},!1)):E(t,n)),t}function E(e,t){D(()=>{t===void 0&&ee(()=>e),w(t===void 0?g?`ready`:`unresolved`:`errored`),x(t);for(let e of v.keys())e.decrement();v.clear()},!1)}function ie(){let e=Le&&ne(Le),t=y(),n=te();if(n!==void 0&&!o)throw n;return z&&!z.user&&e&&c(()=>{re(),o&&(e.resolved&&I&&p?I.promises.add(o):v.has(e)||(e.increment(),v.add(e)))}),t}function ae(e=!0){if(e!==!1&&m)return;m=!1;let t=_?_():r;if(p=I&&I.running,t==null||t===!1){T(o,h(y));return}I&&o&&I.promises.delete(o);let n,a=l===Ne?h(()=>{try{return i(t,{value:y(),refetching:e})}catch(e){n=e}}):l;if(n!==void 0){T(o,void 0,de(n),t);return}else if(!f(a))return T(o,a,void 0,t),a;return o=a,`v`in a?(a.s===1?T(o,a.v,void 0,t):T(o,void 0,de(a.v),t),a):(m=!0,queueMicrotask(()=>m=!1),D(()=>{w(g?`refreshing`:`pending`),S()},!1),a.then(e=>T(a,e,void 0,t),e=>T(a,void 0,de(e),t)))}Object.defineProperties(ie,{state:{get:()=>C()},error:{get:()=>te()},loading:{get(){let e=C();return e===`pending`||e===`refreshing`}},latest:{get(){if(!g)return ie();let e=te();if(e&&!o)throw e;return y()}}});let oe=F;return _?c(()=>(oe=F,ae(!1))):ae(!1),[ie,{refetch:e=>b(oe,()=>ae(e)),mutate:ee}]}function m(e){return D(e,!1)}function h(e){if(!R&&z===null)return e();let t=z;z=null;try{return R?R.untrack(e):e()}finally{z=t}}function g(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=h(()=>t(o,i,n));return i=o,s}}function _(e){u(()=>h(e))}function v(e){return F===null||(F.cleanups===null?F.cleanups=[e]:F.cleanups.push(e)),e}function y(){return F}function b(e,t){let n=F,r=z;F=e,z=null;try{return D(t,!0)}catch(e){pe(e)}finally{F=n,z=r}}function ee(e){if(I&&I.running)return e(),I.done;let t=z,n=F;return Promise.resolve().then(()=>{z=t,F=n;let r;return(L||Le)&&(r=I||={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0},r.done||=new Promise(e=>r.resolve=e),r.running=!0),D(e,!1),z=F=null,r?r.done:void 0})}function te(e,t){let n=Symbol(`context`);return{id:n,Provider:he(n),defaultValue:e}}function ne(e){let t;return F&&F.context&&(t=F.context[e.id])!==void 0?t:e.defaultValue}function x(e){let t=d(e),n=d(()=>me(t()));return n.toArray=()=>{let e=n();return Array.isArray(e)?e:e==null?[]:[e]},n}function re(){let e=I&&I.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===P)C(this);else{let e=B;B=null,D(()=>ce(this),!1),B=e}if(z){let e=this.observers;if(!e||e[e.length-1]!==z){let t=e?e.length:0;z.sources?(z.sources.push(this),z.sourceSlots.push(t)):(z.sources=[this],z.sourceSlots=[t]),e?(e.push(z),this.observerSlots.push(z.sources.length-1)):(this.observers=[z],this.observerSlots=[z.sources.length-1])}}return e&&I.sources.has(this)?this.tValue:this.value}function S(e,t,n){let r=I&&I.running&&I.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(I){let r=I.running;(r||!n&&I.sources.has(e))&&(I.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&D(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=I&&I.running;r&&I.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?B.push(n):V.push(n),n.observers&&le(n)),r?n.tState=P:n.state=P)}if(B.length>1e6)throw B=[],Error()},!1)}return t}function C(e){if(!e.fn)return;O(e);let t=Pe;w(e,I&&I.running&&I.sources.has(e)?e.tValue:e.value,t),I&&!I.running&&I.sources.has(e)&&queueMicrotask(()=>{D(()=>{I&&(I.running=!0),z=F=e,w(e,e.tValue,t),z=F=null},!1)})}function w(e,t,n){let r,i=F,a=z;z=F=e;try{r=e.fn(t)}catch(t){return e.pure&&(I&&I.running?(e.tState=P,e.tOwned&&e.tOwned.forEach(O),e.tOwned=void 0):(e.state=P,e.owned&&e.owned.forEach(O),e.owned=null)),e.updatedAt=n+1,pe(t)}finally{z=a,F=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?S(e,r,!0):I&&I.running&&e.pure?(I.sources.has(e)||(e.value=r),I.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function T(e,t,n,r=P,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:F,context:F?F.context:null,pure:n};if(I&&I.running&&(a.state=0,a.tState=r),F===null||F!==Me&&(I&&I.running&&F.pure?F.tOwned?F.tOwned.push(a):F.tOwned=[a]:F.owned?F.owned.push(a):F.owned=[a]),R&&a.fn){let e=a.fn,[t,n]=s(void 0,{equals:!1}),r=R.factory(e,n);v(()=>r.dispose());let i,o=()=>ee(n).then(()=>{i&&=(i.dispose(),void 0)});a.fn=n=>(t(),I&&I.running?(i||=R.factory(e,o),i.track(n)):r.track(n))}return a}function E(e){let t=I&&I.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===je)return ce(e);if(e.suspense&&h(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Pe);){if(t&&I.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(I.disposed.has(t))return}if((t?e.tState:e.state)===P)C(e);else if((t?e.tState:e.state)===je){let t=B;B=null,D(()=>ce(e,n[0]),!1),B=t}}}function D(e,t){if(B)return e();let n=!1;t||(B=[]),V?n=!0:V=[],Pe++;try{let t=e();return ie(n),t}catch(e){n||(V=null),B=null,pe(e)}}function ie(e){if(B&&=(L&&I&&I.running?oe(B):ae(B),null),e)return;let t;if(I){if(!I.promises.size&&!I.queue.size){let e=I.sources,n=I.disposed;V.push.apply(V,I.effects),t=I.resolve;for(let e of V)`tState`in e&&(e.state=e.tState),delete e.tState;I=null,D(()=>{for(let e of n)O(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)O(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}Ie(!1)},!1)}else if(I.running){I.running=!1,I.effects.push.apply(I.effects,V),V=null,Ie(!0);return}}let n=V;V=null,n.length&&D(()=>Ae(n),!1),t&&t()}function ae(e){for(let t=0;t<e.length;t++)E(e[t])}function oe(e){for(let t=0;t<e.length;t++){let n=e[t],r=I.queue;r.has(n)||(r.add(n),L(()=>{r.delete(n),D(()=>{I.running=!0,E(n)},!1),I&&(I.running=!1)}))}}function se(e){let t,n=0;for(t=0;t<e.length;t++){let r=e[t];r.user?e[n++]=r:E(r)}if(N.context){if(N.count){N.effects||=[],N.effects.push(...e.slice(0,n));return}i()}for(N.effects&&(N.done||!N.count)&&(e=[...N.effects,...e],n+=N.effects.length,delete N.effects),t=0;t<n;t++)E(e[t])}function ce(e,t){let n=I&&I.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===P?i!==t&&(!i.updatedAt||i.updatedAt<Pe)&&E(i):e===je&&ce(i,t)}}}function le(e){let t=I&&I.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=je:r.state=je,r.pure?B.push(r):V.push(r),r.observers&&le(r))}}function O(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)O(e.tOwned[t]);delete e.tOwned}if(I&&I.running&&e.pure)ue(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)O(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}I&&I.running?e.tState=0:e.state=0}function ue(e,t){if(t||(e.tState=0,I.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ue(e.owned[t])}function de(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function fe(e,t,n){try{for(let n of t)n(e)}catch(e){pe(e,n&&n.owner||null)}}function pe(e,t=F){let n=ke&&t&&t.context&&t.context[ke],r=de(e);if(!n)throw r;V?V.push({fn(){fe(r,n,t)},state:P}):fe(r,n,t)}function me(e){if(typeof e==`function`&&!e.length)return me(e());if(Array.isArray(e)){let t=[];for(let n=0;n<e.length;n++){let r=me(e[n]);if(Array.isArray(r))if(r.length<32768)t.push.apply(t,r);else for(let e=0;e<r.length;e++)t.push(r[e]);else t.push(r)}return t}return e}function he(e,t){return function(t){let n;return l(()=>n=h(()=>(F.context={...F.context,[e]:t.value},x(()=>t.children))),void 0),n}}function ge(e){for(let t=0;t<e.length;t++)e[t]()}function _e(e,t,n={}){let r=[],i=[],a=[],c=0,l=t.length>1?[]:null;return v(()=>ge(a)),()=>{let u=e()||[],d=u.length,f,p;return u[De],h(()=>{let e,t,s,h,g,_,v,y,b;if(d===0)c!==0&&(ge(a),a=[],r=[],i=[],c=0,l&&=[]),n.fallback&&(r=[Re],i[0]=o(e=>(a[0]=e,n.fallback())),c=1);else if(c===0){for(i=Array(d),p=0;p<d;p++)r[p]=u[p],i[p]=o(m);c=d}else{for(s=Array(d),h=Array(d),l&&(g=Array(d)),_=0,v=Math.min(c,d);_<v&&r[_]===u[_];_++);for(v=c-1,y=d-1;v>=_&&y>=_&&r[v]===u[y];v--,y--)s[y]=i[v],h[y]=a[v],l&&(g[y]=l[v]);for(e=new Map,t=Array(y+1),p=y;p>=_;p--)b=u[p],f=e.get(b),t[p]=f===void 0?-1:f,e.set(b,p);for(f=_;f<=v;f++)b=r[f],p=e.get(b),p!==void 0&&p!==-1?(s[p]=i[f],h[p]=a[f],l&&(g[p]=l[f]),p=t[p],e.set(b,p)):a[f]();for(p=_;p<d;p++)p in s?(i[p]=s[p],a[p]=h[p],l&&(l[p]=g[p],l[p](p))):i[p]=o(m);i=i.slice(0,c=d),r=u.slice(0)}return i});function m(e){if(a[p]=e,l){let[e,n]=s(p);return l[p]=n,t(u[p],e)}return t(u[p])}}}function k(e,t){if(ze&&N.context){let n=N.context;i(a());let r=h(()=>e(t||{}));return i(n),r}return h(()=>e(t||{}))}function ve(){return!0}function ye(e){return(e=typeof e==`function`?e():e)?e:{}}function be(){for(let e=0,t=this.length;e<t;++e){let t=this[e]();if(t!==void 0)return t}}function A(...e){let t=!1;for(let n=0;n<e.length;n++){let r=e[n];t||=!!r&&Te in r,e[n]=typeof r==`function`?(t=!0,d(r)):r}if(Ee&&t)return new Proxy({get(t){for(let n=e.length-1;n>=0;n--){let r=ye(e[n])[t];if(r!==void 0)return r}},has(t){for(let n=e.length-1;n>=0;n--)if(t in ye(e[n]))return!0;return!1},keys(){let t=[];for(let n=0;n<e.length;n++)t.push(...Object.keys(ye(e[n])));return[...new Set(t)]}},Be);let n={},r=Object.create(null);for(let t=e.length-1;t>=0;t--){let i=e[t];if(!i)continue;let a=Object.getOwnPropertyNames(i);for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===`__proto__`||t===`constructor`)continue;let o=Object.getOwnPropertyDescriptor(i,t);if(!r[t])r[t]=o.get?{enumerable:!0,configurable:!0,get:be.bind(n[t]=[o.get.bind(i)])}:o.value===void 0?void 0:o;else{let e=n[t];e&&(o.get?e.push(o.get.bind(i)):o.value!==void 0&&e.push(()=>o.value))}}}let i={},a=Object.keys(r);for(let e=a.length-1;e>=0;e--){let t=a[e],n=r[t];n&&n.get?Object.defineProperty(i,t,n):i[t]=n?n.value:void 0}return i}function xe(e,...t){let n=t.length;if(Ee&&Te in e){let r=n>1?t.flat():t[0],i=t.map(t=>new Proxy({get(n){return t.includes(n)?e[n]:void 0},has(n){return t.includes(n)&&n in e},keys(){return t.filter(t=>t in e)}},Be));return i.push(new Proxy({get(t){return r.includes(t)?void 0:e[t]},has(t){return r.includes(t)?!1:t in e},keys(){return Object.keys(e).filter(e=>!r.includes(e))}},Be)),i}let r=[];for(let e=0;e<=n;e++)r[e]={};for(let i of Object.getOwnPropertyNames(e)){let a=n;for(let e=0;e<t.length;e++)if(t[e].includes(i)){a=e;break}let o=Object.getOwnPropertyDescriptor(e,i);!o.get&&!o.set&&o.enumerable&&o.writable&&o.configurable?r[a][i]=o.value:Object.defineProperty(r[a],i,o)}return r}function Se(e){let t,n,r=r=>{let a=N.context;if(a){let[r,o]=s();N.count||=0,N.count++,(n||=e()).then(e=>{!N.done&&i(a),N.count--,o(()=>e.default),i()}),t=r}else if(!t){let[r]=p(()=>(n||=e()).then(e=>e.default));t=r}let o;return d(()=>(o=t())?h(()=>{if(!a||N.done)return o(r);let e=N.context;i(a);let t=o(r);return i(e),t}):``)};return r.preload=()=>n||((n=e()).then(e=>t=()=>e.default),n),r}function j(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return d(_e(()=>e.each,e.children,t||void 0))}function M(e){let t=e.keyed,n=d(()=>e.when,void 0,void 0),r=t?n:d(n,void 0,{equals:(e,t)=>!e==!t});return d(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?h(()=>a(t?i:()=>{if(!h(r))throw Ve(`Show`);return n()})):a}return e.fallback},void 0,void 0)}function Ce(){He&&[...He].forEach(e=>e())}var N,we,Te,Ee,De,Oe,ke,Ae,P,je,Me,Ne,F,I,L,R,z,B,V,Pe,Fe,Ie,Le,Re,ze,Be,Ve,He,H=t((()=>{N={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return r(this.context.count)},getNextContextId(){return r(this.context.count++)}},we=(e,t)=>e===t,Te=Symbol(`solid-proxy`),Ee=typeof Proxy==`function`,De=Symbol(`solid-track`),Oe={equals:we},ke=null,Ae=ae,P=1,je=2,Me={owned:null,cleanups:null,context:null,owner:null},Ne={},F=null,I=null,L=null,R=null,z=null,B=null,V=null,Pe=0,[Fe,Ie]=s(!1),Re=Symbol(`fallback`),ze=!1,Be={get(e,t,n){return t===Te?n:e.get(t)},has(e,t){return t===Te?!0:e.has(t)},set:ve,deleteProperty:ve,getOwnPropertyDescriptor(e,t){return{configurable:!0,enumerable:!0,get(){return e.get(t)},set:ve,deleteProperty:ve}},ownKeys(e){return e.keys()}},Ve=e=>`Stale read from <${e}>.`}));function Ue(e,t){let n=vt[e];return typeof n==`object`?n[t]?n.$:void 0:n}function We(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;){if(t[o]===n[s]){o++,s++;continue}for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)(!l||!l.has(t[o]))&&t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null)if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&!((d=l.get(t[c]))==null||d!==r+u);)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++;else t[o++].remove()}}}function Ge(e,t,n,r={}){let i;return o(r=>{i=r,t===document?e():G(t,e(),t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function U(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>h(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function Ke(e,t=window.document){let n=t[St]||(t[St]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,ot))}}function W(e,t,n){K(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function qe(e,t,n,r){K(e)||(r==null?e.removeAttributeNS(t,n):e.setAttributeNS(t,n,r))}function Je(e,t,n){K(e)||(n?e.setAttribute(t,``):e.removeAttribute(t))}function Ye(e,t){K(e)||(t==null?e.removeAttribute(`class`):e.className=t)}function Xe(e,t,n,r){if(r)Array.isArray(n)?(e[`$$${t}`]=n[0],e[`$$${t}Data`]=n[1]):e[`$$${t}`]=n;else if(Array.isArray(n)){let r=n[0];e.addEventListener(t,n[0]=t=>r.call(e,n[1],t))}else e.addEventListener(t,n,typeof n!=`function`&&n)}function Ze(e,t,n={}){let r=Object.keys(t||{}),i=Object.keys(n),a,o;for(a=0,o=i.length;a<o;a++){let r=i[a];!r||r===`undefined`||t[r]||(it(e,r,!1),delete n[r])}for(a=0,o=r.length;a<o;a++){let i=r[a],o=!!t[i];!i||i===`undefined`||n[i]===o||!o||(it(e,i,!0),n[i]=o)}return n}function Qe(e,t,n){if(!t)return n?W(e,`style`):t;let r=e.style;if(typeof t==`string`)return r.cssText=t;typeof n==`string`&&(r.cssText=n=void 0),n||={},t||={};let i,a;for(a in n)t[a]??r.removeProperty(a),delete n[a];for(a in t)i=t[a],i!==n[a]&&(r.setProperty(a,i),n[a]=i);return n}function $e(e,t={},n,r){let i={};return r||l(()=>i.children=st(e,t.children,i.children)),l(()=>typeof t.ref==`function`&&et(t.ref,e)),l(()=>tt(e,t,n,!0,i,!0)),i}function et(e,t,n){return h(()=>e(t,n))}function G(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return st(e,t,r,n);l(r=>st(e,t(),r,n),r)}function tt(e,t,n,r,i={},a=!1){t||={};for(let r in i)if(!(r in t)){if(r===`children`)continue;i[r]=at(e,r,null,i[r],n,a,t)}for(let o in t){if(o===`children`){r||st(e,t.children);continue}let s=t[o];i[o]=at(e,o,s,i[o],n,a,t)}}function nt(e){let t,n;return!K()||!(t=N.registry.get(n=dt()))?e():(N.completed&&N.completed.add(t),N.registry.delete(n),t)}function K(e){return!!N.context&&!N.done&&(!e||e.isConnected)}function rt(e){return e.toLowerCase().replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function it(e,t,n){let r=t.trim().split(/\s+/);for(let t=0,i=r.length;t<i;t++)e.classList.toggle(r[t],n)}function at(e,t,n,r,i,a,o){let s,c,l,u,d;if(t===`style`)return Qe(e,n,r);if(t===`classList`)return Ze(e,n,r);if(n===r)return r;if(t===`ref`)a||n(e);else if(t.slice(0,3)===`on:`){let i=t.slice(3);r&&e.removeEventListener(i,r,typeof r!=`function`&&r),n&&e.addEventListener(i,n,typeof n!=`function`&&n)}else if(t.slice(0,10)===`oncapture:`){let i=t.slice(10);r&&e.removeEventListener(i,r,!0),n&&e.addEventListener(i,n,!0)}else if(t.slice(0,2)===`on`){let i=t.slice(2).toLowerCase(),a=yt.has(i);if(!a&&r){let t=Array.isArray(r)?r[0]:r;e.removeEventListener(i,t)}(a||n)&&(Xe(e,i,n,a),a&&Ke([i]))}else if(t.slice(0,5)===`attr:`)W(e,t.slice(5),n);else if(t.slice(0,5)===`bool:`)Je(e,t.slice(5),n);else if((d=t.slice(0,5)===`prop:`)||(l=gt.has(t))||!i&&((u=Ue(t,e.tagName))||(c=ht.has(t)))||(s=e.nodeName.includes(`-`)||`is`in o)){if(d)t=t.slice(5),c=!0;else if(K(e))return n;t===`class`||t===`className`?Ye(e,n):s&&!c&&!l?e[rt(t)]=n:e[u||t]=n}else{let r=i&&t.indexOf(`:`)>-1&&xt[t.split(`:`)[0]];r?qe(e,r,t,n):W(e,_t[t]||t,n)}return n}function ot(e){if(N.registry&&N.events&&N.events.find(([t,n])=>n===e))return;let t=e.target,n=`$$${e.type}`,r=e.target,i=e.currentTarget,a=t=>Object.defineProperty(e,"target",{configurable:!0,value:t}),o=()=>{let r=t[n];if(r&&!t.disabled){let i=t[`${n}Data`];if(i===void 0?r.call(t,e):r.call(t,i,e),e.cancelBubble)return}return t.host&&typeof t.host!=`string`&&!t.host._$host&&t.contains(e.target)&&a(t.host),!0},s=()=>{for(;o()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),N.registry&&!N.done&&(N.done=_$HY.done=!0),e.composedPath){let n=e.composedPath();a(n[0]);for(let e=0;e<n.length-2&&(t=n[e],o());e++){if(t._$host){t=t._$host,s();break}if(t.parentNode===i)break}}else s();a(r)}function st(e,t,n,r,i){let a=K(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=ut(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=ut(e,n,r)}else if(o===`function`)return l(()=>{let i=t();for(;typeof i==`function`;)i=i();n=st(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(ct(o,t,n,i))return l(()=>n=st(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=ut(e,n,r),s)return n}else c?n.length===0?lt(e,o,r):We(e,n,o):(n&&ut(e),lt(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=ut(e,n,r,t);ut(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function ct(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(!(o==null||o===!0||o===!1))if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=ct(e,o,s)||i;else if(c===`function`)if(r){for(;typeof o==`function`;)o=o();i=ct(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0;else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}return i}function lt(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function ut(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}function dt(){return N.getNextContextId()}function ft(e,t=!1,n=void 0){return t?document.createElementNS(Ct,e):document.createElement(e,{is:n})}function pt(e,t){let n=d(e);return d(()=>{let e=n();switch(typeof e){case`function`:return h(()=>e(t));case`string`:let n=bt.has(e),r=N.context?nt():ft(e,n,h(()=>t.is));return $e(r,t,n),r}})}function mt(e){let[,t]=xe(e,[`component`]);return pt(()=>e.component,t)}var ht,gt,_t,vt,yt,bt,xt,q,St,Ct,J=t((()=>{H(),ht=new Set([`className`,`value`,`readOnly`,`noValidate`,`formNoValidate`,`isMap`,`noModule`,`playsInline`,`adAuctionHeaders`,`allowFullscreen`,`browsingTopics`,`defaultChecked`,`defaultMuted`,`defaultSelected`,`disablePictureInPicture`,`disableRemotePlayback`,`preservesPitch`,`shadowRootClonable`,`shadowRootCustomElementRegistry`,`shadowRootDelegatesFocus`,`shadowRootSerializable`,`sharedStorageWritable`,...`allowfullscreen.async.alpha.autofocus.autoplay.checked.controls.default.disabled.formnovalidate.hidden.indeterminate.inert.ismap.loop.multiple.muted.nomodule.novalidate.open.playsinline.readonly.required.reversed.seamless.selected.adauctionheaders.browsingtopics.credentialless.defaultchecked.defaultmuted.defaultselected.defer.disablepictureinpicture.disableremoteplayback.preservespitch.shadowrootclonable.shadowrootcustomelementregistry.shadowrootdelegatesfocus.shadowrootserializable.sharedstoragewritable`.split(`.`)]),gt=new Set([`innerHTML`,`textContent`,`innerText`,`children`]),_t=Object.assign(Object.create(null),{className:`class`,htmlFor:`for`}),vt=Object.assign(Object.create(null),{class:`className`,novalidate:{$:`noValidate`,FORM:1},formnovalidate:{$:`formNoValidate`,BUTTON:1,INPUT:1},ismap:{$:`isMap`,IMG:1},nomodule:{$:`noModule`,SCRIPT:1},playsinline:{$:`playsInline`,VIDEO:1},readonly:{$:`readOnly`,INPUT:1,TEXTAREA:1},adauctionheaders:{$:`adAuctionHeaders`,IFRAME:1},allowfullscreen:{$:`allowFullscreen`,IFRAME:1},browsingtopics:{$:`browsingTopics`,IMG:1},defaultchecked:{$:`defaultChecked`,INPUT:1},defaultmuted:{$:`defaultMuted`,AUDIO:1,VIDEO:1},defaultselected:{$:`defaultSelected`,OPTION:1},disablepictureinpicture:{$:`disablePictureInPicture`,VIDEO:1},disableremoteplayback:{$:`disableRemotePlayback`,AUDIO:1,VIDEO:1},preservespitch:{$:`preservesPitch`,AUDIO:1,VIDEO:1},shadowrootclonable:{$:`shadowRootClonable`,TEMPLATE:1},shadowrootdelegatesfocus:{$:`shadowRootDelegatesFocus`,TEMPLATE:1},shadowrootserializable:{$:`shadowRootSerializable`,TEMPLATE:1},sharedstoragewritable:{$:`sharedStorageWritable`,IFRAME:1,IMG:1}}),yt=new Set([`beforeinput`,`click`,`dblclick`,`contextmenu`,`focusin`,`focusout`,`input`,`keydown`,`keyup`,`mousedown`,`mousemove`,`mouseout`,`mouseover`,`mouseup`,`pointerdown`,`pointermove`,`pointerout`,`pointerover`,`pointerup`,`touchend`,`touchmove`,`touchstart`]),bt=new Set(`altGlyph.altGlyphDef.altGlyphItem.animate.animateColor.animateMotion.animateTransform.circle.clipPath.color-profile.cursor.defs.desc.ellipse.feBlend.feColorMatrix.feComponentTransfer.feComposite.feConvolveMatrix.feDiffuseLighting.feDisplacementMap.feDistantLight.feDropShadow.feFlood.feFuncA.feFuncB.feFuncG.feFuncR.feGaussianBlur.feImage.feMerge.feMergeNode.feMorphology.feOffset.fePointLight.feSpecularLighting.feSpotLight.feTile.feTurbulence.filter.font.font-face.font-face-format.font-face-name.font-face-src.font-face-uri.foreignObject.g.glyph.glyphRef.hkern.image.line.linearGradient.marker.mask.metadata.missing-glyph.mpath.path.pattern.polygon.polyline.radialGradient.rect.set.stop.svg.switch.symbol.text.textPath.tref.tspan.use.view.vkern`.split(`.`)),xt={xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`},q=e=>d(()=>e()),St=`_$DX_DELEGATE`,Ct=`http://www.w3.org/2000/svg`}));J();function wt(){let e=new Set;function t(t){return e.add(t),()=>e.delete(t)}let n=!1;function r(t,r){if(n)return!(n=!1);let i={to:t,options:r,defaultPrevented:!1,preventDefault:()=>i.defaultPrevented=!0};for(let a of e)a.listener({...i,from:a.location,retry:e=>{e&&(n=!0),a.navigate(t,{...r,resolve:!1})}});return!i.defaultPrevented}return{subscribe:t,confirm:r}}function Tt(){(!window.history.state||window.history.state._depth==null)&&window.history.replaceState({...window.history.state,_depth:window.history.length-1},``),Ot=window.history.state._depth}function Et(e){return{...e,_depth:window.history.state&&window.history.state._depth}}function Dt(e,t){let n=!1;return()=>{let r=Ot;Tt();let i=r==null?null:Ot-r;if(n){n=!1;return}i&&t(i)?(n=!0,window.history.go(-i)):e()}}var Ot,kt=t((()=>{Tt()}));function Y(e,t=!1){let n=e.replace(Bt,`$1`);return n?t||/^[?#]/.test(n)?n:`/`+n:``}function At(e,t,n){if(zt.test(t))return;let r=Y(e),i=n&&Y(n),a=``;return a=!i||t.startsWith(`/`)?r:i.toLowerCase().indexOf(r.toLowerCase())===0?i:r+i,(a||`/`)+Y(t,!a)}function jt(e,t){if(e==null)throw Error(t);return e}function Mt(e,t){return Y(e).replace(/\/*(\*.*)?$/g,``)+Y(t)}function Nt(e){let t={};return e.searchParams.forEach((e,n)=>{n in t?Array.isArray(t[n])?t[n].push(e):t[n]=[t[n],e]:t[n]=e}),t}function Pt(e,t,n){let[r,i]=e.split(`/*`,2),a=r.split(`/`).filter(Boolean),o=a.length;return e=>{let r=e.split(`/`).filter(Boolean),s=r.length-o;if(s<0||s>0&&i===void 0&&!t)return null;let c={path:o?``:`/`,params:{}},l=e=>n===void 0?void 0:n[e];for(let e=0;e<o;e++){let t=a[e],n=t[0]===`:`,i=n?r[e]:r[e].toLowerCase(),o=n?t.slice(1):t.toLowerCase();if(n&&Ft(i,l(o)))c.params[o]=i;else if(n||!Ft(i,o))return null;c.path+=`/${i}`}if(i){let e=s?r.slice(-s).join(`/`):``;if(Ft(e,l(i)))c.params[i]=e;else return null}return c}}function Ft(e,t){let n=t=>t===e;return t===void 0?!0:typeof t==`string`?n(t):typeof t==`function`?t(e):Array.isArray(t)?t.some(n):t instanceof RegExp?t.test(e):!1}function It(e){let[t,n]=e.pattern.split(`/*`,2),r=t.split(`/`).filter(Boolean);return r.reduce((e,t)=>e+(t.startsWith(`:`)?2:3),r.length-(n===void 0?0:1))}function Lt(e){let t=new Map,n=y();return new Proxy({},{get(r,i){return t.has(i)||b(n,()=>t.set(i,d(()=>e()[i]))),t.get(i)()},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}},ownKeys(){return Reflect.ownKeys(e())},has(t,n){return n in e()}})}function Rt(e){let t=/(\/?\:[^\/]+)\?/.exec(e);if(!t)return[e];let n=e.slice(0,t.index),r=e.slice(t.index+t[0].length),i=[n,n+=t[1]];for(;t=/^(\/\:[^\/]+)\?/.exec(r);)i.push(n+=t[1]),r=r.slice(t[0].length);return Rt(r).reduce((e,t)=>[...e,...i.map(e=>e+t)],[])}var zt,Bt,Vt,Ht=t((()=>{H(),zt=/^(?:[a-z0-9]+:)?\/\//i,Bt=/^\/+|(\/)\/+$/g,Vt=`http://sr`}));function Ut(e,t=``){let{component:n,preload:r,load:i,children:a,info:o}=e,s=!a||Array.isArray(a)&&!a.length,c={key:e,component:n,preload:r||i,info:o};return Gt(e.path).reduce((n,r)=>{for(let i of Rt(r)){let a=Mt(t,i),o=s?a:a.split(`/*`,1)[0];o=o.split(`/`).map(e=>e.startsWith(`:`)||e.startsWith(`*`)?e:encodeURIComponent(e)).join(`/`),n.push({...c,originalPath:r,pattern:o,matcher:Pt(o,!s,e.matchFilters)})}return n},[])}function Wt(e,t=0){return{routes:e,score:It(e[e.length-1])*1e4-t,matcher(t){let n=[];for(let r=e.length-1;r>=0;r--){let i=e[r],a=i.matcher(t);if(!a)return null;n.unshift({...a,route:i})}return n}}}function Gt(e){return Array.isArray(e)?e:[e]}function Kt(e,t=``,n=[],r=[]){let i=Gt(e);for(let e=0,a=i.length;e<a;e++){let a=i[e];if(a&&typeof a==`object`){a.hasOwnProperty(`path`)||(a.path=``);let e=Ut(a,t);for(let t of e){n.push(t);let e=Array.isArray(a.children)&&a.children.length===0;if(a.children&&!e)Kt(a.children,t.pattern,n,r);else{let e=Wt([...n],r.length);r.push(e)}n.pop()}}}return n.length?r:r.sort((e,t)=>t.score-e.score)}function qt(e,t){for(let n=0,r=e.length;n<r;n++){let r=e[n].matcher(t);if(r)return r}return[]}function Jt(e,t,n){let r=new URL(Vt),i=d(t=>{let n=e();try{return new URL(n,r)}catch{return console.error(`Invalid path ${n}`),t}},r,{equals:(e,t)=>e.href===t.href}),a=d(()=>i().pathname),o=d(()=>i().search,!0),s=d(()=>i().hash),c=()=>``,l=g(o,()=>Nt(i()));return{get pathname(){return a()},get search(){return o()},get hash(){return s()},get state(){return t()},get key(){return c()},query:n?n(l):Lt(l)}}function Yt(){return un}function Xt(e){dn=e}function Zt(e,t,n,r={}){let{signal:[i,a],utils:o={}}=e,c=o.parsePath||(e=>e),u=o.renderPath||(e=>e),f=o.beforeLeave||wt(),p=At(``,r.base||``);if(p===void 0)throw Error(`${p} is not a valid base path`);p&&!i().value&&a({value:p,replace:!0,scroll:!1});let[_,v]=s(!1),y,te=(e,t)=>{t.value===x()&&t.state===S()||(y===void 0&&v(!0),un=e,y=t,ee(()=>{y===t&&(re(y.value),C(y.state),Ce(),E[1](e=>e.filter(e=>e.pending)))}).finally(()=>{y===t&&m(()=>{un=void 0,e===`navigate`&&le(y),v(!1),y=void 0})}))},[x,re]=s(i().value),[S,C]=s(i().state),w=Jt(x,S,o.queryWrapper),T=[],E=s([]),D=d(()=>typeof r.transformUrl==`function`?qt(t(),r.transformUrl(w.pathname)):qt(t(),w.pathname)),ie=()=>{let e=D(),t={};for(let n=0;n<e.length;n++)Object.assign(t,e[n].params);return t},ae=o.paramsWrapper?o.paramsWrapper(ie,t):Lt(ie),oe={pattern:p,path:()=>p,outlet:()=>null,resolvePath(e){return At(p,e)}};return l(g(i,e=>te(`native`,e),{defer:!0})),{base:oe,location:w,params:ae,isRouting:_,renderPath:u,parsePath:c,navigatorFactory:ce,matches:D,beforeLeave:f,preloadRoute:O,singleFlight:r.singleFlight===void 0?!0:r.singleFlight,submissions:E};function se(e,t,n){h(()=>{if(typeof t==`number`){t&&(o.go?o.go(t):console.warn(`Router integration does not support relative routing`));return}let r=!t||t[0]===`?`,{replace:i,resolve:a,scroll:s,state:c}={replace:!1,resolve:!r,scroll:!0,...n},l=a?e.resolvePath(t):At(r&&w.pathname||``,t);if(l===void 0)throw Error(`Path '${t}' is not a routable path`);if(T.length>=$t)throw Error(`Too many redirects`);let u=x();(l!==u||c!==S())&&f.confirm(l,n)&&(T.push({value:u,replace:i,scroll:s,state:S()}),te(`navigate`,{value:l,state:c}))})}function ce(e){return e=e||ne(tn)||oe,(t,n)=>se(e,t,n)}function le(e){let t=T[0];t&&(a({...e,replace:t.replace,scroll:t.scroll}),T.length=0)}function O(e,r){let i=qt(t(),e.pathname),a=un;un=`preload`;for(let t in i){let{route:a,params:o}=i[t];a.component&&a.component.preload&&a.component.preload();let{preload:s}=a;dn=!0,r&&s&&b(n(),()=>s({params:o,location:{pathname:e.pathname,search:e.search,hash:e.hash,query:Nt(e),state:null,key:``},intent:`preload`})),dn=!1}un=a}}function Qt(e,t,n,r){let{base:i,location:a,params:o}=e,{pattern:s,component:c,preload:l}=r().route,u=d(()=>r().path);c&&c.preload&&c.preload(),dn=!0;let f=l?l({params:o,location:a,intent:un||`initial`}):void 0;return dn=!1,{parent:t,pattern:s,path:u,outlet:()=>c?k(c,{params:o,location:a,data:f,get children(){return n()}}):n(),resolvePath(e){return At(i.path(),e,u())}}}var $t,en,tn,nn,rn,an,on,sn,cn,ln,un,dn,fn=t((()=>{H(),J(),kt(),Ht(),$t=100,en=te(),tn=te(),nn=()=>jt(ne(en),`<A> and 'use' router primitives can be only used inside a Route.`),rn=()=>ne(tn)||nn().base,an=e=>{let t=rn();return d(()=>t.resolvePath(e()))},on=e=>{let t=nn();return d(()=>{let n=e();return n===void 0?n:t.renderPath(n)})},sn=()=>nn().navigatorFactory(),cn=()=>nn().location,ln=()=>nn().params}));function pn(e){let t=e.routerState.location,n=e.routerState.params,r=d(()=>e.preload&&h(()=>{Xt(!0),e.preload({params:n,location:t,intent:Yt()||`initial`}),Xt(!1)}));return k(M,{get when(){return e.root},keyed:!0,get fallback(){return e.children},children:i=>k(i,{params:n,location:t,get data(){return r()},get children(){return e.children}})})}function mn(e){let t=[],n,r=d(g(e.routerState.matches,(i,a,s)=>{let c=a&&i.length===a.length,l=[];for(let n=0,u=i.length;n<u;n++){let u=a&&a[n],d=i[n];s&&u&&d.route.key===u.route.key?l[n]=s[n]:(c=!1,t[n]&&t[n](),o(i=>{t[n]=i,l[n]=Qt(e.routerState,l[n-1]||e.routerState.base,gn(()=>r()[n+1]),()=>{let t=e.routerState.matches();return t[n]??t[0]})}))}return t.splice(i.length).forEach(e=>e()),s&&c?s:(n=l[0],l)}));return gn(()=>r()&&n)()}var hn,gn,X,_n=t((()=>{J(),H(),fn(),hn=e=>t=>{let{base:n}=t,r=x(()=>t.children),i=d(()=>Kt(r(),t.base||``)),a,o=Zt(e,i,()=>a,{base:n,singleFlight:t.singleFlight,transformUrl:t.transformUrl});return e.create&&e.create(o),k(en.Provider,{value:o,get children(){return k(pn,{routerState:o,get root(){return t.root},get preload(){return t.rootPreload||t.rootLoad},get children(){return[q(()=>(a=y())&&null),k(mn,{routerState:o,get branches(){return i()}})]}})}})},gn=e=>()=>k(M,{get when(){return e()},keyed:!0,children:e=>k(tn.Provider,{value:e,get children(){return e.outlet()}})}),X=e=>{let t=x(()=>e.children);return A(e,{get children(){return t()}})}}));function vn([e,t],n,r){return[n?()=>n(e()):e,r?e=>t(r(e)):t]}function yn(e){let t=!1,n=e=>typeof e==`string`?{value:e}:e,r=vn(s(n(e.get()),{equals:(e,t)=>e.value===t.value&&e.state===t.state}),void 0,n=>(!t&&e.set(n),N.registry&&!N.done&&(N.done=!0),n));return e.init&&v(e.init((i=e.get())=>{t=!0,r[1](n(i)),t=!1})),hn({signal:r,create:e.create,utils:e.utils})}function bn(e,t,n){return e.addEventListener(t,n),()=>e.removeEventListener(t,n)}function xn(e,t){let n=e&&document.getElementById(e);n?n.scrollIntoView():t&&window.scrollTo(0,0)}var Sn=t((()=>{H(),_n()})),Cn,wn=t((()=>{Cn=new Map}));function Tn(e=!0,t=!1,n=`/_server`,r){return i=>{let a=i.base.path(),o=i.navigatorFactory(i.base),s,c;function l(e){return e.namespaceURI===`http://www.w3.org/2000/svg`}function u(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;let n=e.composedPath().find(e=>e instanceof Node&&e.nodeName.toUpperCase()===`A`);if(!n||t&&!n.hasAttribute(`link`))return;let r=l(n),i=r?n.href.baseVal:n.href;if((r?n.target.baseVal:n.target)||!i&&!n.hasAttribute(`state`))return;let o=(n.getAttribute(`rel`)||``).split(/\s+/);if(n.hasAttribute(`download`)||o&&o.includes(`external`))return;let s=r?new URL(i,document.baseURI):new URL(i);if(!(s.origin!==window.location.origin||a&&s.pathname&&!s.pathname.toLowerCase().startsWith(a.toLowerCase())))return[n,s]}function d(e){let t=u(e);if(!t)return;let[n,r]=t,a=i.parsePath(r.pathname+r.search+r.hash),s=n.getAttribute(`state`);e.preventDefault(),o(a,{resolve:!1,replace:n.hasAttribute(`replace`),scroll:!n.hasAttribute(`noscroll`),state:s?JSON.parse(s):void 0})}function f(e){let t=u(e);if(!t)return;let[n,a]=t;r&&(a.pathname=r(a.pathname)),i.preloadRoute(a,n.getAttribute(`preload`)!==`false`)}function p(e){clearTimeout(s);let t=u(e);if(!t)return c=null;let[n,a]=t;c!==n&&(r&&(a.pathname=r(a.pathname)),s=setTimeout(()=>{i.preloadRoute(a,n.getAttribute(`preload`)!==`false`),c=n},20))}function m(e){if(e.defaultPrevented)return;let t=e.submitter&&e.submitter.hasAttribute(`formaction`)?e.submitter.getAttribute(`formaction`):e.target.getAttribute(`action`);if(!t)return;if(!t.startsWith(`https://action/`)){let e=new URL(t,Vt);if(t=i.parsePath(e.pathname+e.search),!t.startsWith(n))return}if(e.target.method.toUpperCase()!==`POST`)throw Error(`Only POST forms are supported for Actions`);let r=Cn.get(t);if(r){e.preventDefault();let t=new FormData(e.target,e.submitter);r.call({r:i,f:e.target},e.target.enctype===`multipart/form-data`?t:new URLSearchParams(t))}}Ke([`click`,`submit`]),document.addEventListener(`click`,d),e&&(document.addEventListener(`mousemove`,p,{passive:!0}),document.addEventListener(`focusin`,f,{passive:!0}),document.addEventListener(`touchstart`,f,{passive:!0})),document.addEventListener(`submit`,m),v(()=>{document.removeEventListener(`click`,d),e&&(document.removeEventListener(`mousemove`,p),document.removeEventListener(`focusin`,f),document.removeEventListener(`touchstart`,f)),document.removeEventListener(`submit`,m)})}}var En=t((()=>{J(),H(),wn(),Ht()}));function Dn(e){let t=e.replace(/^.*?#/,``);if(!t.startsWith(`/`)){let[,e=`/`]=window.location.hash.split(`#`,2);return`${e}#${t}`}return t}function On(e){let t=()=>window.location.hash.slice(1),n=wt();return yn({get:t,set({value:e,replace:t,scroll:n,state:r}){t?window.history.replaceState(Et(r),``,`#`+e):window.history.pushState(r,``,`#`+e);let i=e.indexOf(`#`);xn(i>=0?e.slice(i+1):``,n),Tt()},init:e=>bn(window,`hashchange`,Dt(e,e=>!n.confirm(e&&e<0?e:t()))),create:Tn(e.preload,e.explicitLinks,e.actionBase),utils:{go:e=>window.history.go(e),renderPath:e=>`#${e}`,parsePath:Dn,beforeLeave:n}})(e)}var kn=t((()=>{En(),Sn(),kt()})),An=t((()=>{_n(),Sn(),J(),En(),kt(),kn()}));function jn(e){e=A({inactiveClass:`inactive`,activeClass:`active`},e);let[,t]=xe(e,[`href`,`state`,`class`,`activeClass`,`inactiveClass`,`end`]),n=an(()=>e.href),r=on(n),i=cn(),a=d(()=>{let t=n();if(t===void 0)return[!1,!1];let r=Y(t.split(/[?#]/,1)[0]).toLowerCase(),a=decodeURI(Y(i.pathname).toLowerCase());return[e.end?r===a:a.startsWith(r+`/`)||a===r,r===a]});return(()=>{var n=Mn();return $e(n,A(t,{get href(){return r()||e.href},get state(){return JSON.stringify(e.state)},get classList(){return{...e.class&&{[e.class]:!0},[e.inactiveClass]:!a()[0],[e.activeClass]:a()[0],...t.classList}},link:``,get"aria-current"(){return a()[1]?`page`:void 0}}),!1,!1),n})()}var Mn,Nn=t((()=>{J(),H(),fn(),Ht(),Mn=U(`<a>`)})),Pn=t((()=>{H(),J(),wn(),fn()})),Fn=t((()=>{An(),Nn(),kt(),fn(),Ht(),Pn()})),In,Ln=t((()=>{In={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":2,"stroke-linecap":`round`,"stroke-linejoin":`round`}})),Rn,zn,Bn,Vn,Z,Q=t((()=>{J(),H(),Ln(),Rn=U(`<svg>`),zn=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),Bn=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),Vn=e=>{let[t,n]=xe(e,[`color`,`size`,`strokeWidth`,`children`,`class`,`name`,`iconNode`,`absoluteStrokeWidth`]);return(()=>{var e=Rn();return $e(e,A(In,{get width(){return t.size??In.width},get height(){return t.size??In.height},get stroke(){return t.color??In.stroke},get"stroke-width"(){return q(()=>!!t.absoluteStrokeWidth)()?Number(t.strokeWidth??In[`stroke-width`])*24/Number(t.size):Number(t.strokeWidth??In[`stroke-width`])},get class(){return Bn(`lucide`,`lucide-icon`,t.name==null?void 0:`lucide-${zn(t?.name)}`,t.class==null?``:t.class)}},n),!0,!0),G(e,k(j,{get each(){return t.iconNode},children:([e,t])=>k(mt,A({component:e},t))})),e})()},Z=Vn})),Hn,Un,Wn,Gn=t((()=>{J(),Q(),Hn=[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]],Un=e=>k(Z,A(e,{name:`Activity`,iconNode:Hn})),Wn=Un})),Kn,qn,Jn,Yn=t((()=>{J(),Q(),Kn=[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]],qn=e=>k(Z,A(e,{name:`ArrowLeft`,iconNode:Kn})),Jn=qn})),Xn,Zn,Qn,$n=t((()=>{J(),Q(),Xn=[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]],Zn=e=>k(Z,A(e,{name:`BookOpen`,iconNode:Xn})),Qn=Zn})),er,tr,nr,rr=t((()=>{J(),Q(),er=[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]],tr=e=>k(Z,A(e,{name:`ChevronRight`,iconNode:er})),nr=tr})),ir,ar,or,sr=t((()=>{J(),Q(),ir=[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]],ar=e=>k(Z,A(e,{name:`CircleCheckBig`,iconNode:ir})),or=ar})),cr,lr,ur,dr=t((()=>{J(),Q(),cr=[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]],lr=e=>k(Z,A(e,{name:`CircleDashed`,iconNode:cr})),ur=lr})),fr,pr,mr,hr=t((()=>{J(),Q(),fr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]],pr=e=>k(Z,A(e,{name:`CircleX`,iconNode:fr})),mr=pr})),gr,_r,vr,yr=t((()=>{J(),Q(),gr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]],_r=e=>k(Z,A(e,{name:`Clock`,iconNode:gr})),vr=_r})),br,xr,Sr,Cr=t((()=>{J(),Q(),br=[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]],xr=e=>k(Z,A(e,{name:`CodeXml`,iconNode:br})),Sr=xr})),wr,Tr,Er,Dr=t((()=>{J(),Q(),wr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M9 15h6`,key:`cctwl0`}],[`path`,{d:`M12 18v-6`,key:`17g6i2`}]],Tr=e=>k(Z,A(e,{name:`FilePlus`,iconNode:wr})),Er=Tr})),Or,kr,Ar,jr=t((()=>{J(),Q(),Or=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]],kr=e=>k(Z,A(e,{name:`FileText`,iconNode:Or})),Ar=kr})),Mr,Nr,Pr,Fr=t((()=>{J(),Q(),Mr=[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]],Nr=e=>k(Z,A(e,{name:`FolderOpen`,iconNode:Mr})),Pr=Nr})),Ir,Lr,Rr,zr=t((()=>{J(),Q(),Ir=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]],Lr=e=>k(Z,A(e,{name:`Globe`,iconNode:Ir})),Rr=Lr})),Br,Vr,Hr,Ur=t((()=>{J(),Q(),Br=[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]],Vr=e=>k(Z,A(e,{name:`Image`,iconNode:Br})),Hr=Vr})),Wr,Gr,Kr,qr=t((()=>{J(),Q(),Wr=[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]],Gr=e=>k(Z,A(e,{name:`Languages`,iconNode:Wr})),Kr=Gr})),Jr,Yr,Xr,Zr=t((()=>{J(),Q(),Jr=[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]],Yr=e=>k(Z,A(e,{name:`Layers`,iconNode:Jr})),Xr=Yr})),Qr,$r,ei,ti=t((()=>{J(),Q(),Qr=[[`rect`,{width:`7`,height:`9`,x:`3`,y:`3`,rx:`1`,key:`10lvy0`}],[`rect`,{width:`7`,height:`5`,x:`14`,y:`3`,rx:`1`,key:`16une8`}],[`rect`,{width:`7`,height:`9`,x:`14`,y:`12`,rx:`1`,key:`1hutg5`}],[`rect`,{width:`7`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`ldoo1y`}]],$r=e=>k(Z,A(e,{name:`LayoutDashboard`,iconNode:Qr})),ei=$r})),ni,ri,ii,ai=t((()=>{J(),Q(),ni=[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]],ri=e=>k(Z,A(e,{name:`Plus`,iconNode:ni})),ii=ri})),oi,si,ci,li=t((()=>{J(),Q(),oi=[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]],si=e=>k(Z,A(e,{name:`RefreshCw`,iconNode:oi})),ci=si})),ui,di,fi,pi=t((()=>{J(),Q(),ui=[[`path`,{d:`M3 7V5a2 2 0 0 1 2-2h2`,key:`aa7l1z`}],[`path`,{d:`M17 3h2a2 2 0 0 1 2 2v2`,key:`4qcy5o`}],[`path`,{d:`M21 17v2a2 2 0 0 1-2 2h-2`,key:`6vwrx8`}],[`path`,{d:`M7 21H5a2 2 0 0 1-2-2v-2`,key:`ioqczr`}],[`path`,{d:`M7 8h8`,key:`1jbsf9`}],[`path`,{d:`M7 12h10`,key:`b7w52i`}],[`path`,{d:`M7 16h6`,key:`1vyc9m`}]],di=e=>k(Z,A(e,{name:`ScanText`,iconNode:ui})),fi=di})),mi,hi,gi,_i=t((()=>{J(),Q(),mi=[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]],hi=e=>k(Z,A(e,{name:`ShieldAlert`,iconNode:mi})),gi=hi})),vi,yi,bi,xi=t((()=>{J(),Q(),vi=[[`path`,{d:`M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z`,key:`4pj2yx`}],[`path`,{d:`M20 3v4`,key:`1olli1`}],[`path`,{d:`M22 5h-4`,key:`1gvqau`}],[`path`,{d:`M4 17v2`,key:`vumght`}],[`path`,{d:`M5 18H3`,key:`zchphs`}]],yi=e=>k(Z,A(e,{name:`Sparkles`,iconNode:vi})),bi=yi})),Si=t((()=>{Gn(),Yn(),$n(),rr(),dr(),yr(),Dr(),jr(),Fr(),zr(),Ur(),qr(),Zr(),ti(),ai(),li(),pi(),_i(),xi()})),Ci=t((()=>{sr()})),wi=t((()=>{hr()})),Ti=t((()=>{Cr()})),Ei=t((()=>{Ci(),wi(),Ti()})),Di=t((()=>{})),Oi=t((()=>{})),ki=t((()=>{Ei(),Di(),Oi()})),Ai=t((()=>{})),$=t((()=>{Si(),ki(),Ai()}));J(),Fn(),$();var ji=U(`<div class="flex h-screen bg-slate-50 text-slate-800"><nav class="group flex w-14 flex-col gap-1 overflow-hidden bg-slate-900 px-2 py-4 transition-all duration-200 hover:w-48"><div class="mb-4 flex items-center gap-3 px-1"><span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-violet-600 text-xs font-bold text-white">W</span><span class="whitespace-nowrap text-sm font-semibold text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100">WebOCR</span></div></nav><main class="flex-1 overflow-y-auto">`),Mi=U(`<span class="flex h-8 w-8 shrink-0 items-center justify-center">`),Ni=U(`<span class="whitespace-nowrap text-sm opacity-0 transition-opacity duration-200 group-hover:opacity-100">`),Pi=[{href:`/`,label:`Dashboard`,Icon:ei},{href:`/jobs`,label:`Jobs`,Icon:Hr},{href:`/library`,label:`Library`,Icon:Qn}];function Fi(e){return(()=>{var t=ji(),n=t.firstChild;n.firstChild;var r=n.nextSibling;return G(n,()=>Pi.map(e=>k(jn,{get href(){return e.href},get end(){return e.href===`/`},class:`flex items-center gap-3 rounded-lg px-1 py-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-white`,activeClass:`bg-slate-800 !text-white`,get children(){return[(()=>{var t=Mi();return G(t,k(e.Icon,{class:`h-5 w-5`})),t})(),(()=>{var t=Ni();return G(t,()=>e.label),t})()]}})),null),G(r,()=>e.children),t})()}J(),H(),$();var Ii=U(`<span class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700">`),Li=U(`<span class="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-500">`),Ri=U(`<span class="inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-xs text-red-600">`),zi=U(`<div class="min-h-screen bg-slate-50 px-4 py-10"><div class="mx-auto max-w-2xl space-y-8"><div class="flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div><h1 class="text-xl font-semibold text-slate-800">Web OCR Server</h1><p class="text-sm text-slate-500">ASP.NET Core · Manga-OCR · Opus-MT</p></div><div class=ml-auto></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">Server info</span></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">API Endpoints</span></div><ul class="divide-y divide-slate-50">`),Bi=U(`<div class="flex items-center gap-2 px-5 py-4 text-sm text-red-600">`),Vi=U(`<div class="px-5 py-4 text-sm text-slate-400">Loading…`),Hi=U(`<dl class="divide-y divide-slate-50 text-sm"><div class="flex items-center gap-3 px-5 py-3"><dt class="w-36 shrink-0 text-slate-500">Version</dt><dd class="font-medium text-slate-800"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> OCR models</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> Translate</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-center gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> DeepL</dt><dd>`),Ui=U(`<li class="flex items-center gap-4 px-5 py-3.5 text-sm"><span></span><code class="w-28 shrink-0 text-slate-700"></code><span></span><span class=text-slate-500>`);function Wi(e){return k(M,{get when(){return e.ok!==null},get fallback(){return(()=>{var t=Li();return G(t,k(ur,{class:`h-3 w-3 animate-spin`}),null),G(t,()=>e.label,null),t})()},get children(){return k(M,{get when(){return e.ok},get fallback(){return(()=>{var t=Ri();return G(t,k(mr,{class:`h-3 w-3`}),null),G(t,()=>e.label,null),t})()},get children(){var t=Ii();return G(t,k(or,{class:`h-3 w-3`}),null),G(t,()=>e.label,null),t}})}})}var Gi=[{method:`GET`,path:`/health`,desc:`Server status, version, model paths`,Icon:Wn,color:`text-sky-600`},{method:`POST`,path:`/ocr`,desc:`Base64 image → Japanese text`,Icon:fi,color:`text-violet-600`},{method:`POST`,path:`/translate`,desc:`Japanese → English (local Opus-MT or DeepL)`,Icon:Kr,color:`text-amber-600`},{method:`POST`,path:`/analyze`,desc:`Tokenise text + dictionary lookup`,Icon:Qn,color:`text-emerald-600`}],Ki={GET:`bg-sky-50 text-sky-700`,POST:`bg-violet-50 text-violet-700`};function qi(){let[e,t]=s(null),[n,r]=s(null);_(()=>{fetch(`/health`).then(e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);return e.json()}).then(t).catch(e=>r(String(e)))});let i=()=>{if(n())return!1;let t=e();return t?t.status===`ok`:null},a=()=>{if(n())return`error`;let t=e();return t?t.status:`connecting`};return(()=>{var t=zi(),r=t.firstChild.firstChild,o=r.firstChild,s=o.nextSibling.nextSibling,c=r.nextSibling;c.firstChild;var u=c.nextSibling.firstChild.nextSibling;return G(o,k(Sr,{class:`h-6 w-6 text-slate-700`})),G(s,k(Wi,{get ok(){return i()},get label(){return a()}})),G(c,k(M,{get when(){return!n()},get fallback(){return(()=>{var e=Bi();return G(e,k(gi,{class:`h-4 w-4 shrink-0`}),null),G(e,n,null),e})()},get children(){return k(M,{get when(){return e()},get fallback(){return Vi()},children:e=>(()=>{var t=Hi(),n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild,o=a.firstChild,s=a.nextSibling,c=i.nextSibling,l=c.firstChild,u=l.firstChild,d=l.nextSibling,f=c.nextSibling.firstChild,p=f.firstChild,m=f.nextSibling;return G(r,()=>e().version),G(a,k(Pr,{class:`h-3.5 w-3.5`}),o),G(s,()=>e().ocr_models_dir),G(l,k(Pr,{class:`h-3.5 w-3.5`}),u),G(d,()=>e().translate_models_dir),G(f,k(Rr,{class:`h-3.5 w-3.5`}),p),G(m,k(Wi,{get ok(){return e().deepl_available},get label(){return e().deepl_available?`configured`:`not configured`}})),t})()})}}),null),G(u,k(j,{each:Gi,children:({method:e,path:t,desc:n,Icon:r,color:i})=>(()=>{var a=Ui(),o=a.firstChild,s=o.nextSibling,c=s.nextSibling,u=c.nextSibling;return G(o,e),G(s,t),Ye(c,`shrink-0 ${i}`),G(c,k(r,{class:`h-4 w-4`})),G(u,n),l(()=>Ye(o,`w-12 shrink-0 rounded px-1.5 py-0.5 text-center text-xs font-semibold ${Ki[e]??``}`)),a})()})),t})()}function Ji(e){return e.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function Yi(e){if(Array.isArray(e))return e.map(Yi);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Ji(n)]=Yi(r);return t}return e}async function Xi(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`,...t?.headers},...t});if(!n.ok){let e=await n.text().catch(()=>n.statusText);throw Error(`API ${n.status}: ${e}`)}if(n.status!==204)return Yi(await n.json())}function Zi(e={}){let t=new URLSearchParams;e.page!==void 0&&t.set(`page`,String(e.page)),e.pageSize!==void 0&&t.set(`page_size`,String(e.pageSize)),e.status&&t.set(`status`,e.status),e.chapterId!==void 0&&t.set(`chapter_id`,String(e.chapterId));let n=t.toString();return Xi(`/api/portal/jobs${n?`?${n}`:``}`)}function Qi(e){return Xi(`/api/portal/jobs/${e}`)}function $i(){return Xi(`/api/portal/volumes`)}function ea(e={}){let t=new URLSearchParams;e.volumeId!==void 0&&t.set(`volume_id`,String(e.volumeId));let n=t.toString();return Xi(`/api/portal/chapters${n?`?${n}`:``}`)}function ta(e){return Xi(`/api/portal/chapters/${e}/jobs`)}function na(e){return`/api/portal/jobs/${e}/original`}function ra(e){return`/api/portal/jobs/${e}/result`}var ia=t((()=>{})),aa=n({JobsListPage:()=>ca});function oa(e){let t=()=>{switch(e.status){case`done`:return{cls:`bg-green-100 text-green-700`,Icon:or,label:`Done`};case`processing`:return{cls:`bg-yellow-100 text-yellow-700`,Icon:vr,label:`Processing`};case`error`:return{cls:`bg-red-100 text-red-700`,Icon:mr,label:`Error`}}};return(()=>{var e=la();return G(e,()=>{let e=t().Icon;return k(e,{class:`h-3 w-3`})},null),G(e,()=>t().label,null),l(()=>Ye(e,`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${t().cls}`)),e})()}function sa(e){let t=()=>e.job.resultImagePath?ra(e.job.id):na(e.job.id);return(()=>{var n=ua(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling.firstChild,s=o.nextSibling.firstChild,c=s.firstChild,u=s.nextSibling;return Xe(n,`click`,e.onClick,!0),G(a,k(oa,{get status(){return e.job.status}})),G(o,()=>e.job.title),G(s,k(Xr,{class:`h-3 w-3`}),c),G(s,()=>e.job.bubbleCount,c),G(u,()=>new Date(e.job.createdAt).toLocaleDateString()),l(n=>{var r=t(),a=e.job.title;return r!==n.e&&W(i,`src`,n.e=r),a!==n.t&&W(i,`alt`,n.t=a),n},{e:void 0,t:void 0}),n})()}function ca(){let e=sn(),[t,n]=s(``),[r,i]=s(``),[a]=p(t,e=>Zi({pageSize:100,status:e||void 0})),o=()=>{let e=r().toLowerCase();return(a()?.items??[]).filter(t=>!e||t.title.toLowerCase().includes(e))};return(()=>{var s=pa(),c=s.firstChild,u=c.firstChild,d=c.nextSibling.firstChild,f=d.nextSibling;return G(u,k(Hr,{class:`h-5 w-5 text-violet-600`})),d.$$input=e=>i(e.currentTarget.value),f.addEventListener(`change`,e=>n(e.currentTarget.value)),G(f,()=>_a.map(e=>(()=>{var t=ma();return G(t,()=>e.label),l(()=>t.value=e.value),t})())),G(s,k(M,{get when(){return a.loading},get children(){var e=da();return G(e,()=>Array.from({length:10}).map(()=>ha())),e}}),null),G(s,k(M,{get when(){return a.error},get children(){var e=fa();return e.firstChild,G(e,()=>String(a.error),null),e}}),null),G(s,k(M,{get when(){return q(()=>!a.loading)()&&!a.error},get children(){return k(M,{get when(){return o().length>0},get fallback(){return(()=>{var e=ga(),t=e.firstChild;return G(e,k(Hr,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var t=da();return G(t,k(j,{get each(){return o()},children:t=>k(sa,{job:t,onClick:()=>e(`/jobs/${t.id}`)})})),t}})}}),null),l(()=>d.value=r()),l(()=>f.value=t()),s})()}var la,ua,da,fa,pa,ma,ha,ga,_a,va=t((()=>{J(),H(),Fn(),$(),ia(),la=U(`<span>`),ua=U(`<button class="group flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-violet-500"><div class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><div class="absolute right-2 top-2"></div></div><div class="flex flex-col gap-1 p-3"><p class="truncate text-sm font-medium text-slate-800"></p><div class="flex items-center gap-3 text-xs text-slate-500"><span class="flex items-center gap-1"> bubbles</span><span class=ml-auto>`,!0,!1,!1),da=U(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),fa=U(`<div class="rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load jobs: `),pa=U(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Jobs</h1></div><div class="mb-6 flex flex-wrap gap-3"><input type=search placeholder="Search jobs…"class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-400"><select class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-400">`),ma=U(`<option>`),ha=U(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),ga=U(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No jobs yet.</p><p class="max-w-xs text-center text-xs text-slate-400">Upload pages via the extension or API to see translation jobs here.`),_a=[{value:``,label:`All statuses`},{value:`done`,label:`Done`},{value:`processing`,label:`Processing`},{value:`error`,label:`Error`}],Ke([`click`,`input`])})),ya=n({StudioPage:()=>xa});function ba(e){switch(e.status){case`done`:return(()=>{var e=Sa(),t=e.firstChild;return G(e,k(or,{class:`h-3 w-3`}),t),e})();case`processing`:return(()=>{var e=Ca(),t=e.firstChild;return G(e,k(vr,{class:`h-3 w-3`}),t),e})();case`error`:return(()=>{var e=wa(),t=e.firstChild;return G(e,k(mr,{class:`h-3 w-3`}),t),e})()}}function xa(){let e=ln(),[t]=p(()=>e.id,Qi);return(()=>{var e=Oa(),n=e.firstChild,r=n.firstChild,i=r.firstChild,a=i.firstChild,o=i.nextSibling,s=o.firstChild,c=o.nextSibling,l=c.firstChild;return G(n,k(M,{get when(){return t()},get fallback(){return ka()},children:e=>[(()=>{var t=Aa();return G(t,()=>e().title),t})(),k(ba,{get status(){return e().status}})]}),r),G(i,k(fi,{class:`h-3.5 w-3.5`}),a),G(o,k(bi,{class:`h-3.5 w-3.5`}),s),G(c,k(ci,{class:`h-3.5 w-3.5`}),l),G(e,k(M,{get when(){return t.loading},get children(){return Ta()}}),null),G(e,k(M,{get when(){return t.error},get children(){var e=Ea();return e.firstChild,G(e,()=>String(t.error),null),e}}),null),G(e,k(M,{get when(){return q(()=>!t.loading&&!t.error)()&&t()},get children(){return Da()}}),null),e})()}var Sa,Ca,wa,Ta,Ea,Da,Oa,ka,Aa,ja=t((()=>{J(),H(),Fn(),$(),ia(),Sa=U(`<span class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700"> Done`),Ca=U(`<span class="inline-flex items-center gap-1 rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-700"> Processing`),wa=U(`<span class="inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-700"> Error`),Ta=U(`<div class="flex flex-1 items-center justify-center"><p class="text-sm text-slate-400">Loading job…`),Ea=U(`<div class="m-6 rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load job: `),Da=U(`<div class="flex flex-1 overflow-hidden"><aside class="flex w-56 flex-col border-r border-slate-200 bg-white"><div class="border-b border-slate-100 px-4 py-2.5"><p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Bubbles</p></div><div class="flex flex-1 items-center justify-center text-xs text-slate-400">Bubble list coming soon</div></aside><div class="flex flex-1 flex-col items-center justify-center gap-3 bg-slate-100"><div class="rounded-2xl bg-white p-6 shadow-sm ring-1 ring-slate-200 text-sm text-slate-400">Canvas coming soon</div></div><aside class="flex w-64 flex-col border-l border-slate-200 bg-white"><div class="border-b border-slate-100 px-4 py-2.5"><p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Editor</p></div><div class="flex flex-1 items-center justify-center text-xs text-slate-400">Select a bubble to edit`),Oa=U(`<div class="flex h-screen flex-col"><header class="flex items-center gap-3 border-b border-slate-200 bg-white px-4 py-3 shadow-sm"><div class="ml-auto flex items-center gap-2"><button disabled class="flex cursor-not-allowed items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-400 opacity-60"title="Re-detect bubbles"> Re-detect</button><button disabled class="flex cursor-not-allowed items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-400 opacity-60"title=Re-translate> Re-translate</button><button disabled class="flex cursor-not-allowed items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-400 opacity-60"title=Re-render> Re-render`),ka=U(`<div class="h-5 w-48 animate-pulse rounded bg-slate-200">`),Aa=U(`<h1 class="truncate text-sm font-semibold text-slate-800">`)})),Ma=n({LibraryPage:()=>Na});function Na(){let e=sn(),[t]=p($i),[n]=p(()=>ea({volumeId:void 0})),r=()=>(n()??[]).filter(e=>!e.volumeId);return(()=>{var i=Ra(),a=i.firstChild,o=a.firstChild,s=o.nextSibling.nextSibling.firstChild,c=s.firstChild,l=s.nextSibling,u=l.firstChild,d=a.nextSibling;d.firstChild;var f=d.nextSibling;return f.firstChild,G(o,k(Qn,{class:`h-5 w-5 text-violet-600`})),G(s,k(ii,{class:`h-3.5 w-3.5`}),c),G(l,k(ii,{class:`h-3.5 w-3.5`}),u),G(d,k(M,{get when(){return t.loading},get children(){var e=Pa();return G(e,()=>Array.from({length:4}).map(()=>za())),e}}),null),G(d,k(M,{get when(){return t.error},get children(){return Fa()}}),null),G(d,k(M,{get when(){return q(()=>!t.loading)()&&!t.error},get children(){return k(M,{get when(){return(t()??[]).length>0},get fallback(){return(()=>{var e=Ba(),t=e.firstChild;return G(e,k(Pr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var n=Pa();return G(n,k(j,{get each(){return t()},children:t=>(()=>{var n=Va(),r=n.firstChild,i=r.nextSibling.firstChild,a=i.nextSibling,o=a.firstChild;return n.$$click=()=>e(`/library/${t.id}`),G(r,k(Qn,{class:`h-6 w-6 text-violet-500`})),G(i,()=>t.title),G(a,()=>t.chapterCount??0,o),G(n,k(nr,{class:`ml-auto h-4 w-4 shrink-0 text-slate-300 transition group-hover:translate-x-0.5 group-hover:text-slate-500`}),null),n})()})),n}})}}),null),G(f,k(M,{get when(){return n.loading},get children(){var e=Ia();return G(e,()=>Array.from({length:3}).map(()=>Ha())),e}}),null),G(f,k(M,{get when(){return!n.loading},get children(){return k(M,{get when(){return r().length>0},get fallback(){return Ua()},get children(){var t=La();return G(t,k(j,{get each(){return r()},children:t=>(()=>{var n=Wa(),r=n.firstChild,i=r.firstChild;i.firstChild;var a=i.nextSibling,o=a.nextSibling,s=o.firstChild;return r.$$click=()=>e(`/library/chapters/${t.id}`),G(i,()=>t.chapterNumber,null),G(a,()=>t.title),G(o,()=>t.pageCount??0,s),G(r,k(nr,{class:`h-4 w-4 text-slate-300`}),null),n})()})),t}})}}),null),i})()}var Pa,Fa,Ia,La,Ra,za,Ba,Va,Ha,Ua,Wa,Ga=t((()=>{J(),H(),Fn(),$(),ia(),Pa=U(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">`),Fa=U(`<p class="text-sm text-red-500">Failed to load volumes.`),Ia=U(`<div class=space-y-2>`),La=U(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),Ra=U(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Library</h1><div class="ml-auto flex gap-2"><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> New Volume</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 hover:bg-slate-50"> New Chapter</button></div></div><section class=mb-10><h2 class="mb-3 text-sm font-semibold text-slate-600">Volumes</h2></section><section><h2 class="mb-3 text-sm font-semibold text-slate-600">Standalone Chapters`),za=U(`<div class="h-32 animate-pulse rounded-2xl bg-slate-200">`),Ba=U(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-16 text-slate-400"><p class=text-sm>No volumes yet.`),Va=U(`<button class="group flex flex-col gap-2 rounded-2xl bg-white p-4 text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-violet-50"></div><div class=min-w-0><p class="truncate text-sm font-semibold text-slate-800"></p><p class="text-xs text-slate-500"> chapters`),Ha=U(`<div class="h-12 animate-pulse rounded-xl bg-slate-200">`),Ua=U(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-12 text-slate-400"><p class=text-sm>No standalone chapters.`),Wa=U(`<li><button class="flex w-full items-center gap-4 px-5 py-3.5 text-left transition hover:bg-slate-50"><span class="w-14 shrink-0 text-right text-xs font-mono text-slate-400">#</span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages`),Ke([`click`])})),Ka=n({VolumePage:()=>qa});function qa(){let e=ln(),t=sn(),n=()=>Number(e.volumeId),[r]=p($i),i=()=>r()?.find(e=>e.id===n()),[a]=p(n,e=>ea({volumeId:e}));return(()=>{var e=Za(),n=e.firstChild,r=n.firstChild,o=n.nextSibling.firstChild,s=o.nextSibling,c=s.nextSibling,l=c.firstChild;return n.$$click=()=>t(`/library`),G(n,k(Jn,{class:`h-4 w-4`}),r),G(o,k(Qn,{class:`h-5 w-5 text-violet-600`})),G(s,k(M,{get when(){return i()},get fallback(){return Qa()},children:e=>[(()=>{var t=$a();return G(t,()=>e().title),t})(),k(M,{get when(){return e().synopsis},get children(){var t=eo();return G(t,()=>e().synopsis),t}})]})),G(c,k(ii,{class:`h-3.5 w-3.5`}),l),G(e,k(M,{get when(){return a.loading},get children(){var e=Ja();return G(e,()=>Array.from({length:4}).map(()=>to())),e}}),null),G(e,k(M,{get when(){return a.error},get children(){return Ya()}}),null),G(e,k(M,{get when(){return q(()=>!a.loading)()&&!a.error},get children(){return k(M,{get when(){return(a()??[]).length>0},get fallback(){return(()=>{var e=no(),t=e.firstChild;return G(e,k(Ar,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var e=Xa();return G(e,k(j,{get each(){return a()},children:e=>(()=>{var n=ro(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.firstChild;return r.$$click=()=>t(`/library/chapters/${e.id}`),G(i,()=>e.chapterNumber),G(a,()=>e.title),G(o,()=>e.pageCount??0,s),G(r,k(nr,{class:`h-4 w-4 text-slate-300`}),null),n})()})),e}})}}),null),e})()}var Ja,Ya,Xa,Za,Qa,$a,eo,to,no,ro,io=t((()=>{J(),H(),Fn(),$(),ia(),Ja=U(`<div class=space-y-2>`),Ya=U(`<p class="text-sm text-red-500">Failed to load chapters.`),Xa=U(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),Za=U(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"> Library</button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div></div><button class="ml-auto flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add Chapter`),Qa=U(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),$a=U(`<h1 class="text-xl font-semibold text-slate-800">`),eo=U(`<p class="text-sm text-slate-500">`),to=U(`<div class="h-14 animate-pulse rounded-xl bg-slate-200">`),no=U(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-20 text-slate-400"><p class=text-sm>No chapters yet. Add the first one.`),ro=U(`<li><button class="flex w-full items-center gap-4 px-5 py-4 text-left transition hover:bg-slate-50"><span class="w-16 shrink-0 rounded-lg bg-slate-100 px-2 py-1 text-center text-xs font-mono text-slate-600"></span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages`),Ke([`click`])})),ao=n({ChapterPage:()=>co});function oo(e){switch(e.status){case`done`:return k(or,{class:`h-4 w-4 text-green-500`});case`processing`:return k(vr,{class:`h-4 w-4 text-yellow-500`});case`error`:return k(mr,{class:`h-4 w-4 text-red-500`})}}function so(e){let t=()=>e.job.resultImagePath?ra(e.job.id):na(e.job.id);return(()=>{var n=lo(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling.firstChild;return Xe(n,`click`,e.onClick,!0),G(a,k(oo,{get status(){return e.job.status}})),G(o,()=>e.job.title),l(n=>{var r=t(),a=e.job.title;return r!==n.e&&W(i,`src`,n.e=r),a!==n.t&&W(i,`alt`,n.t=a),n},{e:void 0,t:void 0}),n})()}function co(){let e=ln(),t=sn(),n=()=>Number(e.chapterId),[r]=p(()=>ea()),i=()=>r()?.find(e=>e.id===n()),[a]=p(n,ta);return(()=>{var e=po(),n=e.firstChild,r=n.nextSibling.firstChild,o=r.nextSibling,s=o.nextSibling,c=s.firstChild;return n.$$click=()=>{let e=i();e?.volumeId?t(`/library/${e.volumeId}`):t(`/library`)},G(n,k(Jn,{class:`h-4 w-4`}),null),G(n,k(M,{get when(){return i()?.volumeId},fallback:`Library`,children:`Volume`}),null),G(r,k(Hr,{class:`h-5 w-5 text-violet-600`})),G(o,k(M,{get when(){return i()},get fallback(){return mo()},children:e=>(()=>{var t=ho(),n=t.firstChild.nextSibling;return n.nextSibling,G(t,()=>e().chapterNumber,n),G(t,()=>e().title,null),t})()})),G(s,k(Er,{class:`h-3.5 w-3.5`}),c),G(e,k(M,{get when(){return a.loading},get children(){var e=uo();return G(e,()=>Array.from({length:8}).map(()=>go())),e}}),null),G(e,k(M,{get when(){return a.error},get children(){return fo()}}),null),G(e,k(M,{get when(){return q(()=>!a.loading)()&&!a.error},get children(){return k(M,{get when(){return(a()??[]).length>0},get fallback(){return(()=>{var e=_o(),t=e.firstChild;return G(e,k(Hr,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var e=uo();return G(e,k(j,{get each(){return a()},children:e=>k(so,{job:e,onClick:()=>t(`/jobs/${e.id}`)})})),e}})}}),null),e})()}var lo,uo,fo,po,mo,ho,go,_o,vo=t((()=>{J(),H(),Fn(),$(),ia(),lo=U(`<button class="group flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><span class="absolute left-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow"></span></div><div class=p-3><p class="truncate text-xs font-medium text-slate-700">`,!0,!1,!1),uo=U(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),fo=U(`<p class="text-sm text-red-500">Failed to load pages.`),po=U(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"></button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div></div><button disabled class="ml-auto flex cursor-not-allowed items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-400 opacity-60"> Add pages`),mo=U(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),ho=U(`<h1 class="text-xl font-semibold text-slate-800">Ch. <!> — `),go=U(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),_o=U(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No pages in this chapter yet.`),Ke([`click`])}));J(),H(),Fn();var yo=Se(()=>Promise.resolve().then(()=>(va(),aa)).then(e=>({default:e.JobsListPage}))),bo=Se(()=>Promise.resolve().then(()=>(ja(),ya)).then(e=>({default:e.StudioPage}))),xo=Se(()=>Promise.resolve().then(()=>(Ga(),Ma)).then(e=>({default:e.LibraryPage}))),So=Se(()=>Promise.resolve().then(()=>(io(),Ka)).then(e=>({default:e.VolumePage}))),Co=Se(()=>Promise.resolve().then(()=>(vo(),ao)).then(e=>({default:e.ChapterPage})));function wo(){return k(On,{get children(){return k(X,{path:`/`,component:e=>k(Fi,{get children(){return e.children}}),get children(){return[k(X,{path:`/`,component:qi}),k(X,{path:`/jobs`,component:yo}),k(X,{path:`/jobs/:id`,component:bo}),k(X,{path:`/library`,component:xo}),k(X,{path:`/library/:volumeId`,component:So}),k(X,{path:`/library/chapters/:chapterId`,component:Co})]}})}})}var To=new Map;window.AppBridge={mount(e,t={}){if(To.has(e))return;let n=Ge(()=>k(wo,{}),e);To.set(e,n)},unmount(e){To.get(e)?.(),To.delete(e)}}})(); No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Regenerate the committed portal bundle.

This served bundle still contains the placeholder Studio UI and disabled actions, and omits the new bubble editor and mutation API client. Since server/Components/App.razor loads /js/app.js directly at Line 16, production will not include the new portal functionality. Rebuild and commit the matching Vite outputs.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] Avoid assigning untrusted data to innerHTML/outerHTML or document.write
Context: t.innerHTML=e
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').

(inner-outer-html)

🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🪛 OpenGrep (1.25.0)

[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, The committed app.js bundle is stale and
lacks the new Studio bubble editor and mutation API client. Regenerate the
production Vite outputs from the current portal source, ensuring the bundle
loaded by App.razor contains the implemented Studio functionality and enabled
actions, then commit the updated generated assets.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (1)
server/src/Routes/PortalRoutes.cs (1)

214-266: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Retranslate never updates job.Status, unlike redetect/rerender.

Both redetect (Lines 173-212) and rerender (Lines 268-307) flip job.Status to "processing" before running and to "done"/"error" after, giving pollers a signal. retranslate's background task (Lines 225-263) never touches job.Status, and its catch (Line 262) only logs — a failed retranslation leaves the job silently stuck at its prior status with no ErrorMessage, misleading any caller checking job state.

🛠️ Proposed fix mirroring the redetect/rerender pattern
             var logger = loggerFactory.CreateLogger("PortalRetranslate");
             _ = Task.Run(async () =>
             {
+                using var scope = pipeline.CreateScope();
+                var db2 = scope.ServiceProvider.GetRequiredService<AppDbContext>();
                 try
                 {
+                    var j = await db2.PageTranslationJobs.FindAsync(id);
+                    if (j is not null) { j.Status = "processing"; await db2.SaveChangesAsync(); }
+
                     // Re-OCR + re-translate all non-excluded bubbles
                     var imagePng = await File.ReadAllBytesAsync(
                         Path.Combine(pipeline.GetJobDir(id), "original.png"));

-                    using var scope = pipeline.CreateScope();
-                    var db2 = scope.ServiceProvider.GetRequiredService<AppDbContext>();
                     var bubbles = db2.PageTranslationLogs
                         .Where(l => l.JobId == id && !l.IsExcluded)
                         .OrderBy(l => l.BubbleIndex)
                         .ToList();

                     foreach (var b in bubbles)
                     {
                         // ... unchanged ...
                     }

                     await db2.SaveChangesAsync();
+                    j = await db2.PageTranslationJobs.FindAsync(id);
+                    if (j is not null) { j.Status = "done"; await db2.SaveChangesAsync(); }
+                }
+                catch (Exception ex)
+                {
+                    logger.LogError(ex, "Retranslate failed for job {Id}", id);
+                    try
+                    {
+                        var j = await db2.PageTranslationJobs.FindAsync(id);
+                        if (j is not null) { j.Status = "error"; j.ErrorMessage = ex.Message; await db2.SaveChangesAsync(); }
+                    }
+                    catch { /* swallow */ }
                 }
-                catch (Exception ex) { logger.LogError(ex, "Retranslate failed for job {Id}", id); }
             });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/Routes/PortalRoutes.cs` around lines 214 - 266, Update the
retranslate handler around the background task to set the job status to
"processing" before starting work, then persist "done" after successful
completion and "error" plus the exception message in ErrorMessage when it fails.
Use the scoped database context consistently for these status updates, matching
the existing redetect and rerender status lifecycle while preserving the current
logging.
🧹 Nitpick comments (3)
docs/manga-page-translation.md (1)

9-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add languages to fenced Markdown blocks.

The six fences reported by markdownlint should specify languages such as text, json, or http to improve rendering and documentation validation.

Also applies to: 111-125, 129-150, 156-167, 175-201, 250-268

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/manga-page-translation.md` around lines 9 - 22, Add an appropriate
language identifier to every fenced Markdown block in
docs/manga-page-translation.md, including the blocks at the referenced sections;
use text for diagrams or prose, json for JSON examples, and http for HTTP
examples, while preserving their contents.

Source: Linters/SAST tools

docs/portal-plan.md (1)

23-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add languages to fenced Markdown blocks.

Specify appropriate fence languages (text or http) for the nine blocks reported by markdownlint.

Also applies to: 59-63, 67-73, 100-108, 112-117, 121-125, 129-142, 157-164, 179-187

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/portal-plan.md` around lines 23 - 54, Add an appropriate language
identifier to the opening fence of each of the nine Markdown code blocks in
docs/portal-plan.md, using text for schema or plain-text examples and http for
HTTP request/response examples. Update all blocks referenced by the review,
including the block containing Volume, Chapter, and PageTranslationJob, without
changing their contents.

Source: Linters/SAST tools

server/ClientApp/src/pages/StudioPage.tsx (1)

183-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Icon-only buttons rely solely on title for an accessible name.

title isn't reliably exposed to assistive tech. Consider adding aria-label matching the existing title text on the back button and the three action buttons.

♿ Example fix
         <button
           onClick={() => navigate("/jobs")}
           class="flex items-center gap-1 rounded p-1 text-slate-500 hover:bg-slate-100 transition-colors"
           title="Back to jobs"
+          aria-label="Back to jobs"
         >

Also applies to: 232-266

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/ClientApp/src/pages/StudioPage.tsx` around lines 183 - 189, Add an
aria-label matching each existing title to the icon-only back button and the
three action buttons in the StudioPage component, including the button near
navigate("/jobs") and the controls in the corresponding action-button section.
Preserve the existing titles and button behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/manga-page-translation.md`:
- Around line 15-18: Update the detector architecture references in the overview
and detailed section of the document to use the same authoritative model name,
replacing the inconsistent YOLOv8 reference with the documented RT-DETR-v2-S
model. Ensure the model-selection and input/output validation descriptions
remain aligned with that single detector.
- Line 21: Update the overview and Phase 4 in the documentation to describe the
existing job transport endpoints, including the `/events` SSE stream and
job-status endpoint, rather than presenting polling or SSE as future work.
Clearly distinguish the transient in-memory `TranslationJobStore`, logs, and
five-minute TTL from persisted portal state in `PageTranslationJobs`, including
bubble logs and the result path.

In `@server/src/Routes/PortalRoutes.cs`:
- Around line 346-353: Update the delete handlers for /volumes/{id} and
/chapters/{id} to account for existing child rows before removing the parent.
Either reject or guard deletion when dependents exist, or explicitly load and
clear the related children before SaveChangesAsync, ensuring FK constraints are
not violated; anchor the changes to the MapDelete handlers and their
Volume/Chapter removal logic.

In `@server/wwwroot/js/app.js`:
- Line 1: Update the side-by-side result-pane rendering in the relevant
page/component branch so `/result` is mounted only when a result image exists.
For processing or failed jobs without an image, reuse the existing placeholder
rendering used by result-only mode instead of creating a broken image.
- Line 1: Update the BubbleEditor confidence display so manually added bubbles
render the documented “N/A” instead of calculating a percentage from confidence.
Preserve the rounded percentage output for automatically detected bubbles, using
the existing manual-bubble indicator and BubbleEditor logic to select the
display.
- Line 1: Update the chapter card markup generated by the ChapterPage component
so the outer card is a non-interactive wrapper rather than a button. Keep the
move-up, move-down, and remove controls as sibling buttons within that wrapper,
preserving their existing handlers, disabled states, and styling while ensuring
no button is nested inside another button.
- Line 1: Connect StudioPage’s onAddBubble callback to the existing draw-mode or
bubble-creation flow used by the Studio controls, so the add-bubble button
performs the advertised action instead of invoking an empty function. Update the
StudioPage wiring and preserve the button only if it is now functional;
otherwise remove the dead control.
- Line 1: Update the Studio re-detect, re-translate, and re-render action
handlers to consume the returned 202 job ID and poll or otherwise await that
job’s completion before refreshing editor data and re-enabling the action
buttons. Keep controls disabled throughout the background operation and prevent
overlapping mutations; apply the same completion flow to each handler rather
than refreshing immediately after submission.

---

Duplicate comments:
In `@server/src/Routes/PortalRoutes.cs`:
- Around line 214-266: Update the retranslate handler around the background task
to set the job status to "processing" before starting work, then persist "done"
after successful completion and "error" plus the exception message in
ErrorMessage when it fails. Use the scoped database context consistently for
these status updates, matching the existing redetect and rerender status
lifecycle while preserving the current logging.

---

Nitpick comments:
In `@docs/manga-page-translation.md`:
- Around line 9-22: Add an appropriate language identifier to every fenced
Markdown block in docs/manga-page-translation.md, including the blocks at the
referenced sections; use text for diagrams or prose, json for JSON examples, and
http for HTTP examples, while preserving their contents.

In `@docs/portal-plan.md`:
- Around line 23-54: Add an appropriate language identifier to the opening fence
of each of the nine Markdown code blocks in docs/portal-plan.md, using text for
schema or plain-text examples and http for HTTP request/response examples.
Update all blocks referenced by the review, including the block containing
Volume, Chapter, and PageTranslationJob, without changing their contents.

In `@server/ClientApp/src/pages/StudioPage.tsx`:
- Around line 183-189: Add an aria-label matching each existing title to the
icon-only back button and the three action buttons in the StudioPage component,
including the button near navigate("/jobs") and the controls in the
corresponding action-button section. Preserve the existing titles and button
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b2e65ce9-9d3f-494f-b566-edf9d03e9b04

📥 Commits

Reviewing files that changed from the base of the PR and between b838ea1 and 5c34e15.

📒 Files selected for processing (50)
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
🚧 Files skipped from review as they are similar to previous changes (41)
  • extension/src/popup.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/ClientApp/src/components/Modal.tsx
  • extension/static/popup.html
  • extension/static/manifest.json
  • extension/static/popup.css
  • server/ClientApp/src/types.ts
  • server/src/Config.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • extension/static/content.css
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/src/Routes/AnalyzeRoutes.cs
  • server/Program.cs
  • server/src/Routes/HealthRoutes.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/src/Services/TypesettingService.cs
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/src/Data/AppDbContext.cs
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/server-csharp.csproj
  • extension/build.ts
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/TranslatePage.cs
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/package.json
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/src/Jobs/TranslationJobStore.cs
  • extension/src/types.ts
  • extension/src/background.ts
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/ClientApp/src/api.ts
  • server/src/BootExtensions.cs
  • extension/src/content.ts

Comment thread docs/manga-page-translation.md Outdated
Comment thread docs/manga-page-translation.md
Comment thread server/src/Routes/PortalRoutes.cs
Comment thread server/wwwroot/js/app.js Outdated
@@ -0,0 +1 @@
(function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};function r(e){let t=String(e),n=t.length-1;return R.context.id+(n?String.fromCharCode(96+n):``)+t}function i(e){R.context=e}function a(){return{...R.context,id:R.getNextContextId(),count:0}}function o(e,t){let n=H,r=B,i=e.length===0,a=t===void 0?r:t,o=i?ke:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(()=>h(()=>N(o)));B=o,H=null;try{return A(s,!0)}finally{H=n,B=r}}function s(e,t){t=t?Object.assign({},Te,t):Te;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[ee.bind(n),e=>(typeof e==`function`&&(e=V&&V.running&&V.sources.has(n)?e(n.tValue):e(n.value)),T(n,e))]}function c(e,t,n){let r=O(e,t,!0,z);je&&V&&V.running?U.push(r):E(r)}function l(e,t,n){let r=O(e,t,!1,z);je&&V&&V.running?U.push(r):E(r)}function u(e,t,n){De=ne;let r=O(e,t,!1,z),i=Ie&&C(Ie);i&&(r.suspense=i),(!n||!n.render)&&(r.user=!0),W?W.push(r):E(r)}function d(e,t,n){n=n?Object.assign({},Te,n):Te;let r=O(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,je&&V&&V.running?(r.tState=z,U.push(r)):E(r),ee.bind(r)}function f(e){return e&&typeof e==`object`&&`then`in e}function p(e,t,n){let r,i,a;typeof t==`function`?(r=e,i=t,a=n||{}):(r=!0,i=e,a=t||{});let o=null,l=Ae,u=null,p=!1,m=!1,g=`initialValue`in a,_=typeof r==`function`&&d(r),v=new Set,[y,x]=(a.storage||s)(a.initialValue),[S,w]=s(void 0),[ee,T]=s(void 0,{equals:!1}),[E,D]=s(g?`ready`:`unresolved`);R.context&&(u=R.getNextContextId(),a.ssrLoadFrom===`initial`?l=a.initialValue:R.load&&R.has(u)&&(l=R.load(u)));function O(e,t,n,r){return o===e&&(o=null,r!==void 0&&(g=!0),(e===l||t===l)&&a.onHydrated&&queueMicrotask(()=>a.onHydrated(r,{value:t})),l=Ae,V&&e&&p?(V.promises.delete(e),p=!1,A(()=>{V.running=!0,k(t,n)},!1)):k(t,n)),t}function k(e,t){A(()=>{t===void 0&&x(()=>e),D(t===void 0?g?`ready`:`unresolved`:`errored`),w(t);for(let e of v.keys())e.decrement();v.clear()},!1)}function j(){let e=Ie&&C(Ie),t=y(),n=S();if(n!==void 0&&!o)throw n;return H&&!H.user&&e&&c(()=>{ee(),o&&(e.resolved&&V&&p?V.promises.add(o):v.has(e)||(e.increment(),v.add(e)))}),t}function te(e=!0){if(e!==!1&&m)return;m=!1;let t=_?_():r;if(p=V&&V.running,t==null||t===!1){O(o,h(y));return}V&&o&&V.promises.delete(o);let n,a=l===Ae?h(()=>{try{return i(t,{value:y(),refetching:e})}catch(e){n=e}}):l;if(n!==void 0){O(o,void 0,oe(n),t);return}else if(!f(a))return O(o,a,void 0,t),a;return o=a,`v`in a?(a.s===1?O(o,a.v,void 0,t):O(o,void 0,oe(a.v),t),a):(m=!0,queueMicrotask(()=>m=!1),A(()=>{D(g?`refreshing`:`pending`),T()},!1),a.then(e=>O(a,e,void 0,t),e=>O(a,void 0,oe(e),t)))}Object.defineProperties(j,{state:{get:()=>E()},error:{get:()=>S()},loading:{get(){let e=E();return e===`pending`||e===`refreshing`}},latest:{get(){if(!g)return j();let e=S();if(e&&!o)throw e;return y()}}});let M=B;return _?c(()=>(M=B,te(!1))):te(!1),[j,{refetch:e=>b(M,()=>te(e)),mutate:x}]}function m(e){return A(e,!1)}function h(e){if(!Me&&H===null)return e();let t=H;H=null;try{return Me?Me.untrack(e):e()}finally{H=t}}function g(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=h(()=>t(o,i,n));return i=o,s}}function _(e){u(()=>h(e))}function v(e){return B===null||(B.cleanups===null?B.cleanups=[e]:B.cleanups.push(e)),e}function y(){return B}function b(e,t){let n=B,r=H;B=e,H=null;try{return A(t,!0)}catch(e){ce(e)}finally{B=n,H=r}}function x(e){if(V&&V.running)return e(),V.done;let t=H,n=B;return Promise.resolve().then(()=>{H=t,B=n;let r;return(je||Ie)&&(r=V||={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0},r.done||=new Promise(e=>r.resolve=e),r.running=!0),A(e,!1),H=B=null,r?r.done:void 0})}function S(e,t){let n=Symbol(`context`);return{id:n,Provider:ue(n),defaultValue:e}}function C(e){let t;return B&&B.context&&(t=B.context[e.id])!==void 0?t:e.defaultValue}function w(e){let t=d(e),n=d(()=>le(t()));return n.toArray=()=>{let e=n();return Array.isArray(e)?e:e==null?[]:[e]},n}function ee(){let e=V&&V.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===z)E(this);else{let e=U;U=null,A(()=>re(this),!1),U=e}if(H){let e=this.observers;if(!e||e[e.length-1]!==H){let t=e?e.length:0;H.sources?(H.sources.push(this),H.sourceSlots.push(t)):(H.sources=[this],H.sourceSlots=[t]),e?(e.push(H),this.observerSlots.push(H.sources.length-1)):(this.observers=[H],this.observerSlots=[H.sources.length-1])}}return e&&V.sources.has(this)?this.tValue:this.value}function T(e,t,n){let r=V&&V.running&&V.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(V){let r=V.running;(r||!n&&V.sources.has(e))&&(V.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&A(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=V&&V.running;r&&V.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?U.push(n):W.push(n),n.observers&&ie(n)),r?n.tState=z:n.state=z)}if(U.length>1e6)throw U=[],Error()},!1)}return t}function E(e){if(!e.fn)return;N(e);let t=Ne;D(e,V&&V.running&&V.sources.has(e)?e.tValue:e.value,t),V&&!V.running&&V.sources.has(e)&&queueMicrotask(()=>{A(()=>{V&&(V.running=!0),H=B=e,D(e,e.tValue,t),H=B=null},!1)})}function D(e,t,n){let r,i=B,a=H;H=B=e;try{r=e.fn(t)}catch(t){return e.pure&&(V&&V.running?(e.tState=z,e.tOwned&&e.tOwned.forEach(N),e.tOwned=void 0):(e.state=z,e.owned&&e.owned.forEach(N),e.owned=null)),e.updatedAt=n+1,ce(t)}finally{H=a,B=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?T(e,r,!0):V&&V.running&&e.pure?(V.sources.has(e)||(e.value=r),V.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function O(e,t,n,r=z,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:B,context:B?B.context:null,pure:n};if(V&&V.running&&(a.state=0,a.tState=r),B===null||B!==ke&&(V&&V.running&&B.pure?B.tOwned?B.tOwned.push(a):B.tOwned=[a]:B.owned?B.owned.push(a):B.owned=[a]),Me&&a.fn){let e=a.fn,[t,n]=s(void 0,{equals:!1}),r=Me.factory(e,n);v(()=>r.dispose());let i,o=()=>x(n).then(()=>{i&&=(i.dispose(),void 0)});a.fn=n=>(t(),V&&V.running?(i||=Me.factory(e,o),i.track(n)):r.track(n))}return a}function k(e){let t=V&&V.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===Oe)return re(e);if(e.suspense&&h(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Ne);){if(t&&V.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(V.disposed.has(t))return}if((t?e.tState:e.state)===z)E(e);else if((t?e.tState:e.state)===Oe){let t=U;U=null,A(()=>re(e,n[0]),!1),U=t}}}function A(e,t){if(U)return e();let n=!1;t||(U=[]),W?n=!0:W=[],Ne++;try{let t=e();return j(n),t}catch(e){n||(W=null),U=null,ce(e)}}function j(e){if(U&&=(je&&V&&V.running?M(U):te(U),null),e)return;let t;if(V){if(!V.promises.size&&!V.queue.size){let e=V.sources,n=V.disposed;W.push.apply(W,V.effects),t=V.resolve;for(let e of W)`tState`in e&&(e.state=e.tState),delete e.tState;V=null,A(()=>{for(let e of n)N(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)N(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}Fe(!1)},!1)}else if(V.running){V.running=!1,V.effects.push.apply(V.effects,W),W=null,Fe(!0);return}}let n=W;W=null,n.length&&A(()=>De(n),!1),t&&t()}function te(e){for(let t=0;t<e.length;t++)k(e[t])}function M(e){for(let t=0;t<e.length;t++){let n=e[t],r=V.queue;r.has(n)||(r.add(n),je(()=>{r.delete(n),A(()=>{V.running=!0,k(n)},!1),V&&(V.running=!1)}))}}function ne(e){let t,n=0;for(t=0;t<e.length;t++){let r=e[t];r.user?e[n++]=r:k(r)}if(R.context){if(R.count){R.effects||=[],R.effects.push(...e.slice(0,n));return}i()}for(R.effects&&(R.done||!R.count)&&(e=[...R.effects,...e],n+=R.effects.length,delete R.effects),t=0;t<n;t++)k(e[t])}function re(e,t){let n=V&&V.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===z?i!==t&&(!i.updatedAt||i.updatedAt<Ne)&&k(i):e===Oe&&re(i,t)}}}function ie(e){let t=V&&V.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=Oe:r.state=Oe,r.pure?U.push(r):W.push(r),r.observers&&ie(r))}}function N(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)N(e.tOwned[t]);delete e.tOwned}if(V&&V.running&&e.pure)ae(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)N(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}V&&V.running?e.tState=0:e.state=0}function ae(e,t){if(t||(e.tState=0,V.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ae(e.owned[t])}function oe(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function se(e,t,n){try{for(let n of t)n(e)}catch(e){ce(e,n&&n.owner||null)}}function ce(e,t=B){let n=Ee&&t&&t.context&&t.context[Ee],r=oe(e);if(!n)throw r;W?W.push({fn(){se(r,n,t)},state:z}):se(r,n,t)}function le(e){if(typeof e==`function`&&!e.length)return le(e());if(Array.isArray(e)){let t=[];for(let n=0;n<e.length;n++){let r=le(e[n]);if(Array.isArray(r))if(r.length<32768)t.push.apply(t,r);else for(let e=0;e<r.length;e++)t.push(r[e]);else t.push(r)}return t}return e}function ue(e,t){return function(t){let n;return l(()=>n=h(()=>(B.context={...B.context,[e]:t.value},w(()=>t.children))),void 0),n}}function de(e){for(let t=0;t<e.length;t++)e[t]()}function fe(e,t,n={}){let r=[],i=[],a=[],c=0,l=t.length>1?[]:null;return v(()=>de(a)),()=>{let u=e()||[],d=u.length,f,p;return u[we],h(()=>{let e,t,s,h,g,_,v,y,b;if(d===0)c!==0&&(de(a),a=[],r=[],i=[],c=0,l&&=[]),n.fallback&&(r=[Le],i[0]=o(e=>(a[0]=e,n.fallback())),c=1);else if(c===0){for(i=Array(d),p=0;p<d;p++)r[p]=u[p],i[p]=o(m);c=d}else{for(s=Array(d),h=Array(d),l&&(g=Array(d)),_=0,v=Math.min(c,d);_<v&&r[_]===u[_];_++);for(v=c-1,y=d-1;v>=_&&y>=_&&r[v]===u[y];v--,y--)s[y]=i[v],h[y]=a[v],l&&(g[y]=l[v]);for(e=new Map,t=Array(y+1),p=y;p>=_;p--)b=u[p],f=e.get(b),t[p]=f===void 0?-1:f,e.set(b,p);for(f=_;f<=v;f++)b=r[f],p=e.get(b),p!==void 0&&p!==-1?(s[p]=i[f],h[p]=a[f],l&&(g[p]=l[f]),p=t[p],e.set(b,p)):a[f]();for(p=_;p<d;p++)p in s?(i[p]=s[p],a[p]=h[p],l&&(l[p]=g[p],l[p](p))):i[p]=o(m);i=i.slice(0,c=d),r=u.slice(0)}return i});function m(e){if(a[p]=e,l){let[e,n]=s(p);return l[p]=n,t(u[p],e)}return t(u[p])}}}function P(e,t){if(Re&&R.context){let n=R.context;i(a());let r=h(()=>e(t||{}));return i(n),r}return h(()=>e(t||{}))}function pe(){return!0}function me(e){return(e=typeof e==`function`?e():e)?e:{}}function he(){for(let e=0,t=this.length;e<t;++e){let t=this[e]();if(t!==void 0)return t}}function F(...e){let t=!1;for(let n=0;n<e.length;n++){let r=e[n];t||=!!r&&Se in r,e[n]=typeof r==`function`?(t=!0,d(r)):r}if(Ce&&t)return new Proxy({get(t){for(let n=e.length-1;n>=0;n--){let r=me(e[n])[t];if(r!==void 0)return r}},has(t){for(let n=e.length-1;n>=0;n--)if(t in me(e[n]))return!0;return!1},keys(){let t=[];for(let n=0;n<e.length;n++)t.push(...Object.keys(me(e[n])));return[...new Set(t)]}},ze);let n={},r=Object.create(null);for(let t=e.length-1;t>=0;t--){let i=e[t];if(!i)continue;let a=Object.getOwnPropertyNames(i);for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===`__proto__`||t===`constructor`)continue;let o=Object.getOwnPropertyDescriptor(i,t);if(!r[t])r[t]=o.get?{enumerable:!0,configurable:!0,get:he.bind(n[t]=[o.get.bind(i)])}:o.value===void 0?void 0:o;else{let e=n[t];e&&(o.get?e.push(o.get.bind(i)):o.value!==void 0&&e.push(()=>o.value))}}}let i={},a=Object.keys(r);for(let e=a.length-1;e>=0;e--){let t=a[e],n=r[t];n&&n.get?Object.defineProperty(i,t,n):i[t]=n?n.value:void 0}return i}function ge(e,...t){let n=t.length;if(Ce&&Se in e){let r=n>1?t.flat():t[0],i=t.map(t=>new Proxy({get(n){return t.includes(n)?e[n]:void 0},has(n){return t.includes(n)&&n in e},keys(){return t.filter(t=>t in e)}},ze));return i.push(new Proxy({get(t){return r.includes(t)?void 0:e[t]},has(t){return r.includes(t)?!1:t in e},keys(){return Object.keys(e).filter(e=>!r.includes(e))}},ze)),i}let r=[];for(let e=0;e<=n;e++)r[e]={};for(let i of Object.getOwnPropertyNames(e)){let a=n;for(let e=0;e<t.length;e++)if(t[e].includes(i)){a=e;break}let o=Object.getOwnPropertyDescriptor(e,i);!o.get&&!o.set&&o.enumerable&&o.writable&&o.configurable?r[a][i]=o.value:Object.defineProperty(r[a],i,o)}return r}function _e(e){let t,n,r=r=>{let a=R.context;if(a){let[r,o]=s();R.count||=0,R.count++,(n||=e()).then(e=>{!R.done&&i(a),R.count--,o(()=>e.default),i()}),t=r}else if(!t){let[r]=p(()=>(n||=e()).then(e=>e.default));t=r}let o;return d(()=>(o=t())?h(()=>{if(!a||R.done)return o(r);let e=R.context;i(a);let t=o(r);return i(e),t}):``)};return r.preload=()=>n||((n=e()).then(e=>t=()=>e.default),n),r}function I(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return d(fe(()=>e.each,e.children,t||void 0))}function L(e){let t=e.keyed,n=d(()=>e.when,void 0,void 0),r=t?n:d(n,void 0,{equals:(e,t)=>!e==!t});return d(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?h(()=>a(t?i:()=>{if(!h(r))throw Be(`Show`);return n()})):a}return e.fallback},void 0,void 0)}function ve(e){let t=w(()=>e.children),n=d(()=>{let e=t(),n=Array.isArray(e)?e:[e],r=()=>void 0;for(let e=0;e<n.length;e++){let t=e,i=n[e],a=r,o=d(()=>a()?void 0:i.when,void 0,void 0),s=i.keyed?o:d(o,void 0,{equals:(e,t)=>!e==!t});r=()=>a()||(s()?[t,o,i]:void 0)}return r});return d(()=>{let t=n()();if(!t)return e.fallback;let[r,i,a]=t,o=a.children;return typeof o==`function`&&o.length>0?h(()=>o(a.keyed?i():()=>{if(h(n)()?.[0]!==r)throw Be(`Match`);return i()})):o},void 0,void 0)}function ye(e){return e}function be(){Ve&&[...Ve].forEach(e=>e())}var R,xe,Se,Ce,we,Te,Ee,De,z,Oe,ke,Ae,B,V,je,Me,H,U,W,Ne,Pe,Fe,Ie,Le,Re,ze,Be,Ve,G=t((()=>{R={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return r(this.context.count)},getNextContextId(){return r(this.context.count++)}},xe=(e,t)=>e===t,Se=Symbol(`solid-proxy`),Ce=typeof Proxy==`function`,we=Symbol(`solid-track`),Te={equals:xe},Ee=null,De=te,z=1,Oe=2,ke={owned:null,cleanups:null,context:null,owner:null},Ae={},B=null,V=null,je=null,Me=null,H=null,U=null,W=null,Ne=0,[Pe,Fe]=s(!1),Le=Symbol(`fallback`),Re=!1,ze={get(e,t,n){return t===Se?n:e.get(t)},has(e,t){return t===Se?!0:e.has(t)},set:pe,deleteProperty:pe,getOwnPropertyDescriptor(e,t){return{configurable:!0,enumerable:!0,get(){return e.get(t)},set:pe,deleteProperty:pe}},ownKeys(e){return e.keys()}},Be=e=>`Stale read from <${e}>.`}));function He(e,t){let n=vt[e];return typeof n==`object`?n[t]?n.$:void 0:n}function Ue(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;){if(t[o]===n[s]){o++,s++;continue}for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)(!l||!l.has(t[o]))&&t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null)if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&!((d=l.get(t[c]))==null||d!==r+u);)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++;else t[o++].remove()}}}function We(e,t,n,r={}){let i;return o(r=>{i=r,t===document?e():Y(t,e(),t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function K(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>h(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function q(e,t=window.document){let n=t[Ct]||(t[Ct]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,ot))}}function J(e,t,n){nt(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function Ge(e,t,n,r){nt(e)||(r==null?e.removeAttributeNS(t,n):e.setAttributeNS(t,n,r))}function Ke(e,t,n){nt(e)||(n?e.setAttribute(t,``):e.removeAttribute(t))}function qe(e,t){nt(e)||(t==null?e.removeAttribute(`class`):e.className=t)}function Je(e,t,n,r){if(r)Array.isArray(n)?(e[`$$${t}`]=n[0],e[`$$${t}Data`]=n[1]):e[`$$${t}`]=n;else if(Array.isArray(n)){let r=n[0];e.addEventListener(t,n[0]=t=>r.call(e,n[1],t))}else e.addEventListener(t,n,typeof n!=`function`&&n)}function Ye(e,t,n={}){let r=Object.keys(t||{}),i=Object.keys(n),a,o;for(a=0,o=i.length;a<o;a++){let r=i[a];!r||r===`undefined`||t[r]||(it(e,r,!1),delete n[r])}for(a=0,o=r.length;a<o;a++){let i=r[a],o=!!t[i];!i||i===`undefined`||n[i]===o||!o||(it(e,i,!0),n[i]=o)}return n}function Xe(e,t,n){if(!t)return n?J(e,`style`):t;let r=e.style;if(typeof t==`string`)return r.cssText=t;typeof n==`string`&&(r.cssText=n=void 0),n||={},t||={};let i,a;for(a in n)t[a]??r.removeProperty(a),delete n[a];for(a in t)i=t[a],i!==n[a]&&(r.setProperty(a,i),n[a]=i);return n}function Ze(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function Qe(e,t={},n,r){let i={};return r||l(()=>i.children=st(e,t.children,i.children)),l(()=>typeof t.ref==`function`&&$e(t.ref,e)),l(()=>et(e,t,n,!0,i,!0)),i}function $e(e,t,n){return h(()=>e(t,n))}function Y(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return st(e,t,r,n);l(r=>st(e,t(),r,n),r)}function et(e,t,n,r,i={},a=!1){t||={};for(let r in i)if(!(r in t)){if(r===`children`)continue;i[r]=at(e,r,null,i[r],n,a,t)}for(let o in t){if(o===`children`){r||st(e,t.children);continue}let s=t[o];i[o]=at(e,o,s,i[o],n,a,t)}}function tt(e){let t,n;return!nt()||!(t=R.registry.get(n=dt()))?e():(R.completed&&R.completed.add(t),R.registry.delete(n),t)}function nt(e){return!!R.context&&!R.done&&(!e||e.isConnected)}function rt(e){return e.toLowerCase().replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function it(e,t,n){let r=t.trim().split(/\s+/);for(let t=0,i=r.length;t<i;t++)e.classList.toggle(r[t],n)}function at(e,t,n,r,i,a,o){let s,c,l,u,d;if(t===`style`)return Xe(e,n,r);if(t===`classList`)return Ye(e,n,r);if(n===r)return r;if(t===`ref`)a||n(e);else if(t.slice(0,3)===`on:`){let i=t.slice(3);r&&e.removeEventListener(i,r,typeof r!=`function`&&r),n&&e.addEventListener(i,n,typeof n!=`function`&&n)}else if(t.slice(0,10)===`oncapture:`){let i=t.slice(10);r&&e.removeEventListener(i,r,!0),n&&e.addEventListener(i,n,!0)}else if(t.slice(0,2)===`on`){let i=t.slice(2).toLowerCase(),a=yt.has(i);if(!a&&r){let t=Array.isArray(r)?r[0]:r;e.removeEventListener(i,t)}(a||n)&&(Je(e,i,n,a),a&&q([i]))}else if(t.slice(0,5)===`attr:`)J(e,t.slice(5),n);else if(t.slice(0,5)===`bool:`)Ke(e,t.slice(5),n);else if((d=t.slice(0,5)===`prop:`)||(l=gt.has(t))||!i&&((u=He(t,e.tagName))||(c=ht.has(t)))||(s=e.nodeName.includes(`-`)||`is`in o)){if(d)t=t.slice(5),c=!0;else if(nt(e))return n;t===`class`||t===`className`?qe(e,n):s&&!c&&!l?e[rt(t)]=n:e[u||t]=n}else{let r=i&&t.indexOf(`:`)>-1&&xt[t.split(`:`)[0]];r?Ge(e,r,t,n):J(e,_t[t]||t,n)}return n}function ot(e){if(R.registry&&R.events&&R.events.find(([t,n])=>n===e))return;let t=e.target,n=`$$${e.type}`,r=e.target,i=e.currentTarget,a=t=>Object.defineProperty(e,"target",{configurable:!0,value:t}),o=()=>{let r=t[n];if(r&&!t.disabled){let i=t[`${n}Data`];if(i===void 0?r.call(t,e):r.call(t,i,e),e.cancelBubble)return}return t.host&&typeof t.host!=`string`&&!t.host._$host&&t.contains(e.target)&&a(t.host),!0},s=()=>{for(;o()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),R.registry&&!R.done&&(R.done=_$HY.done=!0),e.composedPath){let n=e.composedPath();a(n[0]);for(let e=0;e<n.length-2&&(t=n[e],o());e++){if(t._$host){t=t._$host,s();break}if(t.parentNode===i)break}}else s();a(r)}function st(e,t,n,r,i){let a=nt(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=ut(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=ut(e,n,r)}else if(o===`function`)return l(()=>{let i=t();for(;typeof i==`function`;)i=i();n=st(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(ct(o,t,n,i))return l(()=>n=st(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=ut(e,n,r),s)return n}else c?n.length===0?lt(e,o,r):Ue(e,n,o):(n&&ut(e),lt(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=ut(e,n,r,t);ut(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function ct(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(!(o==null||o===!0||o===!1))if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=ct(e,o,s)||i;else if(c===`function`)if(r){for(;typeof o==`function`;)o=o();i=ct(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0;else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}return i}function lt(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function ut(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}function dt(){return R.getNextContextId()}function ft(e,t=!1,n=void 0){return t?document.createElementNS(wt,e):document.createElement(e,{is:n})}function pt(e,t){let n=d(e);return d(()=>{let e=n();switch(typeof e){case`function`:return h(()=>e(t));case`string`:let n=bt.has(e),r=R.context?tt():ft(e,n,h(()=>t.is));return Qe(r,t,n),r}})}function mt(e){let[,t]=ge(e,[`component`]);return pt(()=>e.component,t)}var ht,gt,_t,vt,yt,bt,xt,St,Ct,wt,X=t((()=>{G(),ht=new Set([`className`,`value`,`readOnly`,`noValidate`,`formNoValidate`,`isMap`,`noModule`,`playsInline`,`adAuctionHeaders`,`allowFullscreen`,`browsingTopics`,`defaultChecked`,`defaultMuted`,`defaultSelected`,`disablePictureInPicture`,`disableRemotePlayback`,`preservesPitch`,`shadowRootClonable`,`shadowRootCustomElementRegistry`,`shadowRootDelegatesFocus`,`shadowRootSerializable`,`sharedStorageWritable`,...`allowfullscreen.async.alpha.autofocus.autoplay.checked.controls.default.disabled.formnovalidate.hidden.indeterminate.inert.ismap.loop.multiple.muted.nomodule.novalidate.open.playsinline.readonly.required.reversed.seamless.selected.adauctionheaders.browsingtopics.credentialless.defaultchecked.defaultmuted.defaultselected.defer.disablepictureinpicture.disableremoteplayback.preservespitch.shadowrootclonable.shadowrootcustomelementregistry.shadowrootdelegatesfocus.shadowrootserializable.sharedstoragewritable`.split(`.`)]),gt=new Set([`innerHTML`,`textContent`,`innerText`,`children`]),_t=Object.assign(Object.create(null),{className:`class`,htmlFor:`for`}),vt=Object.assign(Object.create(null),{class:`className`,novalidate:{$:`noValidate`,FORM:1},formnovalidate:{$:`formNoValidate`,BUTTON:1,INPUT:1},ismap:{$:`isMap`,IMG:1},nomodule:{$:`noModule`,SCRIPT:1},playsinline:{$:`playsInline`,VIDEO:1},readonly:{$:`readOnly`,INPUT:1,TEXTAREA:1},adauctionheaders:{$:`adAuctionHeaders`,IFRAME:1},allowfullscreen:{$:`allowFullscreen`,IFRAME:1},browsingtopics:{$:`browsingTopics`,IMG:1},defaultchecked:{$:`defaultChecked`,INPUT:1},defaultmuted:{$:`defaultMuted`,AUDIO:1,VIDEO:1},defaultselected:{$:`defaultSelected`,OPTION:1},disablepictureinpicture:{$:`disablePictureInPicture`,VIDEO:1},disableremoteplayback:{$:`disableRemotePlayback`,AUDIO:1,VIDEO:1},preservespitch:{$:`preservesPitch`,AUDIO:1,VIDEO:1},shadowrootclonable:{$:`shadowRootClonable`,TEMPLATE:1},shadowrootdelegatesfocus:{$:`shadowRootDelegatesFocus`,TEMPLATE:1},shadowrootserializable:{$:`shadowRootSerializable`,TEMPLATE:1},sharedstoragewritable:{$:`sharedStorageWritable`,IFRAME:1,IMG:1}}),yt=new Set([`beforeinput`,`click`,`dblclick`,`contextmenu`,`focusin`,`focusout`,`input`,`keydown`,`keyup`,`mousedown`,`mousemove`,`mouseout`,`mouseover`,`mouseup`,`pointerdown`,`pointermove`,`pointerout`,`pointerover`,`pointerup`,`touchend`,`touchmove`,`touchstart`]),bt=new Set(`altGlyph.altGlyphDef.altGlyphItem.animate.animateColor.animateMotion.animateTransform.circle.clipPath.color-profile.cursor.defs.desc.ellipse.feBlend.feColorMatrix.feComponentTransfer.feComposite.feConvolveMatrix.feDiffuseLighting.feDisplacementMap.feDistantLight.feDropShadow.feFlood.feFuncA.feFuncB.feFuncG.feFuncR.feGaussianBlur.feImage.feMerge.feMergeNode.feMorphology.feOffset.fePointLight.feSpecularLighting.feSpotLight.feTile.feTurbulence.filter.font.font-face.font-face-format.font-face-name.font-face-src.font-face-uri.foreignObject.g.glyph.glyphRef.hkern.image.line.linearGradient.marker.mask.metadata.missing-glyph.mpath.path.pattern.polygon.polyline.radialGradient.rect.set.stop.svg.switch.symbol.text.textPath.tref.tspan.use.view.vkern`.split(`.`)),xt={xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`},St=e=>d(()=>e()),Ct=`_$DX_DELEGATE`,wt=`http://www.w3.org/2000/svg`}));X();function Tt(){let e=new Set;function t(t){return e.add(t),()=>e.delete(t)}let n=!1;function r(t,r){if(n)return!(n=!1);let i={to:t,options:r,defaultPrevented:!1,preventDefault:()=>i.defaultPrevented=!0};for(let a of e)a.listener({...i,from:a.location,retry:e=>{e&&(n=!0),a.navigate(t,{...r,resolve:!1})}});return!i.defaultPrevented}return{subscribe:t,confirm:r}}function Et(){(!window.history.state||window.history.state._depth==null)&&window.history.replaceState({...window.history.state,_depth:window.history.length-1},``),kt=window.history.state._depth}function Dt(e){return{...e,_depth:window.history.state&&window.history.state._depth}}function Ot(e,t){let n=!1;return()=>{let r=kt;Et();let i=r==null?null:kt-r;if(n){n=!1;return}i&&t(i)?(n=!0,window.history.go(-i)):e()}}var kt,At=t((()=>{Et()}));function jt(e,t=!1){let n=e.replace(Ht,`$1`);return n?t||/^[?#]/.test(n)?n:`/`+n:``}function Mt(e,t,n){if(Vt.test(t))return;let r=jt(e),i=n&&jt(n),a=``;return a=!i||t.startsWith(`/`)?r:i.toLowerCase().indexOf(r.toLowerCase())===0?i:r+i,(a||`/`)+jt(t,!a)}function Nt(e,t){if(e==null)throw Error(t);return e}function Pt(e,t){return jt(e).replace(/\/*(\*.*)?$/g,``)+jt(t)}function Ft(e){let t={};return e.searchParams.forEach((e,n)=>{n in t?Array.isArray(t[n])?t[n].push(e):t[n]=[t[n],e]:t[n]=e}),t}function It(e,t,n){let[r,i]=e.split(`/*`,2),a=r.split(`/`).filter(Boolean),o=a.length;return e=>{let r=e.split(`/`).filter(Boolean),s=r.length-o;if(s<0||s>0&&i===void 0&&!t)return null;let c={path:o?``:`/`,params:{}},l=e=>n===void 0?void 0:n[e];for(let e=0;e<o;e++){let t=a[e],n=t[0]===`:`,i=n?r[e]:r[e].toLowerCase(),o=n?t.slice(1):t.toLowerCase();if(n&&Lt(i,l(o)))c.params[o]=i;else if(n||!Lt(i,o))return null;c.path+=`/${i}`}if(i){let e=s?r.slice(-s).join(`/`):``;if(Lt(e,l(i)))c.params[i]=e;else return null}return c}}function Lt(e,t){let n=t=>t===e;return t===void 0?!0:typeof t==`string`?n(t):typeof t==`function`?t(e):Array.isArray(t)?t.some(n):t instanceof RegExp?t.test(e):!1}function Rt(e){let[t,n]=e.pattern.split(`/*`,2),r=t.split(`/`).filter(Boolean);return r.reduce((e,t)=>e+(t.startsWith(`:`)?2:3),r.length-(n===void 0?0:1))}function zt(e){let t=new Map,n=y();return new Proxy({},{get(r,i){return t.has(i)||b(n,()=>t.set(i,d(()=>e()[i]))),t.get(i)()},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}},ownKeys(){return Reflect.ownKeys(e())},has(t,n){return n in e()}})}function Bt(e){let t=/(\/?\:[^\/]+)\?/.exec(e);if(!t)return[e];let n=e.slice(0,t.index),r=e.slice(t.index+t[0].length),i=[n,n+=t[1]];for(;t=/^(\/\:[^\/]+)\?/.exec(r);)i.push(n+=t[1]),r=r.slice(t[0].length);return Bt(r).reduce((e,t)=>[...e,...i.map(e=>e+t)],[])}var Vt,Ht,Ut,Wt=t((()=>{G(),Vt=/^(?:[a-z0-9]+:)?\/\//i,Ht=/^\/+|(\/)\/+$/g,Ut=`http://sr`}));function Gt(e,t=``){let{component:n,preload:r,load:i,children:a,info:o}=e,s=!a||Array.isArray(a)&&!a.length,c={key:e,component:n,preload:r||i,info:o};return qt(e.path).reduce((n,r)=>{for(let i of Bt(r)){let a=Pt(t,i),o=s?a:a.split(`/*`,1)[0];o=o.split(`/`).map(e=>e.startsWith(`:`)||e.startsWith(`*`)?e:encodeURIComponent(e)).join(`/`),n.push({...c,originalPath:r,pattern:o,matcher:It(o,!s,e.matchFilters)})}return n},[])}function Kt(e,t=0){return{routes:e,score:Rt(e[e.length-1])*1e4-t,matcher(t){let n=[];for(let r=e.length-1;r>=0;r--){let i=e[r],a=i.matcher(t);if(!a)return null;n.unshift({...a,route:i})}return n}}}function qt(e){return Array.isArray(e)?e:[e]}function Jt(e,t=``,n=[],r=[]){let i=qt(e);for(let e=0,a=i.length;e<a;e++){let a=i[e];if(a&&typeof a==`object`){a.hasOwnProperty(`path`)||(a.path=``);let e=Gt(a,t);for(let t of e){n.push(t);let e=Array.isArray(a.children)&&a.children.length===0;if(a.children&&!e)Jt(a.children,t.pattern,n,r);else{let e=Kt([...n],r.length);r.push(e)}n.pop()}}}return n.length?r:r.sort((e,t)=>t.score-e.score)}function Yt(e,t){for(let n=0,r=e.length;n<r;n++){let r=e[n].matcher(t);if(r)return r}return[]}function Xt(e,t,n){let r=new URL(Ut),i=d(t=>{let n=e();try{return new URL(n,r)}catch{return console.error(`Invalid path ${n}`),t}},r,{equals:(e,t)=>e.href===t.href}),a=d(()=>i().pathname),o=d(()=>i().search,!0),s=d(()=>i().hash),c=()=>``,l=g(o,()=>Ft(i()));return{get pathname(){return a()},get search(){return o()},get hash(){return s()},get state(){return t()},get key(){return c()},query:n?n(l):zt(l)}}function Zt(){return fn}function Qt(e){pn=e}function $t(e,t,n,r={}){let{signal:[i,a],utils:o={}}=e,c=o.parsePath||(e=>e),u=o.renderPath||(e=>e),f=o.beforeLeave||Tt(),p=Mt(``,r.base||``);if(p===void 0)throw Error(`${p} is not a valid base path`);p&&!i().value&&a({value:p,replace:!0,scroll:!1});let[_,v]=s(!1),y,S=(e,t)=>{t.value===w()&&t.state===T()||(y===void 0&&v(!0),fn=e,y=t,x(()=>{y===t&&(ee(y.value),E(y.state),be(),k[1](e=>e.filter(e=>e.pending)))}).finally(()=>{y===t&&m(()=>{fn=void 0,e===`navigate`&&ie(y),v(!1),y=void 0})}))},[w,ee]=s(i().value),[T,E]=s(i().state),D=Xt(w,T,o.queryWrapper),O=[],k=s([]),A=d(()=>typeof r.transformUrl==`function`?Yt(t(),r.transformUrl(D.pathname)):Yt(t(),D.pathname)),j=()=>{let e=A(),t={};for(let n=0;n<e.length;n++)Object.assign(t,e[n].params);return t},te=o.paramsWrapper?o.paramsWrapper(j,t):zt(j),M={pattern:p,path:()=>p,outlet:()=>null,resolvePath(e){return Mt(p,e)}};return l(g(i,e=>S(`native`,e),{defer:!0})),{base:M,location:D,params:te,isRouting:_,renderPath:u,parsePath:c,navigatorFactory:re,matches:A,beforeLeave:f,preloadRoute:N,singleFlight:r.singleFlight===void 0?!0:r.singleFlight,submissions:k};function ne(e,t,n){h(()=>{if(typeof t==`number`){t&&(o.go?o.go(t):console.warn(`Router integration does not support relative routing`));return}let r=!t||t[0]===`?`,{replace:i,resolve:a,scroll:s,state:c}={replace:!1,resolve:!r,scroll:!0,...n},l=a?e.resolvePath(t):Mt(r&&D.pathname||``,t);if(l===void 0)throw Error(`Path '${t}' is not a routable path`);if(O.length>=tn)throw Error(`Too many redirects`);let u=w();(l!==u||c!==T())&&f.confirm(l,n)&&(O.push({value:u,replace:i,scroll:s,state:T()}),S(`navigate`,{value:l,state:c}))})}function re(e){return e=e||C(rn)||M,(t,n)=>ne(e,t,n)}function ie(e){let t=O[0];t&&(a({...e,replace:t.replace,scroll:t.scroll}),O.length=0)}function N(e,r){let i=Yt(t(),e.pathname),a=fn;fn=`preload`;for(let t in i){let{route:a,params:o}=i[t];a.component&&a.component.preload&&a.component.preload();let{preload:s}=a;pn=!0,r&&s&&b(n(),()=>s({params:o,location:{pathname:e.pathname,search:e.search,hash:e.hash,query:Ft(e),state:null,key:``},intent:`preload`})),pn=!1}fn=a}}function en(e,t,n,r){let{base:i,location:a,params:o}=e,{pattern:s,component:c,preload:l}=r().route,u=d(()=>r().path);c&&c.preload&&c.preload(),pn=!0;let f=l?l({params:o,location:a,intent:fn||`initial`}):void 0;return pn=!1,{parent:t,pattern:s,path:u,outlet:()=>c?P(c,{params:o,location:a,data:f,get children(){return n()}}):n(),resolvePath(e){return Mt(i.path(),e,u())}}}var tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn=t((()=>{G(),X(),At(),Wt(),tn=100,nn=S(),rn=S(),an=()=>Nt(C(nn),`<A> and 'use' router primitives can be only used inside a Route.`),on=()=>C(rn)||an().base,sn=e=>{let t=on();return d(()=>t.resolvePath(e()))},cn=e=>{let t=an();return d(()=>{let n=e();return n===void 0?n:t.renderPath(n)})},ln=()=>an().navigatorFactory(),un=()=>an().location,dn=()=>an().params}));function hn(e){let t=e.routerState.location,n=e.routerState.params,r=d(()=>e.preload&&h(()=>{Qt(!0),e.preload({params:n,location:t,intent:Zt()||`initial`}),Qt(!1)}));return P(L,{get when(){return e.root},keyed:!0,get fallback(){return e.children},children:i=>P(i,{params:n,location:t,get data(){return r()},get children(){return e.children}})})}function gn(e){let t=[],n,r=d(g(e.routerState.matches,(i,a,s)=>{let c=a&&i.length===a.length,l=[];for(let n=0,u=i.length;n<u;n++){let u=a&&a[n],d=i[n];s&&u&&d.route.key===u.route.key?l[n]=s[n]:(c=!1,t[n]&&t[n](),o(i=>{t[n]=i,l[n]=en(e.routerState,l[n-1]||e.routerState.base,vn(()=>r()[n+1]),()=>{let t=e.routerState.matches();return t[n]??t[0]})}))}return t.splice(i.length).forEach(e=>e()),s&&c?s:(n=l[0],l)}));return vn(()=>r()&&n)()}var _n,vn,yn,bn=t((()=>{X(),G(),mn(),_n=e=>t=>{let{base:n}=t,r=w(()=>t.children),i=d(()=>Jt(r(),t.base||``)),a,o=$t(e,i,()=>a,{base:n,singleFlight:t.singleFlight,transformUrl:t.transformUrl});return e.create&&e.create(o),P(nn.Provider,{value:o,get children(){return P(hn,{routerState:o,get root(){return t.root},get preload(){return t.rootPreload||t.rootLoad},get children(){return[St(()=>(a=y())&&null),P(gn,{routerState:o,get branches(){return i()}})]}})}})},vn=e=>()=>P(L,{get when(){return e()},keyed:!0,children:e=>P(rn.Provider,{value:e,get children(){return e.outlet()}})}),yn=e=>{let t=w(()=>e.children);return F(e,{get children(){return t()}})}}));function xn([e,t],n,r){return[n?()=>n(e()):e,r?e=>t(r(e)):t]}function Sn(e){let t=!1,n=e=>typeof e==`string`?{value:e}:e,r=xn(s(n(e.get()),{equals:(e,t)=>e.value===t.value&&e.state===t.state}),void 0,n=>(!t&&e.set(n),R.registry&&!R.done&&(R.done=!0),n));return e.init&&v(e.init((i=e.get())=>{t=!0,r[1](n(i)),t=!1})),_n({signal:r,create:e.create,utils:e.utils})}function Cn(e,t,n){return e.addEventListener(t,n),()=>e.removeEventListener(t,n)}function wn(e,t){let n=e&&document.getElementById(e);n?n.scrollIntoView():t&&window.scrollTo(0,0)}var Tn=t((()=>{G(),bn()})),En,Dn=t((()=>{En=new Map}));function On(e=!0,t=!1,n=`/_server`,r){return i=>{let a=i.base.path(),o=i.navigatorFactory(i.base),s,c;function l(e){return e.namespaceURI===`http://www.w3.org/2000/svg`}function u(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;let n=e.composedPath().find(e=>e instanceof Node&&e.nodeName.toUpperCase()===`A`);if(!n||t&&!n.hasAttribute(`link`))return;let r=l(n),i=r?n.href.baseVal:n.href;if((r?n.target.baseVal:n.target)||!i&&!n.hasAttribute(`state`))return;let o=(n.getAttribute(`rel`)||``).split(/\s+/);if(n.hasAttribute(`download`)||o&&o.includes(`external`))return;let s=r?new URL(i,document.baseURI):new URL(i);if(!(s.origin!==window.location.origin||a&&s.pathname&&!s.pathname.toLowerCase().startsWith(a.toLowerCase())))return[n,s]}function d(e){let t=u(e);if(!t)return;let[n,r]=t,a=i.parsePath(r.pathname+r.search+r.hash),s=n.getAttribute(`state`);e.preventDefault(),o(a,{resolve:!1,replace:n.hasAttribute(`replace`),scroll:!n.hasAttribute(`noscroll`),state:s?JSON.parse(s):void 0})}function f(e){let t=u(e);if(!t)return;let[n,a]=t;r&&(a.pathname=r(a.pathname)),i.preloadRoute(a,n.getAttribute(`preload`)!==`false`)}function p(e){clearTimeout(s);let t=u(e);if(!t)return c=null;let[n,a]=t;c!==n&&(r&&(a.pathname=r(a.pathname)),s=setTimeout(()=>{i.preloadRoute(a,n.getAttribute(`preload`)!==`false`),c=n},20))}function m(e){if(e.defaultPrevented)return;let t=e.submitter&&e.submitter.hasAttribute(`formaction`)?e.submitter.getAttribute(`formaction`):e.target.getAttribute(`action`);if(!t)return;if(!t.startsWith(`https://action/`)){let e=new URL(t,Ut);if(t=i.parsePath(e.pathname+e.search),!t.startsWith(n))return}if(e.target.method.toUpperCase()!==`POST`)throw Error(`Only POST forms are supported for Actions`);let r=En.get(t);if(r){e.preventDefault();let t=new FormData(e.target,e.submitter);r.call({r:i,f:e.target},e.target.enctype===`multipart/form-data`?t:new URLSearchParams(t))}}q([`click`,`submit`]),document.addEventListener(`click`,d),e&&(document.addEventListener(`mousemove`,p,{passive:!0}),document.addEventListener(`focusin`,f,{passive:!0}),document.addEventListener(`touchstart`,f,{passive:!0})),document.addEventListener(`submit`,m),v(()=>{document.removeEventListener(`click`,d),e&&(document.removeEventListener(`mousemove`,p),document.removeEventListener(`focusin`,f),document.removeEventListener(`touchstart`,f)),document.removeEventListener(`submit`,m)})}}var kn=t((()=>{X(),G(),Dn(),Wt()}));function An(e){let t=e.replace(/^.*?#/,``);if(!t.startsWith(`/`)){let[,e=`/`]=window.location.hash.split(`#`,2);return`${e}#${t}`}return t}function jn(e){let t=()=>window.location.hash.slice(1),n=Tt();return Sn({get:t,set({value:e,replace:t,scroll:n,state:r}){t?window.history.replaceState(Dt(r),``,`#`+e):window.history.pushState(r,``,`#`+e);let i=e.indexOf(`#`);wn(i>=0?e.slice(i+1):``,n),Et()},init:e=>Cn(window,`hashchange`,Ot(e,e=>!n.confirm(e&&e<0?e:t()))),create:On(e.preload,e.explicitLinks,e.actionBase),utils:{go:e=>window.history.go(e),renderPath:e=>`#${e}`,parsePath:An,beforeLeave:n}})(e)}var Mn=t((()=>{kn(),Tn(),At()})),Nn=t((()=>{bn(),Tn(),X(),kn(),At(),Mn()}));function Pn(e){e=F({inactiveClass:`inactive`,activeClass:`active`},e);let[,t]=ge(e,[`href`,`state`,`class`,`activeClass`,`inactiveClass`,`end`]),n=sn(()=>e.href),r=cn(n),i=un(),a=d(()=>{let t=n();if(t===void 0)return[!1,!1];let r=jt(t.split(/[?#]/,1)[0]).toLowerCase(),a=decodeURI(jt(i.pathname).toLowerCase());return[e.end?r===a:a.startsWith(r+`/`)||a===r,r===a]});return(()=>{var n=Fn();return Qe(n,F(t,{get href(){return r()||e.href},get state(){return JSON.stringify(e.state)},get classList(){return{...e.class&&{[e.class]:!0},[e.inactiveClass]:!a()[0],[e.activeClass]:a()[0],...t.classList}},link:``,get"aria-current"(){return a()[1]?`page`:void 0}}),!1,!1),n})()}var Fn,In=t((()=>{X(),G(),mn(),Wt(),Fn=K(`<a>`)})),Ln=t((()=>{G(),X(),Dn(),mn()})),Rn=t((()=>{Nn(),In(),At(),mn(),Wt(),Ln()})),zn,Bn=t((()=>{zn={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":2,"stroke-linecap":`round`,"stroke-linejoin":`round`}})),Vn,Hn,Un,Wn,Z,Q=t((()=>{X(),G(),Bn(),Vn=K(`<svg>`),Hn=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),Un=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),Wn=e=>{let[t,n]=ge(e,[`color`,`size`,`strokeWidth`,`children`,`class`,`name`,`iconNode`,`absoluteStrokeWidth`]);return(()=>{var e=Vn();return Qe(e,F(zn,{get width(){return t.size??zn.width},get height(){return t.size??zn.height},get stroke(){return t.color??zn.stroke},get"stroke-width"(){return St(()=>!!t.absoluteStrokeWidth)()?Number(t.strokeWidth??zn[`stroke-width`])*24/Number(t.size):Number(t.strokeWidth??zn[`stroke-width`])},get class(){return Un(`lucide`,`lucide-icon`,t.name==null?void 0:`lucide-${Hn(t?.name)}`,t.class==null?``:t.class)}},n),!0,!0),Y(e,P(I,{get each(){return t.iconNode},children:([e,t])=>P(mt,F({component:e},t))})),e})()},Z=Wn})),Gn,Kn,qn,Jn=t((()=>{X(),Q(),Gn=[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]],Kn=e=>P(Z,F(e,{name:`Activity`,iconNode:Gn})),qn=Kn})),Yn,Xn,Zn,Qn=t((()=>{X(),Q(),Yn=[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]],Xn=e=>P(Z,F(e,{name:`ArrowLeft`,iconNode:Yn})),Zn=Xn})),$n,er,tr,nr=t((()=>{X(),Q(),$n=[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]],er=e=>P(Z,F(e,{name:`BookOpen`,iconNode:$n})),tr=er})),rr,ir,ar,or=t((()=>{X(),Q(),rr=[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]],ir=e=>P(Z,F(e,{name:`ChevronDown`,iconNode:rr})),ar=ir})),sr,cr,lr,ur=t((()=>{X(),Q(),sr=[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]],cr=e=>P(Z,F(e,{name:`ChevronRight`,iconNode:sr})),lr=cr})),dr,fr,pr,mr=t((()=>{X(),Q(),dr=[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]],fr=e=>P(Z,F(e,{name:`ChevronUp`,iconNode:dr})),pr=fr})),hr,gr,_r,vr=t((()=>{X(),Q(),hr=[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]],gr=e=>P(Z,F(e,{name:`CircleCheckBig`,iconNode:hr})),_r=gr})),yr,br,xr,Sr=t((()=>{X(),Q(),yr=[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]],br=e=>P(Z,F(e,{name:`CircleDashed`,iconNode:yr})),xr=br})),Cr,wr,Tr,Er=t((()=>{X(),Q(),Cr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]],wr=e=>P(Z,F(e,{name:`CircleX`,iconNode:Cr})),Tr=wr})),Dr,Or,kr,Ar=t((()=>{X(),Q(),Dr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]],Or=e=>P(Z,F(e,{name:`Clock`,iconNode:Dr})),kr=Or})),jr,Mr,Nr,Pr=t((()=>{X(),Q(),jr=[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]],Mr=e=>P(Z,F(e,{name:`CodeXml`,iconNode:jr})),Nr=Mr})),Fr,Ir,Lr,Rr=t((()=>{X(),Q(),Fr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M9 15h6`,key:`cctwl0`}],[`path`,{d:`M12 18v-6`,key:`17g6i2`}]],Ir=e=>P(Z,F(e,{name:`FilePlus`,iconNode:Fr})),Lr=Ir})),zr,Br,Vr,Hr=t((()=>{X(),Q(),zr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]],Br=e=>P(Z,F(e,{name:`FileText`,iconNode:zr})),Vr=Br})),Ur,Wr,Gr,Kr=t((()=>{X(),Q(),Ur=[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]],Wr=e=>P(Z,F(e,{name:`FolderOpen`,iconNode:Ur})),Gr=Wr})),qr,Jr,Yr,Xr=t((()=>{X(),Q(),qr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]],Jr=e=>P(Z,F(e,{name:`Globe`,iconNode:qr})),Yr=Jr})),Zr,Qr,$r,ei=t((()=>{X(),Q(),Zr=[[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}],[`path`,{d:`M10.41 10.41a2 2 0 1 1-2.83-2.83`,key:`1bzlo9`}],[`line`,{x1:`13.5`,x2:`6`,y1:`13.5`,y2:`21`,key:`1q0aeu`}],[`line`,{x1:`18`,x2:`21`,y1:`12`,y2:`15`,key:`5mozeu`}],[`path`,{d:`M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59`,key:`mmje98`}],[`path`,{d:`M21 15V5a2 2 0 0 0-2-2H9`,key:`43el77`}]],Qr=e=>P(Z,F(e,{name:`ImageOff`,iconNode:Zr})),$r=Qr})),ti,ni,ri,ii=t((()=>{X(),Q(),ti=[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]],ni=e=>P(Z,F(e,{name:`Image`,iconNode:ti})),ri=ni})),ai,oi,si,ci=t((()=>{X(),Q(),ai=[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]],oi=e=>P(Z,F(e,{name:`Languages`,iconNode:ai})),si=oi})),li,ui,di,fi=t((()=>{X(),Q(),li=[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]],ui=e=>P(Z,F(e,{name:`Layers`,iconNode:li})),di=ui})),pi,mi,hi,gi=t((()=>{X(),Q(),pi=[[`rect`,{width:`7`,height:`9`,x:`3`,y:`3`,rx:`1`,key:`10lvy0`}],[`rect`,{width:`7`,height:`5`,x:`14`,y:`3`,rx:`1`,key:`16une8`}],[`rect`,{width:`7`,height:`9`,x:`14`,y:`12`,rx:`1`,key:`1hutg5`}],[`rect`,{width:`7`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`ldoo1y`}]],mi=e=>P(Z,F(e,{name:`LayoutDashboard`,iconNode:pi})),hi=mi})),_i,vi,yi,bi=t((()=>{X(),Q(),_i=[[`path`,{d:`M12 20h9`,key:`t2du7b`}],[`path`,{d:`M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z`,key:`1ykcvy`}]],vi=e=>P(Z,F(e,{name:`PenLine`,iconNode:_i})),yi=vi})),xi,Si,Ci,wi=t((()=>{X(),Q(),xi=[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]],Si=e=>P(Z,F(e,{name:`Pen`,iconNode:xi})),Ci=Si})),Ti,Ei,Di,Oi=t((()=>{X(),Q(),Ti=[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]],Ei=e=>P(Z,F(e,{name:`Plus`,iconNode:Ti})),Di=Ei})),ki,Ai,ji,Mi=t((()=>{X(),Q(),ki=[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]],Ai=e=>P(Z,F(e,{name:`RefreshCw`,iconNode:ki})),ji=Ai})),Ni,Pi,Fi,Ii=t((()=>{X(),Q(),Ni=[[`path`,{d:`M3 7V5a2 2 0 0 1 2-2h2`,key:`aa7l1z`}],[`path`,{d:`M17 3h2a2 2 0 0 1 2 2v2`,key:`4qcy5o`}],[`path`,{d:`M21 17v2a2 2 0 0 1-2 2h-2`,key:`6vwrx8`}],[`path`,{d:`M7 21H5a2 2 0 0 1-2-2v-2`,key:`ioqczr`}],[`path`,{d:`M7 8h8`,key:`1jbsf9`}],[`path`,{d:`M7 12h10`,key:`b7w52i`}],[`path`,{d:`M7 16h6`,key:`1vyc9m`}]],Pi=e=>P(Z,F(e,{name:`ScanText`,iconNode:Ni})),Fi=Pi})),Li,Ri,zi,Bi=t((()=>{X(),Q(),Li=[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]],Ri=e=>P(Z,F(e,{name:`ShieldAlert`,iconNode:Li})),zi=Ri})),Vi,Hi,Ui,Wi=t((()=>{X(),Q(),Vi=[[`path`,{d:`M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z`,key:`4pj2yx`}],[`path`,{d:`M20 3v4`,key:`1olli1`}],[`path`,{d:`M22 5h-4`,key:`1gvqau`}],[`path`,{d:`M4 17v2`,key:`vumght`}],[`path`,{d:`M5 18H3`,key:`zchphs`}]],Hi=e=>P(Z,F(e,{name:`Sparkles`,iconNode:Vi})),Ui=Hi})),Gi,Ki,qi,Ji=t((()=>{X(),Q(),Gi=[[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6`,key:`4alrt4`}],[`path`,{d:`M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2`,key:`v07s0e`}],[`line`,{x1:`10`,x2:`10`,y1:`11`,y2:`17`,key:`1uufr5`}],[`line`,{x1:`14`,x2:`14`,y1:`11`,y2:`17`,key:`xtxkd`}]],Ki=e=>P(Z,F(e,{name:`Trash2`,iconNode:Gi})),qi=Ki})),Yi,Xi,Zi,Qi=t((()=>{X(),Q(),Yi=[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]],Xi=e=>P(Z,F(e,{name:`X`,iconNode:Yi})),Zi=Xi})),$i=t((()=>{Jn(),Qn(),nr(),or(),ur(),mr(),Sr(),Ar(),Rr(),Hr(),Kr(),Xr(),ei(),ii(),ci(),fi(),gi(),bi(),Oi(),Mi(),Ii(),Bi(),Wi(),Ji(),Qi()})),ea=t((()=>{vr()})),ta=t((()=>{Er()})),na=t((()=>{Pr()})),ra=t((()=>{wi()})),ia=t((()=>{ea(),ta(),na(),ra()})),aa=t((()=>{})),oa=t((()=>{})),sa=t((()=>{ia(),aa(),oa()})),ca=t((()=>{})),la=t((()=>{$i(),sa(),ca()}));X(),Rn(),la();var ua=K(`<div class="flex h-screen bg-slate-50 text-slate-800"><nav class="group flex w-14 flex-col gap-1 overflow-hidden bg-slate-900 px-2 py-4 transition-all duration-200 hover:w-48"><div class="mb-4 flex items-center gap-3 px-1"><span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-violet-600 text-xs font-bold text-white">W</span><span class="whitespace-nowrap text-sm font-semibold text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100">WebOCR</span></div></nav><main class="flex-1 overflow-y-auto">`),da=K(`<span class="flex h-8 w-8 shrink-0 items-center justify-center">`),fa=K(`<span class="whitespace-nowrap text-sm opacity-0 transition-opacity duration-200 group-hover:opacity-100">`),pa=[{href:`/`,label:`Dashboard`,Icon:hi},{href:`/jobs`,label:`Jobs`,Icon:ri},{href:`/library`,label:`Library`,Icon:tr}];function ma(e){return(()=>{var t=ua(),n=t.firstChild;n.firstChild;var r=n.nextSibling;return Y(n,()=>pa.map(e=>P(Pn,{get href(){return e.href},get end(){return e.href===`/`},class:`flex items-center gap-3 rounded-lg px-1 py-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-white`,activeClass:`bg-slate-800 text-white!`,get children(){return[(()=>{var t=da();return Y(t,P(e.Icon,{class:`h-5 w-5`})),t})(),(()=>{var t=fa();return Y(t,()=>e.label),t})()]}})),null),Y(r,()=>e.children),t})()}X(),G(),la();var ha=K(`<span class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700">`),ga=K(`<span class="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-500">`),_a=K(`<span class="inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-xs text-red-600">`),va=K(`<div class="min-h-screen bg-slate-50 px-4 py-10"><div class="mx-auto max-w-2xl space-y-8"><div class="flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div><h1 class="text-xl font-semibold text-slate-800">Web OCR Server</h1><p class="text-sm text-slate-500">ASP.NET Core · Manga-OCR · Opus-MT</p></div><div class=ml-auto></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">Server info</span></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">API Endpoints</span></div><ul class="divide-y divide-slate-50">`),ya=K(`<div class="flex items-center gap-2 px-5 py-4 text-sm text-red-600">`),ba=K(`<div class="px-5 py-4 text-sm text-slate-400">Loading…`),xa=K(`<dl class="divide-y divide-slate-50 text-sm"><div class="flex items-center gap-3 px-5 py-3"><dt class="w-36 shrink-0 text-slate-500">Version</dt><dd class="font-medium text-slate-800"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> OCR models</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> Translate</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-center gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> DeepL</dt><dd>`),Sa=K(`<li class="flex items-center gap-4 px-5 py-3.5 text-sm"><span></span><code class="w-28 shrink-0 text-slate-700"></code><span></span><span class=text-slate-500>`);function Ca(e){return P(L,{get when(){return e.ok!==null},get fallback(){return(()=>{var t=ga();return Y(t,P(xr,{class:`h-3 w-3 animate-spin`}),null),Y(t,()=>e.label,null),t})()},get children(){return P(L,{get when(){return e.ok},get fallback(){return(()=>{var t=_a();return Y(t,P(Tr,{class:`h-3 w-3`}),null),Y(t,()=>e.label,null),t})()},get children(){var t=ha();return Y(t,P(_r,{class:`h-3 w-3`}),null),Y(t,()=>e.label,null),t}})}})}var wa=[{method:`GET`,path:`/health`,desc:`Server status, version, model paths`,Icon:qn,color:`text-sky-600`},{method:`POST`,path:`/ocr`,desc:`Base64 image → Japanese text`,Icon:Fi,color:`text-violet-600`},{method:`POST`,path:`/translate`,desc:`Japanese → English (local Opus-MT or DeepL)`,Icon:si,color:`text-amber-600`},{method:`POST`,path:`/analyze`,desc:`Tokenise text + dictionary lookup`,Icon:tr,color:`text-emerald-600`}],Ta={GET:`bg-sky-50 text-sky-700`,POST:`bg-violet-50 text-violet-700`};function Ea(){let[e,t]=s(null),[n,r]=s(null);_(()=>{fetch(`/health`).then(e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);return e.json()}).then(t).catch(e=>r(String(e)))});let i=()=>{if(n())return!1;let t=e();return t?t.status===`ok`:null},a=()=>{if(n())return`error`;let t=e();return t?t.status:`connecting`};return(()=>{var t=va(),r=t.firstChild.firstChild,o=r.firstChild,s=o.nextSibling.nextSibling,c=r.nextSibling;c.firstChild;var u=c.nextSibling.firstChild.nextSibling;return Y(o,P(Nr,{class:`h-6 w-6 text-slate-700`})),Y(s,P(Ca,{get ok(){return i()},get label(){return a()}})),Y(c,P(L,{get when(){return!n()},get fallback(){return(()=>{var e=ya();return Y(e,P(zi,{class:`h-4 w-4 shrink-0`}),null),Y(e,n,null),e})()},get children(){return P(L,{get when(){return e()},get fallback(){return ba()},children:e=>(()=>{var t=xa(),n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild,o=a.firstChild,s=a.nextSibling,c=i.nextSibling,l=c.firstChild,u=l.firstChild,d=l.nextSibling,f=c.nextSibling.firstChild,p=f.firstChild,m=f.nextSibling;return Y(r,()=>e().version),Y(a,P(Gr,{class:`h-3.5 w-3.5`}),o),Y(s,()=>e().ocr_models_dir),Y(l,P(Gr,{class:`h-3.5 w-3.5`}),u),Y(d,()=>e().translate_models_dir),Y(f,P(Yr,{class:`h-3.5 w-3.5`}),p),Y(m,P(Ca,{get ok(){return e().deepl_available},get label(){return e().deepl_available?`configured`:`not configured`}})),t})()})}}),null),Y(u,P(I,{each:wa,children:({method:e,path:t,desc:n,Icon:r,color:i})=>(()=>{var a=Sa(),o=a.firstChild,s=o.nextSibling,c=s.nextSibling,u=c.nextSibling;return Y(o,e),Y(s,t),qe(c,`shrink-0 ${i}`),Y(c,P(r,{class:`h-4 w-4`})),Y(u,n),l(()=>qe(o,`w-12 shrink-0 rounded px-1.5 py-0.5 text-center text-xs font-semibold ${Ta[e]??``}`)),a})()})),t})()}function Da(e){return e.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function Oa(e){return e.replace(/([A-Z])/g,e=>`_${e.toLowerCase()}`)}function ka(e){if(Array.isArray(e))return e.map(ka);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Da(n)]=ka(r);return t}return e}function Aa(e){if(Array.isArray(e))return e.map(Aa);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Oa(n)]=Aa(r);return t}return e}async function $(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`,...t?.headers},...t});if(!n.ok){let e=await n.text().catch(()=>n.statusText);throw Error(`API ${n.status}: ${e}`)}if(n.status!==204)return ka(await n.json())}function ja(e={}){let t=new URLSearchParams;e.page!==void 0&&t.set(`page`,String(e.page)),e.pageSize!==void 0&&t.set(`page_size`,String(e.pageSize)),e.status&&t.set(`status`,e.status),e.chapterId!==void 0&&t.set(`chapter_id`,String(e.chapterId));let n=t.toString();return $(`/api/portal/jobs${n?`?${n}`:``}`)}function Ma(e){return $(`/api/portal/jobs/${e}`)}function Na(e,t){return $(`/api/portal/jobs/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Pa(e){return $(`/api/portal/jobs/${e}/bubbles`)}function Fa(e,t){return $(`/api/portal/jobs/${e}/bubbles`,{method:`POST`,body:JSON.stringify(Aa(t))})}function Ia(e,t,n){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`PUT`,body:JSON.stringify(Aa(n))})}function La(e,t){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`DELETE`})}function Ra(e){return $(`/api/portal/jobs/${e}/redetect`,{method:`POST`})}function za(e){return $(`/api/portal/jobs/${e}/retranslate`,{method:`POST`})}function Ba(e){return $(`/api/portal/jobs/${e}/rerender`,{method:`POST`})}function Va(){return $(`/api/portal/volumes`)}function Ha(e){return $(`/api/portal/volumes`,{method:`POST`,body:JSON.stringify(Aa(e))})}function Ua(e,t){return $(`/api/portal/volumes/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Wa(e){return $(`/api/portal/volumes/${e}`,{method:`DELETE`})}function Ga(e={}){let t=new URLSearchParams;e.volumeId!==void 0&&t.set(`volume_id`,String(e.volumeId));let n=t.toString();return $(`/api/portal/chapters${n?`?${n}`:``}`)}function Ka(e){return $(`/api/portal/chapters`,{method:`POST`,body:JSON.stringify(Aa(e))})}function qa(e,t){return $(`/api/portal/chapters/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Ja(e){return $(`/api/portal/chapters/${e}`,{method:`DELETE`})}function Ya(e){return $(`/api/portal/chapters/${e}/jobs`)}function Xa(e){return`/api/portal/jobs/${e}/original`}function Za(e){return`/api/portal/jobs/${e}/result`}var Qa=t((()=>{})),$a=n({JobsListPage:()=>no,StatusBadge:()=>eo});function eo(e){let t=()=>{switch(e.status){case`done`:return{cls:`bg-green-100 text-green-700`,Icon:_r,label:`Done`};case`processing`:return{cls:`bg-yellow-100 text-yellow-700`,Icon:kr,label:`Processing`};case`error`:return{cls:`bg-red-100 text-red-700`,Icon:Tr,label:`Error`};default:return{cls:`bg-slate-100 text-slate-600`,Icon:kr,label:String(e.status)}}};return(()=>{var e=ro();return Y(e,()=>P(t()?.Icon??kr,{class:`h-3 w-3`}),null),Y(e,()=>t()?.label??``,null),l(()=>qe(e,`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${t()?.cls??``}`)),e})()}function to(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=io(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling.firstChild,s=o.nextSibling.firstChild,c=s.firstChild,u=s.nextSibling;return Je(n,`click`,e.onClick,!0),Y(a,P(eo,{get status(){return e.job.status}})),Y(o,()=>e.job.title),Y(s,P(di,{class:`h-3 w-3`}),c),Y(s,()=>e.job.bubbleCount,c),Y(u,()=>new Date(e.job.createdAt).toLocaleDateString()),l(n=>{var r=t(),a=e.job.title;return r!==n.e&&J(i,`src`,n.e=r),a!==n.t&&J(i,`alt`,n.t=a),n},{e:void 0,t:void 0}),n})()}function no(){let e=ln(),[t,n]=s(``),[r,i]=s(``),[a]=p(t,e=>ja({pageSize:100,status:e||void 0})),o=()=>{let e=r().toLowerCase();return(a()?.items??[]).filter(t=>!e||t.title.toLowerCase().includes(e))};return(()=>{var s=so(),c=s.firstChild,u=c.firstChild,d=c.nextSibling.firstChild,f=d.nextSibling;return Y(u,P(ri,{class:`h-5 w-5 text-violet-600`})),d.$$input=e=>i(e.currentTarget.value),f.addEventListener(`change`,e=>n(e.currentTarget.value)),Y(f,()=>fo.map(e=>(()=>{var t=co();return Y(t,()=>e.label),l(()=>t.value=e.value),t})())),Y(s,P(L,{get when(){return a.loading},get children(){var e=ao();return Y(e,()=>Array.from({length:10}).map(()=>lo())),e}}),null),Y(s,P(L,{get when(){return a.error},get children(){var e=oo();return e.firstChild,Y(e,()=>String(a.error),null),e}}),null),Y(s,P(L,{get when(){return St(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return o().length>0},get fallback(){return(()=>{var e=uo(),t=e.firstChild;return Y(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var t=ao();return Y(t,P(I,{get each(){return o()},children:t=>P(to,{job:t,onClick:()=>e(`/jobs/${t.id}`)})})),t}})}}),null),l(()=>d.value=r()),l(()=>f.value=t()),s})()}var ro,io,ao,oo,so,co,lo,uo,fo,po=t((()=>{X(),G(),Rn(),la(),Qa(),ro=K(`<span>`),io=K(`<button class="group flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-violet-500"><div class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><div class="absolute right-2 top-2"></div></div><div class="flex flex-col gap-1 p-3"><p class="truncate text-sm font-medium text-slate-800"></p><div class="flex items-center gap-3 text-xs text-slate-500"><span class="flex items-center gap-1"> bubbles</span><span class=ml-auto>`,!0,!1,!1),ao=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),oo=K(`<div class="rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load jobs: `),so=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Jobs</h1></div><div class="mb-6 flex flex-wrap gap-3"><input type=search placeholder="Search jobs…"class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-400"><select class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-400">`),co=K(`<option>`),lo=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),uo=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No jobs yet.</p><p class="max-w-xs text-center text-xs text-slate-400">Upload pages via the extension or API to see translation jobs here.`),fo=[{value:``,label:`All statuses`},{value:`done`,label:`Done`},{value:`processing`,label:`Processing`},{value:`error`,label:`Error`}],q([`click`,`input`])}));function mo(e,t,n,r){let{x:i,y:a,w:o,h:s}=t;switch(e){case`TL`:i+=n,a+=r,o-=n,s-=r;break;case`T`:a+=r,s-=r;break;case`TR`:a+=r,o+=n,s-=r;break;case`L`:i+=n,o-=n;break;case`R`:o+=n;break;case`BL`:i+=n,o-=n,s+=r;break;case`B`:s+=r;break;case`BR`:o+=n,s+=r;break}return o<5&&(o=5),s<5&&(s=5),{x:i,y:a,w:o,h:s}}function ho(e){let t,n,[r,i]=s({scale:1,offsetX:0,offsetY:0}),[a,o]=s({kind:`none`});function c(){if(!t||!e.imageWidth||!e.imageHeight)return;let n=t.clientWidth,r=t.clientHeight;if(n===0||r===0)return;let a=n/e.imageWidth,o=r/e.imageHeight,s=Math.min(a,o),c=e.imageWidth*s,l=e.imageHeight*s;i({scale:s,offsetX:(n-c)/2,offsetY:(r-l)/2})}function u(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return{x:e*n+i,y:t*n+a}}function d(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return n===0?{x:0,y:0}:{x:(e-i)/n,y:(t-a)/n}}function f(e){let t=n.getBoundingClientRect();return d(e.clientX-t.left,e.clientY-t.top)}function p(e){let t=a();return t.kind===`moving`&&t.bubbleIndex===e.bubbleIndex?{x:e.bubbleX+(t.curImgX-t.startImgX),y:e.bubbleY+(t.curImgY-t.startImgY),w:e.bubbleW,h:e.bubbleH}:t.kind===`resizing`&&t.bubbleIndex===e.bubbleIndex?mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY):{x:e.bubbleX,y:e.bubbleY,w:e.bubbleW,h:e.bubbleH}}function m(){let e=a();return e.kind===`drawing`?{x:Math.min(e.startImgX,e.curImgX),y:Math.min(e.startImgY,e.curImgY),w:Math.abs(e.curImgX-e.startImgX),h:Math.abs(e.curImgY-e.startImgY)}:null}function h(e){let t=a();if(t.kind===`none`)return;e.preventDefault();let n=f(e);(t.kind===`moving`||t.kind===`resizing`||t.kind===`drawing`)&&o({...t,curImgX:n.x,curImgY:n.y})}function g(){let t=a();if(t.kind===`moving`){let n=t.curImgX-t.startImgX,r=t.curImgY-t.startImgY;(Math.abs(n)>1||Math.abs(r)>1)&&e.onMove(t.bubbleIndex,n,r)}else if(t.kind===`resizing`){let n=mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY);e.onResize(t.bubbleIndex,n.x,n.y,n.w,n.h)}else if(t.kind===`drawing`){let n=Math.min(t.startImgX,t.curImgX),r=Math.min(t.startImgY,t.curImgY),i=Math.abs(t.curImgX-t.startImgX),a=Math.abs(t.curImgY-t.startImgY);i>5&&a>5?e.onDraw(n,r,i,a):e.onSelect(null)}o({kind:`none`}),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)}function y(e){e.preventDefault(),g()}function b(){window.addEventListener(`mousemove`,h),window.addEventListener(`mouseup`,y)}function x(e){e.preventDefault();let t=f(e);o({kind:`drawing`,startImgX:t.x,startImgY:t.y,curImgX:t.x,curImgY:t.y}),b()}function S(t,n){t.preventDefault(),t.stopPropagation(),e.onSelect(n.bubbleIndex);let r=f(t);o({kind:`moving`,bubbleIndex:n.bubbleIndex,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}function C(e,t,n){e.preventDefault(),e.stopPropagation();let r=f(e);o({kind:`resizing`,bubbleIndex:t.bubbleIndex,handle:n,origX:t.bubbleX,origY:t.bubbleY,origW:t.bubbleW,origH:t.bubbleH,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}return _(()=>{c();let e=new ResizeObserver(()=>c());e.observe(t),v(()=>{e.disconnect(),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)})}),(()=>{var r=go(),i=r.firstChild,o=i.nextSibling,s=t;typeof s==`function`?$e(s,r):t=r,i.addEventListener(`load`,c),J(i,`draggable`,!1),o.$$mousedown=x;var d=n;return typeof d==`function`?$e(d,o):n=o,Y(o,P(I,{get each(){return e.bubbles},children:t=>{let n=()=>p(t),r=()=>{let e=n(),t=u(e.x,e.y),r=u(e.x+e.w,e.y+e.h);return{x:t.x,y:t.y,w:r.x-t.x,h:r.y-t.y}},i=()=>e.selectedIndex===t.bubbleIndex,a=()=>t.isExcluded?`#9ca3af`:i()?`#7c3aed`:t.isManuallyAdded?`#10b981`:`#3b82f6`,o=()=>t.isExcluded?`rgba(0,0,0,0.15)`:i()?`rgba(124,58,237,0.1)`:`rgba(59,130,246,0.05)`;return(()=>{var e=vo(),s=e.firstChild,c=s.nextSibling,d=c.nextSibling;return s.$$mousedown=e=>S(e,t),Y(e,P(L,{get when(){return t.isExcluded},get children(){var e=_o();return l(t=>{var n=r().x,i=r().y,a=r().x+r().w,o=r().y+r().h;return n!==t.e&&J(e,`x1`,t.e=n),i!==t.t&&J(e,`y1`,t.t=i),a!==t.a&&J(e,`x2`,t.a=a),o!==t.o&&J(e,`y2`,t.o=o),t},{e:void 0,t:void 0,a:void 0,o:void 0}),e}}),c),Y(c,()=>t.bubbleIndex),Y(d,()=>t.bubbleIndex),Y(e,P(L,{get when(){return i()},get children(){return P(I,{each:xo,children:e=>{let[r,i]=So[e],a=()=>{let e=n();return u(e.x+r*e.w,e.y+i*e.h)};return(()=>{var n=yo();return n.$$mousedown=n=>C(n,t,e),l(t=>{var r=a().x-4,i=a().y-4,o=Co[e];return r!==t.e&&J(n,`x`,t.e=r),i!==t.t&&J(n,`y`,t.t=i),o!==t.a&&Ze(n,`cursor`,t.a=o),t},{e:void 0,t:void 0,a:void 0}),n})()}})}}),null),l(e=>{var t=r().x,n=r().y,l=r().w,u=r().h,f=o(),p=a(),m=i()?3:2,h=r().x+4,g=r().y+13,_=r().x+3,v=r().y+12;return t!==e.e&&J(s,`x`,e.e=t),n!==e.t&&J(s,`y`,e.t=n),l!==e.a&&J(s,`width`,e.a=l),u!==e.o&&J(s,`height`,e.o=u),f!==e.i&&J(s,`fill`,e.i=f),p!==e.n&&J(s,`stroke`,e.n=p),m!==e.s&&J(s,`stroke-width`,e.s=m),h!==e.h&&J(c,`x`,e.h=h),g!==e.r&&J(c,`y`,e.r=g),_!==e.d&&J(d,`x`,e.d=_),v!==e.l&&J(d,`y`,e.l=v),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0,h:void 0,r:void 0,d:void 0,l:void 0}),e})()}}),null),Y(o,P(L,{get when(){return m()},children:e=>{let t=()=>{let t=e(),n=u(t.x,t.y),r=u(t.x+t.w,t.y+t.h);return{x:n.x,y:n.y,w:r.x-n.x,h:r.y-n.y}};return(()=>{var e=bo();return l(n=>{var r=t().x,i=t().y,a=t().w,o=t().h;return r!==n.e&&J(e,`x`,n.e=r),i!==n.t&&J(e,`y`,n.t=i),a!==n.a&&J(e,`width`,n.a=a),o!==n.o&&J(e,`height`,n.o=o),n},{e:void 0,t:void 0,a:void 0,o:void 0}),e})()}}),null),l(t=>{var n=e.imageUrl,r=a().kind===`moving`?`grabbing`:`crosshair`;return n!==t.e&&J(i,`src`,t.e=n),r!==t.t&&Ze(o,`cursor`,t.t=r),t},{e:void 0,t:void 0}),r})()}var go,_o,vo,yo,bo,xo,So,Co,wo=t((()=>{X(),G(),go=K(`<div class="relative overflow-hidden bg-slate-900 w-full h-full select-none"><img alt="manga page"class="w-full h-full object-contain pointer-events-none"><svg class="absolute inset-0 w-full h-full">`),_o=K(`<svg><line stroke=#9ca3af stroke-width=1 style=pointer-events:none></svg>`,!1,!0,!1),vo=K(`<svg><g><rect style=cursor:grab></rect><text font-size=10 fill=black style=pointer-events:none;user-select:none></text><text font-size=10 fill=white style=pointer-events:none;user-select:none></svg>`,!1,!0,!1),yo=K(`<svg><rect width=8 height=8 fill=white stroke=#7c3aed stroke-width=1.5></svg>`,!1,!0,!1),bo=K(`<svg><rect fill=rgba(16,185,129,0.1) stroke=#10b981 stroke-width=2 stroke-dasharray=4,2 style=pointer-events:none></svg>`,!1,!0,!1),xo=[`TL`,`T`,`TR`,`L`,`R`,`BL`,`B`,`BR`],So={TL:[0,0],T:[.5,0],TR:[1,0],L:[0,.5],R:[1,.5],BL:[0,1],B:[.5,1],BR:[1,1]},Co={TL:`nw-resize`,T:`n-resize`,TR:`ne-resize`,L:`w-resize`,R:`e-resize`,BL:`sw-resize`,B:`s-resize`,BR:`se-resize`},q([`mousedown`])}));function To(e){let t;return u(()=>{let n=e.selectedIndex;n!==null&&(t?.querySelector(`[data-bubble-idx="${n}"]`))?.scrollIntoView({behavior:`smooth`,block:`nearest`})}),(()=>{var n=Eo(),r=n.firstChild,i=r.firstChild,a=i.firstChild.nextSibling;a.nextSibling;var o=i.nextSibling,s=r.nextSibling;Y(i,()=>e.bubbles.length,a),Je(o,`click`,e.onAddBubble,!0),Y(o,P(Di,{class:`h-3 w-3`}),null),Y(o,P(yi,{class:`h-3 w-3`}),null);var c=t;return typeof c==`function`?$e(c,s):t=s,Y(s,P(L,{get when(){return e.bubbles.length>0},get fallback(){return Do()},get children(){return P(I,{get each(){return e.bubbles},children:t=>{let n=()=>e.selectedIndex===t.bubbleIndex;return(()=>{var r=Ao(),i=r.firstChild,a=i.firstChild;a.firstChild;var o=i.nextSibling;return r.$$click=()=>e.onSelect(n()?null:t.bubbleIndex),Y(a,()=>t.bubbleIndex,null),Y(i,P(L,{get when(){return t.isManuallyAdded},get children(){return Oo()}}),null),Y(i,P(L,{get when(){return t.isExcluded},get children(){return ko()}}),null),Y(o,()=>t.sourceText.slice(0,20)||`(empty)`),l(e=>{var i=t.bubbleIndex,s=`w-full border-b border-slate-100 px-3 py-2 text-left transition-colors ${n()?`border-l-2 border-l-violet-500 bg-violet-50`:`hover:bg-slate-50`} ${t.isExcluded?`opacity-50`:``}`,c=`font-mono text-xs font-medium ${n()?`text-violet-700`:`text-slate-500`}`,l=`mt-0.5 truncate text-xs ${t.isExcluded?`line-through text-slate-400`:`text-slate-600`}`;return i!==e.e&&J(r,`data-bubble-idx`,e.e=i),s!==e.t&&qe(r,e.t=s),c!==e.a&&qe(a,e.a=c),l!==e.o&&qe(o,e.o=l),e},{e:void 0,t:void 0,a:void 0,o:void 0}),r})()}})}})),n})()}var Eo,Do,Oo,ko,Ao,jo=t((()=>{X(),G(),la(),Eo=K(`<div class="flex flex-col h-full"><div class="flex items-center gap-2 border-b border-slate-100 px-3 py-2 shrink-0"><span class="flex-1 text-xs font-semibold uppercase tracking-wide text-slate-500">Bubbles (<!>)</span><button class="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium text-slate-600 hover:bg-slate-100 active:bg-slate-200 transition-colors"title="Draw a new bubble on the canvas"></button></div><div class="flex-1 overflow-y-auto">`),Do=K(`<div class="px-3 py-6 text-center text-xs text-slate-400">No bubbles detected`),Oo=K(`<span class="rounded bg-emerald-100 px-1 py-0.5 text-[10px] font-medium text-emerald-700">M`),ko=K(`<span class="rounded bg-slate-100 px-1 py-0.5 text-[10px] font-medium text-slate-500">×`),Ao=K(`<button><div class="flex items-center gap-1.5"><span>#</span></div><p>`),q([`click`])}));function Mo(e){return(()=>{var t=Po(),n=t.firstChild,r=n.nextSibling;return Y(n,()=>e.label),r.addEventListener(`change`,t=>e.onChange(parseFloat(t.currentTarget.value)||0)),r.$$input=t=>e.onInput(parseFloat(t.currentTarget.value)||0),l(()=>r.value=e.value),t})()}function No(e){let[t,n]=s(0),[r,i]=s(0),[a,o]=s(0),[c,d]=s(0),[f,p]=s(``),[m,h]=s(``),[_,v]=s(!1);return u(g(()=>e.bubble,()=>{let t=e.bubble;t&&(n(t.bubbleX),i(t.bubbleY),o(t.bubbleW),d(t.bubbleH),p(t.sourceText),h(t.translatedText),v(t.isExcluded))})),(()=>{var s=Fo();return s.firstChild,Y(s,P(L,{get when(){return e.bubble},get fallback(){return Io()},children:s=>(()=>{var u=Ro(),g=u.firstChild,y=g.firstChild;y.firstChild;var b=y.nextSibling,x=b.firstChild,S=g.nextSibling,C=S.firstChild.nextSibling,w=S.nextSibling,ee=w.firstChild.nextSibling,T=w.nextSibling,E=T.firstChild.nextSibling,D=T.nextSibling,O=D.firstChild,k=D.nextSibling.firstChild,A=k.firstChild;return Y(y,()=>s().bubbleIndex,null),Y(g,P(L,{get when(){return s().isManuallyAdded},get children(){return Lo()}}),b),Y(b,()=>Math.round(s().confidence*100),x),Y(C,P(Mo,{label:`X`,get value(){return t()},onInput:n,onChange:t=>e.onUpdate({bubbleX:t})}),null),Y(C,P(Mo,{label:`Y`,get value(){return r()},onInput:i,onChange:t=>e.onUpdate({bubbleY:t})}),null),Y(C,P(Mo,{label:`W`,get value(){return a()},onInput:o,onChange:t=>e.onUpdate({bubbleW:t})}),null),Y(C,P(Mo,{label:`H`,get value(){return c()},onInput:d,onChange:t=>e.onUpdate({bubbleH:t})}),null),ee.addEventListener(`blur`,t=>e.onUpdate({sourceText:t.currentTarget.value})),ee.$$input=e=>p(e.currentTarget.value),E.addEventListener(`blur`,t=>e.onUpdate({translatedText:t.currentTarget.value})),E.$$input=e=>h(e.currentTarget.value),O.addEventListener(`change`,t=>{let n=t.currentTarget.checked;v(n),e.onUpdate({isExcluded:n})}),Je(k,`click`,e.onDelete,!0),Y(k,P(qi,{class:`h-3.5 w-3.5`}),A),l(()=>ee.value=f()),l(()=>E.value=m()),l(()=>O.checked=_()),u})()}),null),s})()}var Po,Fo,Io,Lo,Ro,zo=t((()=>{X(),G(),la(),Po=K(`<label class="flex flex-col gap-0.5"><span class="text-[10px] text-slate-400"></span><input type=number step=0.1 class="rounded border border-slate-200 px-2 py-1 text-xs focus:border-violet-400 focus:outline-none">`),Fo=K(`<div class="flex h-full flex-col"><div class="shrink-0 border-b border-slate-100 px-3 py-2"><span class="text-xs font-semibold uppercase tracking-wide text-slate-500">Editor`),Io=K(`<div class="flex flex-1 items-center justify-center text-xs text-slate-400">Select a bubble to edit`),Lo=K(`<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700">Manual`),Ro=K(`<div class="flex flex-1 flex-col gap-4 overflow-y-auto p-3"><div class="flex items-center gap-2"><span class="text-sm font-medium text-slate-700">Bubble #</span><span class="ml-auto text-[10px] text-slate-400">% conf</span></div><div><p class="mb-1.5 text-xs font-medium text-slate-500">Position &amp; Size (px)</p><div class="grid grid-cols-2 gap-1.5"></div></div><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Source</span><textarea rows=3 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Translation</span><textarea rows=4 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><div class="flex items-center gap-2"><input id=exclude-check type=checkbox class="h-3.5 w-3.5 rounded accent-violet-600"><label for=exclude-check class="cursor-pointer text-xs text-slate-600">Exclude from render</label></div><div class="mt-auto border-t border-slate-100 pt-3"><button class="flex w-full items-center justify-center gap-1.5 rounded-lg bg-red-50 px-3 py-2 text-xs font-medium text-red-600 transition-colors hover:bg-red-100 active:bg-red-200">Delete bubble`),q([`input`,`click`])})),Bo=n({StudioPage:()=>Vo});function Vo(){let e=dn(),t=ln(),[n]=p(()=>e.id,Ma),[r,{refetch:i}]=p(()=>e.id,Pa),[a,o]=s(null),[c,u]=s(`result`),[d,f]=s(!1),[m,h]=s(!1),[g,_]=s(!1),v=()=>r()??[],y=()=>{let e=a();return e===null?null:v().find(t=>t.bubbleIndex===e)??null};function b(e){o(e===a()?null:e)}async function x(t,n,r){let a=v().find(e=>e.bubbleIndex===t);a&&(await Ia(e.id,t,{bubbleX:a.bubbleX+n,bubbleY:a.bubbleY+r,bubbleW:a.bubbleW,bubbleH:a.bubbleH}),i())}async function S(t,n,r,a,o){await Ia(e.id,t,{bubbleX:n,bubbleY:r,bubbleW:a,bubbleH:o}),i()}async function C(t,n,r,a){let s=await Fa(e.id,{x:t,y:n,w:r,h:a});await i(),o(s.bubbleIndex)}async function w(t){let n=y();n&&(await Ia(e.id,n.bubbleIndex,t),i())}async function ee(){let t=y();t&&(await La(e.id,t.bubbleIndex),o(null),i())}async function T(){f(!0);try{await Ra(e.id),await i()}finally{f(!1)}}async function E(){h(!0);try{await za(e.id),await i()}finally{h(!1)}}async function D(){_(!0);try{await Ba(e.id),await i()}finally{_(!1)}}let O=()=>({bubbles:v(),selectedIndex:a(),onSelect:b,onMove:x,onResize:S,onDraw:C});return(()=>{var r=Wo(),i=r.firstChild,o=i.firstChild,s=o.nextSibling,f=s.nextSibling.nextSibling,p=f.firstChild,h=f.nextSibling,_=h.firstChild,x=h.nextSibling,S=x.firstChild;return o.$$click=()=>t(`/jobs`),Y(o,P(Zn,{class:`h-4 w-4`})),Y(i,P(L,{get when(){return n()},get fallback(){return Go()},children:e=>[(()=>{var t=Ko();return Y(t,()=>e().title),t})(),P(eo,{get status(){return e().status}})]}),s),Y(s,()=>[`original`,`result`,`sidebyside`].map(e=>(()=>{var t=qo();return t.$$click=()=>u(e),Y(t,e===`original`?`Original`:e===`result`?`Result`:`Side by side`),l(()=>qe(t,`px-2.5 py-1.5 font-medium transition-colors ${c()===e?`bg-violet-600 text-white`:`bg-white text-slate-600 hover:bg-slate-50`}`)),t})())),f.$$click=T,Y(f,P(L,{get when(){return d()},get fallback(){return P(Fi,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),p),h.$$click=E,Y(h,P(L,{get when(){return m()},get fallback(){return P(Ui,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),_),x.$$click=D,Y(x,P(L,{get when(){return g()},get fallback(){return P(ji,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),S),Y(r,P(L,{get when(){return n.loading},get children(){return Ho()}}),null),Y(r,P(L,{get when(){return n.error},get children(){var e=Uo();return e.firstChild,Y(e,()=>String(n.error),null),e}}),null),Y(r,P(L,{get when(){return St(()=>!n.loading&&!n.error)()&&n()},children:t=>(()=>{var n=Yo(),r=n.firstChild,i=r.nextSibling,o=i.nextSibling;return Y(r,P(To,{get bubbles(){return v()},get selectedIndex(){return a()},onSelect:b,onAddBubble:()=>{}})),Y(i,P(ve,{get children(){return[P(ye,{get when(){return c()===`original`},get children(){return P(ho,F(O,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}}),P(ye,{get when(){return c()===`result`},get children(){return P(L,{get when(){return t().resultImagePath},get fallback(){return(()=>{var e=Xo(),t=e.firstChild;return Y(e,P($r,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){return P(ho,F(O,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}})}}),P(ye,{get when(){return c()===`sidebyside`},get children(){var n=Jo(),r=n.firstChild,i=r.nextSibling;return Y(r,P(ho,F(O,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))),Y(i,P(ho,F(O,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))),n}})]}})),Y(o,P(No,{get bubble(){return y()},onUpdate:w,onDelete:ee})),n})()}),null),l(e=>{var t=d(),n=m(),r=g();return t!==e.e&&(f.disabled=e.e=t),n!==e.t&&(h.disabled=e.t=n),r!==e.a&&(x.disabled=e.a=r),e},{e:void 0,t:void 0,a:void 0}),r})()}var Ho,Uo,Wo,Go,Ko,qo,Jo,Yo,Xo,Zo=t((()=>{X(),G(),Rn(),la(),Qa(),wo(),jo(),zo(),po(),Ho=K(`<div class="flex flex-1 items-center justify-center"><p class="text-sm text-slate-400">Loading job…`),Uo=K(`<div class="m-6 rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load job: `),Wo=K(`<div class="flex h-screen flex-col bg-slate-50"><header class="flex shrink-0 items-center gap-2 border-b border-slate-200 bg-white px-3 py-2 shadow-sm"><button class="flex items-center gap-1 rounded p-1 text-slate-500 hover:bg-slate-100 transition-colors"title="Back to jobs"></button><div class="ml-4 flex overflow-hidden rounded-lg border border-slate-200 text-xs"></div><div class=flex-1></div><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-detect bubbles">Re-detect</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title=Re-translate>Re-translate</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-render image">Re-render`),Go=K(`<div class="h-4 w-40 animate-pulse rounded bg-slate-200">`),Ko=K(`<h1 class="max-w-xs truncate text-sm font-semibold text-slate-800">`),qo=K(`<button>`),Jo=K(`<div class="flex h-full w-full"><div class="flex-1 overflow-hidden border-r border-slate-700"></div><div class="flex-1 overflow-hidden">`),Yo=K(`<div class="flex flex-1 overflow-hidden"><aside class="flex w-52 shrink-0 flex-col border-r border-slate-200 bg-white"></aside><main class="relative flex flex-1 overflow-hidden"></main><aside class="flex w-64 shrink-0 flex-col border-l border-slate-200 bg-white">`),Xo=K(`<div class="flex flex-1 flex-col items-center justify-center gap-3 text-slate-400"><p class=text-sm>No result image yet</p><p class=text-xs>Run Re-render to generate the translated image.`),q([`click`])}));function Qo(e){return u(()=>{if(!e.open){document.body.style.overflow=``;return}document.body.style.overflow=`hidden`;let t=t=>{t.key===`Escape`&&e.onClose()};return document.addEventListener(`keydown`,t),()=>{document.body.style.overflow=``,document.removeEventListener(`keydown`,t)}}),P(L,{get when(){return e.open},get children(){var t=$o(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>{t.target===t.currentTarget&&e.onClose()},Y(r,()=>e.title),Je(i,`click`,e.onClose,!0),Y(i,P(Zi,{class:`h-4 w-4`})),Y(n,()=>e.children,null),t}})}var $o,es=t((()=>{X(),G(),la(),$o=K(`<div role=dialog aria-modal=true aria-labelledby=modal-title class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"><div class="w-full max-w-md rounded-2xl bg-white p-6 shadow-xl"><div class="mb-4 flex items-center justify-between"><h2 id=modal-title class="text-base font-semibold text-slate-800"></h2><button class="rounded-lg p-1 text-slate-400 hover:bg-slate-100 hover:text-slate-600"aria-label=Close>`),q([`click`])}));function ts(e){return P(Qo,{get open(){return e.open},get title(){return e.title},get onClose(){return e.onCancel},get children(){return[(()=>{var t=ns();return Y(t,()=>e.message),t})(),(()=>{var t=rs(),n=t.firstChild,r=n.nextSibling;return Je(n,`click`,e.onCancel,!0),Je(r,`click`,e.onConfirm,!0),Y(r,(()=>{var t=St(()=>!!e.loading);return()=>t()?`Deleting…`:e.confirmLabel??`Delete`})()),l(t=>{var i=e.loading,a=e.confirmClass??`rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:opacity-50`,o=e.loading;return i!==t.e&&(n.disabled=t.e=i),a!==t.t&&qe(r,t.t=a),o!==t.a&&(r.disabled=t.a=o),t},{e:void 0,t:void 0,a:void 0}),t})()]}})}var ns,rs,is=t((()=>{X(),es(),ns=K(`<p class="mb-6 text-sm text-slate-600">`),rs=K(`<div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 disabled:opacity-50">Cancel</button><button>`),q([`click`])})),as=n({LibraryPage:()=>os});function os(){let e=ln(),[t,{refetch:n}]=p(Va),[r,{refetch:i}]=p(()=>Ga()),a=()=>(r()??[]).filter(e=>!e.volumeId),[o,c]=s(null),[u,d]=s(``),[f,m]=s(``);function h(){d(``),m(``),c({mode:`create`})}function g(e){d(e.title),m(e.synopsis??``),c({mode:`edit`,vol:e})}let[_,v]=s(null),[y,b]=s(``),[x,S]=s(``),[C,w]=s(void 0);function ee(){b(``),S(``),w(void 0),v({mode:`create`})}function T(e){b(e.title),S(e.chapterNumber),w(e.volumeId),v({mode:`edit`,ch:e})}let[E,D]=s(null),[O,k]=s(null),[A,j]=s(!1),[te,M]=s(null);async function ne(){j(!0),M(null);try{let e=o();if(!e)return;e.mode===`create`?await Ha({title:u(),synopsis:f()||void 0}):await Ua(e.vol.id,{title:u(),synopsis:f()||void 0}),c(null),n()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function re(){M(null);try{let e=E();if(!e)return;await Wa(e.id),D(null),n()}catch(e){M(e instanceof Error?e.message:String(e)),D(null)}}async function ie(){j(!0),M(null);try{let e=_();if(!e)return;e.mode===`create`?await Ka({title:y(),chapterNumber:x(),volumeId:C()}):await qa(e.ch.id,{title:y(),chapterNumber:x(),volumeId:C()??null}),v(null),i()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function N(){M(null);try{let e=O();if(!e)return;await Ja(e.id),k(null),i()}catch(e){M(e instanceof Error?e.message:String(e)),k(null)}}return(()=>{var n=ms(),i=n.firstChild,s=i.firstChild,p=s.nextSibling.nextSibling.firstChild,j=p.firstChild,ae=p.nextSibling,oe=ae.firstChild,se=i.nextSibling;se.firstChild;var ce=se.nextSibling;return ce.firstChild,Y(n,P(L,{get when(){return te()},get children(){var e=ss(),t=e.firstChild,n=t.nextSibling;return Y(t,te),n.$$click=()=>M(null),e}}),i),Y(s,P(tr,{class:`h-5 w-5 text-violet-600`})),p.$$click=h,Y(p,P(Di,{class:`h-3.5 w-3.5`}),j),ae.$$click=ee,Y(ae,P(Di,{class:`h-3.5 w-3.5`}),oe),Y(se,P(L,{get when(){return t.loading},get children(){var e=cs();return Y(e,()=>Array.from({length:4}).map(()=>hs())),e}}),null),Y(se,P(L,{get when(){return t.error},get children(){return ls()}}),null),Y(se,P(L,{get when(){return St(()=>!t.loading)()&&!t.error},get children(){return P(L,{get when(){return(t()??[]).length>0},get fallback(){return(()=>{var e=gs(),t=e.firstChild;return Y(e,P(Gr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var n=cs();return Y(n,P(I,{get each(){return t()},children:t=>(()=>{var n=_s(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling,s=o.firstChild,c=s.nextSibling.firstChild,l=c.nextSibling,u=l.firstChild;return i.$$click=e=>{e.stopPropagation(),g(t)},Y(i,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),a.$$click=e=>{e.stopPropagation(),D(t)},Y(a,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),o.$$click=()=>e(`/library/${t.id}`),Y(s,P(tr,{class:`h-6 w-6 text-violet-500`})),Y(c,()=>t.title),Y(l,()=>t.chapterCount??0,u),Y(o,P(lr,{class:`ml-auto h-4 w-4 shrink-0 text-slate-300 transition group-hover:translate-x-0.5 group-hover:text-slate-500`}),null),n})()})),n}})}}),null),Y(ce,P(L,{get when(){return r.loading},get children(){var e=us();return Y(e,()=>Array.from({length:3}).map(()=>vs())),e}}),null),Y(ce,P(L,{get when(){return!r.loading},get children(){return P(L,{get when(){return a().length>0},get fallback(){return ys()},get children(){var t=ds();return Y(t,P(I,{get each(){return a()},children:t=>(()=>{var n=bs(),r=n.firstChild,i=r.firstChild;i.firstChild;var a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=r.nextSibling.firstChild,l=c.nextSibling;return r.$$click=()=>e(`/library/chapters/${t.id}`),Y(i,()=>t.chapterNumber,null),Y(a,()=>t.title),Y(o,()=>t.pageCount??0,s),Y(r,P(lr,{class:`h-4 w-4 text-slate-300`}),null),c.$$click=()=>T(t),Y(c,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),l.$$click=()=>k(t),Y(l,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),n})()})),t}})}}),null),Y(n,P(Qo,{get open(){return o()!==null},get title(){return o()?.mode===`create`?`New Volume`:`Edit Volume`},onClose:()=>c(null),get children(){var e=fs(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>d(e.currentTarget.value),i.$$input=e=>m(e.currentTarget.value),a.$$click=()=>c(null),o.$$click=ne,Y(o,()=>A()?`Saving…`:`Save`),l(()=>o.disabled=A()||!u().trim()),l(()=>n.value=u()),l(()=>i.value=f()),e}}),null),Y(n,P(Qo,{get open(){return _()!==null},get title(){return _()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>v(null),get children(){var e=ps(),n=e.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling,s=o.firstChild.nextSibling;s.firstChild;var c=o.nextSibling.firstChild,u=c.nextSibling;return r.$$input=e=>b(e.currentTarget.value),a.$$input=e=>S(e.currentTarget.value),s.addEventListener(`change`,e=>{let t=e.currentTarget.value;w(t?Number(t):void 0)}),Y(s,P(I,{get each(){return t()??[]},children:e=>(()=>{var t=xs();return Y(t,()=>e.title),l(()=>t.value=e.id),t})()}),null),c.$$click=()=>v(null),u.$$click=ie,Y(u,()=>A()?`Saving…`:`Save`),l(()=>u.disabled=A()||!y().trim()||!x().trim()),l(()=>r.value=y()),l(()=>a.value=x()),l(()=>s.value=C()??``),e}}),null),Y(n,P(ts,{get open(){return E()!==null},title:`Delete Volume`,get message(){return`Delete "${E()?.title}"? Chapters inside will be ungrouped but not deleted.`},onConfirm:re,onCancel:()=>D(null)}),null),Y(n,P(ts,{get open(){return O()!==null},title:`Delete Chapter`,get message(){return`Delete "${O()?.title}"? This cannot be undone.`},onConfirm:N,onCancel:()=>k(null)}),null),n})()}var ss,cs,ls,us,ds,fs,ps,ms,hs,gs,_s,vs,ys,bs,xs,Ss=t((()=>{X(),G(),Rn(),la(),Qa(),es(),is(),ss=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),cs=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">`),ls=K(`<p class="text-sm text-red-500">Failed to load volumes.`),us=K(`<div class=space-y-2>`),ds=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),fs=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Volume title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3 placeholder="Brief description…"></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),ps=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Volume (optional)</label><select class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"><option value>No volume / Standalone</option></select></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),ms=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Library</h1><div class="ml-auto flex gap-2"><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> New Volume</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 hover:bg-slate-50"> New Chapter</button></div></div><section class=mb-10><h2 class="mb-3 text-sm font-semibold text-slate-600">Volumes</h2></section><section><h2 class="mb-3 text-sm font-semibold text-slate-600">Standalone Chapters`),hs=K(`<div class="h-32 animate-pulse rounded-2xl bg-slate-200">`),gs=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-16 text-slate-400"><p class=text-sm>No volumes yet.`),_s=K(`<div class="group relative flex flex-col gap-2 rounded-2xl bg-white p-4 text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-slate-50"title="Edit volume"></button><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-red-50"title="Delete volume"></button></div><button class="flex flex-col gap-2 text-left"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-violet-50"></div><div class="min-w-0 pr-10"><p class="truncate text-sm font-semibold text-slate-800"></p><p class="text-xs text-slate-500"> chapters`),vs=K(`<div class="h-12 animate-pulse rounded-xl bg-slate-200">`),ys=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-12 text-slate-400"><p class=text-sm>No standalone chapters.`),bs=K(`<li class="group flex items-center"><button class="flex flex-1 items-center gap-4 px-5 py-3.5 text-left transition hover:bg-slate-50"><span class="w-14 shrink-0 text-right text-xs font-mono text-slate-400">#</span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-3 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),xs=K(`<option>`),q([`click`,`input`])})),Cs=n({VolumePage:()=>ws});function ws(){let e=dn(),t=ln(),n=()=>Number(e.volumeId),[r,{refetch:i}]=p(Va),a=()=>r()?.find(e=>e.id===n()),[o,{refetch:c}]=p(n,e=>Ga({volumeId:e})),[u,d]=s(!1),[f,m]=s(``),[h,g]=s(``),[_,v]=s(!1),[y,b]=s(null);function x(){let e=a();e&&(m(e.title),g(e.synopsis??``),d(!0))}async function S(){v(!0),b(null);try{await Ua(n(),{title:f(),synopsis:h()||void 0}),d(!1),i()}catch(e){b(e instanceof Error?e.message:String(e))}finally{v(!1)}}let[C,w]=s(!1);async function ee(){b(null);try{await Wa(n()),w(!1),t(`/library`)}catch(e){b(e instanceof Error?e.message:String(e)),w(!1)}}let[T,E]=s(null),[D,O]=s(``),[k,A]=s(``),[j,te]=s(!1);function M(){O(``),A(``),E({mode:`create`})}function ne(e){O(e.title),A(e.chapterNumber),E({mode:`edit`,ch:e})}async function re(){te(!0),b(null);try{let e=T();if(!e)return;e.mode===`create`?await Ka({title:D(),chapterNumber:k(),volumeId:n()}):await qa(e.ch.id,{title:D(),chapterNumber:k()}),E(null),c()}catch(e){b(e instanceof Error?e.message:String(e))}finally{te(!1)}}let[ie,N]=s(null);async function ae(){b(null);try{let e=ie();if(!e)return;await Ja(e.id),N(null),c()}catch(e){b(e instanceof Error?e.message:String(e)),N(null)}}async function oe(e,t){b(null);try{let n=o()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];if(!i)return;await Promise.all([qa(e.id,{sortOrder:i.sortOrder}),qa(i.id,{sortOrder:e.sortOrder})]),c()}catch(e){b(e instanceof Error?e.message:String(e))}}return(()=>{var e=js(),n=e.firstChild,r=n.firstChild,i=n.nextSibling.firstChild,s=i.nextSibling,c=s.nextSibling.firstChild,p=c.nextSibling,v=p.nextSibling,te=v.firstChild;return Y(e,P(L,{get when(){return y()},get children(){var e=Ts(),t=e.firstChild,n=t.nextSibling;return Y(t,y),n.$$click=()=>b(null),e}}),n),n.$$click=()=>t(`/library`),Y(n,P(Zn,{class:`h-4 w-4`}),r),Y(i,P(tr,{class:`h-5 w-5 text-violet-600`})),Y(s,P(L,{get when(){return a()},get fallback(){return Ms()},children:e=>[(()=>{var t=Ns();return Y(t,()=>e().title),t})(),P(L,{get when(){return e().synopsis},get children(){var t=Ps();return Y(t,()=>e().synopsis),t}})]})),c.$$click=x,Y(c,P(Ci,{class:`h-4 w-4`})),p.$$click=()=>w(!0),Y(p,P(qi,{class:`h-4 w-4`})),v.$$click=M,Y(v,P(Di,{class:`h-3.5 w-3.5`}),te),Y(e,P(L,{get when(){return o.loading},get children(){var e=Es();return Y(e,()=>Array.from({length:4}).map(()=>Fs())),e}}),null),Y(e,P(L,{get when(){return o.error},get children(){return Ds()}}),null),Y(e,P(L,{get when(){return St(()=>!o.loading)()&&!o.error},get children(){return P(L,{get when(){return(o()??[]).length>0},get fallback(){return(()=>{var e=Is(),t=e.firstChild;return Y(e,P(Vr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var e=Os();return Y(e,P(I,{get each(){return o()},children:(e,n)=>{let r=()=>o()??[],i=()=>n()===0,a=()=>n()===r().length-1;return(()=>{var n=Ls(),r=n.firstChild,o=r.firstChild,s=o.nextSibling,c=r.nextSibling,u=c.firstChild,d=u.nextSibling,f=d.nextSibling,p=f.firstChild,m=c.nextSibling.firstChild,h=m.nextSibling;return o.$$click=()=>oe(e,`up`),Y(o,P(pr,{class:`h-3.5 w-3.5`})),s.$$click=()=>oe(e,`down`),Y(s,P(ar,{class:`h-3.5 w-3.5`})),c.$$click=()=>t(`/library/chapters/${e.id}`),Y(u,()=>e.chapterNumber),Y(d,()=>e.title),Y(f,()=>e.pageCount??0,p),Y(c,P(lr,{class:`h-4 w-4 text-slate-300`}),null),m.$$click=()=>ne(e),Y(m,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),h.$$click=()=>N(e),Y(h,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),l(e=>{var t=i(),n=a();return t!==e.e&&(o.disabled=e.e=t),n!==e.t&&(s.disabled=e.t=n),e},{e:void 0,t:void 0}),n})()}})),e}})}}),null),Y(e,P(Qo,{get open(){return u()},title:`Edit Volume`,onClose:()=>d(!1),get children(){var e=ks(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>m(e.currentTarget.value),i.$$input=e=>g(e.currentTarget.value),a.$$click=()=>d(!1),o.$$click=S,Y(o,()=>_()?`Saving…`:`Save`),l(()=>o.disabled=_()||!f().trim()),l(()=>n.value=f()),l(()=>i.value=h()),e}}),null),Y(e,P(Qo,{get open(){return T()!==null},get title(){return T()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>E(null),get children(){var e=As(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>O(e.currentTarget.value),i.$$input=e=>A(e.currentTarget.value),a.$$click=()=>E(null),o.$$click=re,Y(o,()=>j()?`Saving…`:`Save`),l(()=>o.disabled=j()||!D().trim()||!k().trim()),l(()=>n.value=D()),l(()=>i.value=k()),e}}),null),Y(e,P(ts,{get open(){return C()},title:`Delete Volume`,get message(){return`Delete "${a()?.title}"? This will not delete the chapters — they will just be ungrouped.`},onConfirm:ee,onCancel:()=>w(!1)}),null),Y(e,P(ts,{get open(){return ie()!==null},title:`Delete Chapter`,get message(){return`Delete "${ie()?.title}"? This cannot be undone.`},onConfirm:ae,onCancel:()=>N(null)}),null),e})()}var Ts,Es,Ds,Os,ks,As,js,Ms,Ns,Ps,Fs,Is,Ls,Rs=t((()=>{X(),G(),Rn(),la(),Qa(),es(),is(),Ts=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),Es=K(`<div class=space-y-2>`),Ds=K(`<p class="text-sm text-red-500">Failed to load chapters.`),Os=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),ks=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),As=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),js=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"> Library</button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><div class="flex items-center gap-2"><button class="rounded-lg p-1.5 text-slate-400 hover:bg-slate-100 hover:text-slate-600"title="Edit volume"></button><button class="rounded-lg p-1.5 text-slate-400 hover:bg-red-50 hover:text-red-500"title="Delete volume"></button><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add Chapter`),Ms=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),Ns=K(`<h1 class="text-xl font-semibold text-slate-800">`),Ps=K(`<p class="text-sm text-slate-500">`),Fs=K(`<div class="h-14 animate-pulse rounded-xl bg-slate-200">`),Is=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-20 text-slate-400"><p class=text-sm>No chapters yet. Add the first one.`),Ls=K(`<li class="group flex items-center"><div class="flex flex-col items-center px-2"><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button></div><button class="flex flex-1 items-center gap-4 py-4 pr-4 text-left transition hover:bg-slate-50"><span class="w-16 shrink-0 rounded-lg bg-slate-100 px-2 py-1 text-center text-xs font-mono text-slate-600"></span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-2 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),q([`click`,`input`])})),zs=n({ChapterPage:()=>Hs});function Bs(e){switch(e.status){case`done`:return P(_r,{class:`h-4 w-4 text-green-500`});case`processing`:return P(kr,{class:`h-4 w-4 text-yellow-500`});case`error`:return P(Tr,{class:`h-4 w-4 text-red-500`});default:return P(kr,{class:`h-4 w-4 text-slate-400`})}}function Vs(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=Us(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=s.nextSibling,u=o.nextSibling,d=r.nextSibling.firstChild;return Je(r,`click`,e.onClick,!0),Y(a,P(Bs,{get status(){return e.job.status}})),s.$$click=t=>{t.stopPropagation(),e.onMove(`up`)},Y(s,P(pr,{class:`h-3.5 w-3.5 text-slate-600`})),c.$$click=t=>{t.stopPropagation(),e.onMove(`down`)},Y(c,P(ar,{class:`h-3.5 w-3.5 text-slate-600`})),u.$$click=t=>{t.stopPropagation(),e.onUnassign()},Y(u,P(Zi,{class:`h-3.5 w-3.5`})),Y(d,()=>e.job.title),l(n=>{var r=t(),a=e.job.title,o=e.isFirst,l=e.isLast;return r!==n.e&&J(i,`src`,n.e=r),a!==n.t&&J(i,`alt`,n.t=a),o!==n.a&&(s.disabled=n.a=o),l!==n.o&&(c.disabled=n.o=l),n},{e:void 0,t:void 0,a:void 0,o:void 0}),n})()}function Hs(){let e=dn(),t=ln(),n=()=>Number(e.chapterId),[r]=p(()=>Ga()),i=()=>r()?.find(e=>e.id===n()),[a,{refetch:o}]=p(n,Ya),[c,u]=s(!1),[d,f]=s([]),[m,h]=s(new Set),[g,_]=s(!1),[v,y]=s(!1);async function b(){_(!0),h(new Set),u(!0);try{let e=[],t=1;for(;;){let n=await ja({page:t,pageSize:200});if(e.push(...n.items.filter(e=>!e.chapterId)),n.items.length<200)break;t++}f(e)}finally{_(!1)}}function x(e){h(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}async function S(){y(!0);try{let e=[...m()],t=a()?.length??0;await Promise.all(e.map((e,r)=>Na(e,{chapterId:n(),pageOrder:t+r}))),u(!1),h(new Set),o()}finally{y(!1)}}async function C(e,t){let n=a()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];i&&(await Promise.all([Na(e.id,{pageOrder:i.pageOrder}),Na(i.id,{pageOrder:e.pageOrder})]),o())}async function w(e){await Na(e,{chapterId:null}),o()}return(()=>{var e=Xs(),n=e.firstChild,r=n.nextSibling.firstChild,o=r.nextSibling,s=o.nextSibling,f=s.firstChild;return n.$$click=()=>{let e=i();e?.volumeId?t(`/library/${e.volumeId}`):t(`/library`)},Y(n,P(Zn,{class:`h-4 w-4`}),null),Y(n,P(L,{get when(){return i()?.volumeId},fallback:`Library`,children:`Volume`}),null),Y(r,P(ri,{class:`h-5 w-5 text-violet-600`})),Y(o,P(L,{get when(){return i()},get fallback(){return Zs()},children:e=>(()=>{var t=Qs(),n=t.firstChild.nextSibling;return n.nextSibling,Y(t,()=>e().chapterNumber,n),Y(t,()=>e().title,null),t})()})),s.$$click=b,Y(s,P(Lr,{class:`h-3.5 w-3.5`}),f),Y(e,P(L,{get when(){return a.loading},get children(){var e=Ws();return Y(e,()=>Array.from({length:8}).map(()=>$s())),e}}),null),Y(e,P(L,{get when(){return a.error},get children(){return Gs()}}),null),Y(e,P(L,{get when(){return St(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return(a()??[]).length>0},get fallback(){return(()=>{var e=ec(),t=e.firstChild;return Y(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var e=Ws();return Y(e,P(I,{get each(){return a()},children:(e,n)=>{let r=()=>a()??[];return P(Vs,{job:e,get isFirst(){return n()===0},get isLast(){return n()===r().length-1},onMove:t=>C(e,t),onUnassign:()=>w(e.id),onClick:()=>t(`/jobs/${e.id}`)})}})),e}})}}),null),Y(e,P(Qo,{get open(){return c()},title:`Add Pages to Chapter`,onClose:()=>u(!1),get children(){var e=Ys(),t=e.firstChild.nextSibling,n=t.firstChild,r=n.nextSibling;return Y(e,P(L,{get when(){return g()},get children(){var e=Ks();return Y(e,()=>Array.from({length:4}).map(()=>tc())),e}}),t),Y(e,P(L,{get when(){return St(()=>!g())()&&d().length===0},get children(){return qs()}}),t),Y(e,P(L,{get when(){return St(()=>!g())()&&d().length>0},get children(){var e=Js();return Y(e,P(I,{get each(){return d()},children:e=>{let t=()=>m().has(e.id);return(()=>{var n=nc(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.firstChild,s=o.nextSibling;return i.addEventListener(`change`,()=>x(e.id)),Y(o,()=>e.title),Y(s,()=>new Date(e.createdAt).toLocaleDateString()),Y(r,P(Bs,{get status(){return e.status}}),null),l(t=>{var n=Xa(e.id),r=e.title;return n!==t.e&&J(a,`src`,t.e=n),r!==t.t&&J(a,`alt`,t.t=r),t},{e:void 0,t:void 0}),l(()=>i.checked=t()),n})()}})),e}}),t),n.$$click=()=>u(!1),r.$$click=S,Y(r,(()=>{var e=St(()=>!!v());return()=>e()?`Assigning…`:`Assign ${m().size>0?m().size:``} selected`})()),l(()=>r.disabled=v()||m().size===0),e}}),null),e})()}var Us,Ws,Gs,Ks,qs,Js,Ys,Xs,Zs,Qs,$s,ec,tc,nc,rc=t((()=>{X(),G(),Rn(),la(),Qa(),es(),Us=K(`<div class="group relative flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><button class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><span class="absolute left-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow"></span><div class="absolute right-2 top-2 flex flex-col gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move up"></button><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move down"></button></div><button class="absolute bottom-2 right-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500/90 text-white shadow opacity-0 transition-opacity group-hover:opacity-100 hover:bg-red-600"title="Remove from chapter"></button></button><div class=p-3><p class="truncate text-xs font-medium text-slate-700">`,!0,!1,!1),Ws=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),Gs=K(`<p class="text-sm text-red-500">Failed to load pages.`),Ks=K(`<div class=space-y-2>`),qs=K(`<p class="py-6 text-center text-sm text-slate-400">No unassigned pages found.`),Js=K(`<ul class="max-h-80 overflow-y-auto divide-y divide-slate-100 rounded-lg border border-slate-200">`),Ys=K(`<div class="flex flex-col gap-3"><p class="text-xs text-slate-500">Select unassigned jobs to add to this chapter.</p><div class="flex justify-end gap-2 pt-1"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Xs=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"></button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><button class="ml-auto flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add pages`),Zs=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),Qs=K(`<h1 class="text-xl font-semibold text-slate-800">Ch. <!> — `),$s=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),ec=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No pages in this chapter yet.`),tc=K(`<div class="h-14 animate-pulse rounded-lg bg-slate-200">`),nc=K(`<li><label class="flex cursor-pointer items-center gap-3 px-3 py-2.5 hover:bg-slate-50"><input type=checkbox class="h-4 w-4 accent-violet-600"><img class="h-10 w-8 rounded object-cover bg-slate-100"loading=lazy><div class="min-w-0 flex-1"><p class="truncate text-sm font-medium text-slate-800"></p><p class="text-xs text-slate-400">`,!0,!1,!1),q([`click`])}));X(),G(),Rn();var ic=_e(()=>Promise.resolve().then(()=>(po(),$a)).then(e=>({default:e.JobsListPage}))),ac=_e(()=>Promise.resolve().then(()=>(Zo(),Bo)).then(e=>({default:e.StudioPage}))),oc=_e(()=>Promise.resolve().then(()=>(Ss(),as)).then(e=>({default:e.LibraryPage}))),sc=_e(()=>Promise.resolve().then(()=>(Rs(),Cs)).then(e=>({default:e.VolumePage}))),cc=_e(()=>Promise.resolve().then(()=>(rc(),zs)).then(e=>({default:e.ChapterPage})));function lc(){return P(jn,{get children(){return P(yn,{path:`/`,component:e=>P(ma,{get children(){return e.children}}),get children(){return[P(yn,{path:`/`,component:Ea}),P(yn,{path:`/jobs`,component:ic}),P(yn,{path:`/jobs/:id`,component:ac}),P(yn,{path:`/library`,component:oc}),P(yn,{path:`/library/:volumeId`,component:sc}),P(yn,{path:`/library/chapters/:chapterId`,component:cc})]}})}})}var uc=new Map;window.AppBridge={mount(e,t={}){if(uc.has(e))return;let n=We(()=>P(lc,{}),e);uc.set(e,n)},unmount(e){uc.get(e)?.(),uc.delete(e)}}})();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard the result pane in side-by-side mode.

Unlike result-only mode, the side-by-side branch always mounts /result. Processing or failed jobs without a result image therefore show a broken image instead of the existing placeholder.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update the side-by-side result-pane
rendering in the relevant page/component branch so `/result` is mounted only
when a result image exists. For processing or failed jobs without an image,
reuse the existing placeholder rendering used by result-only mode instead of
creating a broken image.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Show N/A for manual bubble confidence.

BubbleEditor always renders Math.round(confidence * 100), even for manually added bubbles. These entries display 0% or NaN instead of the documented N/A.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update the BubbleEditor confidence
display so manually added bubbles render the documented “N/A” instead of
calculating a percentage from confidence. Preserve the rounded percentage output
for automatically detected bubbles, using the existing manual-bubble indicator
and BubbleEditor logic to select the display.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove nested buttons from chapter cards.

The chapter-page card renders move-up, move-down, and remove buttons inside an outer button. Nested interactive controls are invalid and prevent reliable keyboard and click behavior. Use a non-interactive wrapper with sibling buttons.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update the chapter card markup generated
by the ChapterPage component so the outer card is a non-interactive wrapper
rather than a button. Keep the move-up, move-down, and remove controls as
sibling buttons within that wrapper, preserving their existing handlers,
disabled states, and styling while ensuring no button is nested inside another
button.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Wire the Studio “add bubble” control.

The button receives e.onAddBubble, but StudioPage supplies onAddBubble: () => {}. Clicking the advertised control is a no-op; connect it to the draw-mode/creation path or remove the dead button.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Connect StudioPage’s onAddBubble
callback to the existing draw-mode or bubble-creation flow used by the Studio
controls, so the add-bubble button performs the advertised action instead of
invoking an empty function. Update the StudioPage wiring and preserve the button
only if it is now functional; otherwise remove the dead control.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Wait for background actions to complete before refreshing Studio.

The portal contract returns 202 Accepted plus a job ID for re-detect, re-translate, and re-render, but these handlers refresh once immediately and re-enable their buttons. Track the returned job until completion before refreshing or allowing another mutation; otherwise the editor shows stale data and overlapping actions can conflict.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update the Studio re-detect,
re-translate, and re-render action handlers to consume the returned 202 job ID
and poll or otherwise await that job’s completion before refreshing editor data
and re-enabling the action buttons. Keep controls disabled throughout the
background operation and prevent overlapping mutations; apply the same
completion flow to each handler rather than refreshing immediately after
submission.

@deckyfx

deckyfx commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/src/BootExtensions.cs (1)

86-93: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

InpaintReady=true set for an unimplemented service.

The TODO explicitly says InpaintService isn't wired yet, but bootState.InpaintReady is still set to true, so /health will report Inpaint as ready when it's actually a no-op. This is inconsistent with the Bubble block right below it, which only flips BubbleReady after a real, successful LoadModel call. As per coding guidelines, "optional model readiness and enabled flags must distinguish disabled models from pending models."

🛠️ Suggested fix
             if (ms.Inpaint.ShouldDownload)
             {
                 logger.LogInformation("[Boot] Inpaint model downloaded; service init pending (not yet wired).");
                 // TODO: initialise InpaintService when implemented
-                bootState.InpaintReady = true;
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/src/BootExtensions.cs` around lines 86 - 93, Remove the
bootState.InpaintReady assignment from the ShouldDownload block in
BootExtensions, leaving InpaintReady false until an implemented InpaintService
initialization completes successfully. Preserve the download log and TODO, and
keep disabled or pending Inpaint models distinguishable from ready ones.

Source: Coding guidelines

🧹 Nitpick comments (1)
server/wwwroot/js/app.css (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exclude generated Tailwind output from Stylelint’s source scope.

Stylelint reports generated duplicate vendor declarations and compatibility values in this bundle. Do not hand-edit the emitted CSS; exclude server/wwwroot/js/app.css from Stylelint or lint the pre-build source stylesheet instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.css` at line 2, Exclude the generated Tailwind bundle
app.css from Stylelint’s source scope rather than modifying its emitted CSS.
Update the Stylelint configuration or lint command to ignore this generated
file, while continuing to lint the pre-build source stylesheet and other
intended CSS sources.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/portal-plan.md`:
- Around line 40-43: Align the PageTranslationJob Title contract with
PageTranslationService.CreateJobRowAsync: either document the persisted “Job
{first-8-chars-of-id}” default instead of a timestamp, or change the service to
persist the timestamp default. Ensure the documentation and implementation
describe the same API behavior.
- Around line 120-126: Align the documented Job Actions contract with the
implementation in PortalRoutes by ensuring each background action returns HTTP
202 together with the created action/job identifier. Update the relevant
handlers for redetect, retranslate, and rerender to include that identifier in
Results.Accepted; if no identifier is available, revise the documentation
instead of promising one.

In `@server/src/Data/AppDbContext.cs`:
- Around line 30-47: Add a required JobId foreign-key/navigation relationship
from PageTranslationLog to PageTranslationJob, configuring cascade deletion so
removing a job also removes its logs. Update the EF Core model configuration and
generate the corresponding migration and AppDbContextModelSnapshot changes to
enforce the relationship in SQLite.

In `@server/src/Services/BubbleDetectionService.cs`:
- Around line 39-79: Update BubbleDetectionService session lifecycle handling so
Detect captures one session snapshot and holds a ReaderWriterLockSlim read lock
for the entire inference call, including DetectRtDetr or DetectYolo, preventing
disposal during Run. Guard LoadModel’s session swap and old-session disposal
with the exclusive lock, and apply the same synchronization to Dispose; avoid
rereading _session during detection while preserving the unloaded empty-result
behavior.

In `@server/wwwroot/js/app.js`:
- Line 1: Update the Studio mutation handlers in the StudioPage flow to catch
rejected API requests and polling errors, store a user-visible error state, and
render that message in the editor. Keep the existing finally cleanup that
re-enables controls, but ensure every awaited mutation path handles failures
instead of producing unhandled promise rejections.

---

Outside diff comments:
In `@server/src/BootExtensions.cs`:
- Around line 86-93: Remove the bootState.InpaintReady assignment from the
ShouldDownload block in BootExtensions, leaving InpaintReady false until an
implemented InpaintService initialization completes successfully. Preserve the
download log and TODO, and keep disabled or pending Inpaint models
distinguishable from ready ones.

---

Nitpick comments:
In `@server/wwwroot/js/app.css`:
- Line 2: Exclude the generated Tailwind bundle app.css from Stylelint’s source
scope rather than modifying its emitted CSS. Update the Stylelint configuration
or lint command to ignore this generated file, while continuing to lint the
pre-build source stylesheet and other intended CSS sources.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8179c367-0734-4f92-a10b-988473e8c3aa

📥 Commits

Reviewing files that changed from the base of the PR and between 5c34e15 and 65a069c.

📒 Files selected for processing (51)
  • .gitignore
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
🚧 Files skipped from review as they are similar to previous changes (37)
  • extension/static/manifest.json
  • extension/package.json
  • extension/src/popup.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • extension/static/popup.css
  • extension/build.ts
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • extension/static/popup.html
  • server/src/Jobs/TranslationJobStore.cs
  • server/ClientApp/src/components/BubbleList.tsx
  • server/src/ModelSettingsStore.cs
  • server/server-csharp.csproj
  • server/ClientApp/src/solid-app.tsx
  • server/package.json
  • extension/static/content.css
  • server/ClientApp/src/components/Modal.tsx
  • server/src/Services/TypesettingService.cs
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/src/Routes/TranslatePage.cs
  • server/ClientApp/src/types.ts
  • server/Program.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/src/Config.cs
  • docs/manga-page-translation.md
  • server/ClientApp/src/pages/StudioPage.tsx
  • extension/src/background.ts
  • server/src/Routes/PortalRoutes.cs
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/src/Routes/HealthRoutes.cs
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/api.ts
  • extension/src/content.ts
  • server/src/Services/PageTranslationService.cs
  • server/ClientApp/src/components/BubbleCanvas.tsx

Comment thread docs/portal-plan.md
Comment thread docs/portal-plan.md Outdated
Comment thread server/src/Data/AppDbContext.cs
Comment thread server/src/Services/BubbleDetectionService.cs
Comment thread server/wwwroot/js/app.js Outdated
@@ -0,0 +1 @@
(function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};function r(e){let t=String(e),n=t.length-1;return R.context.id+(n?String.fromCharCode(96+n):``)+t}function i(e){R.context=e}function a(){return{...R.context,id:R.getNextContextId(),count:0}}function o(e,t){let n=H,r=B,i=e.length===0,a=t===void 0?r:t,o=i?ke:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(()=>h(()=>N(o)));B=o,H=null;try{return A(s,!0)}finally{H=n,B=r}}function s(e,t){t=t?Object.assign({},Te,t):Te;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[ee.bind(n),e=>(typeof e==`function`&&(e=V&&V.running&&V.sources.has(n)?e(n.tValue):e(n.value)),T(n,e))]}function c(e,t,n){let r=O(e,t,!0,z);je&&V&&V.running?U.push(r):E(r)}function l(e,t,n){let r=O(e,t,!1,z);je&&V&&V.running?U.push(r):E(r)}function u(e,t,n){De=ne;let r=O(e,t,!1,z),i=Ie&&C(Ie);i&&(r.suspense=i),(!n||!n.render)&&(r.user=!0),W?W.push(r):E(r)}function d(e,t,n){n=n?Object.assign({},Te,n):Te;let r=O(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,je&&V&&V.running?(r.tState=z,U.push(r)):E(r),ee.bind(r)}function f(e){return e&&typeof e==`object`&&`then`in e}function p(e,t,n){let r,i,a;typeof t==`function`?(r=e,i=t,a=n||{}):(r=!0,i=e,a=t||{});let o=null,l=Ae,u=null,p=!1,m=!1,g=`initialValue`in a,_=typeof r==`function`&&d(r),v=new Set,[y,x]=(a.storage||s)(a.initialValue),[S,w]=s(void 0),[ee,T]=s(void 0,{equals:!1}),[E,D]=s(g?`ready`:`unresolved`);R.context&&(u=R.getNextContextId(),a.ssrLoadFrom===`initial`?l=a.initialValue:R.load&&R.has(u)&&(l=R.load(u)));function O(e,t,n,r){return o===e&&(o=null,r!==void 0&&(g=!0),(e===l||t===l)&&a.onHydrated&&queueMicrotask(()=>a.onHydrated(r,{value:t})),l=Ae,V&&e&&p?(V.promises.delete(e),p=!1,A(()=>{V.running=!0,k(t,n)},!1)):k(t,n)),t}function k(e,t){A(()=>{t===void 0&&x(()=>e),D(t===void 0?g?`ready`:`unresolved`:`errored`),w(t);for(let e of v.keys())e.decrement();v.clear()},!1)}function j(){let e=Ie&&C(Ie),t=y(),n=S();if(n!==void 0&&!o)throw n;return H&&!H.user&&e&&c(()=>{ee(),o&&(e.resolved&&V&&p?V.promises.add(o):v.has(e)||(e.increment(),v.add(e)))}),t}function te(e=!0){if(e!==!1&&m)return;m=!1;let t=_?_():r;if(p=V&&V.running,t==null||t===!1){O(o,h(y));return}V&&o&&V.promises.delete(o);let n,a=l===Ae?h(()=>{try{return i(t,{value:y(),refetching:e})}catch(e){n=e}}):l;if(n!==void 0){O(o,void 0,oe(n),t);return}else if(!f(a))return O(o,a,void 0,t),a;return o=a,`v`in a?(a.s===1?O(o,a.v,void 0,t):O(o,void 0,oe(a.v),t),a):(m=!0,queueMicrotask(()=>m=!1),A(()=>{D(g?`refreshing`:`pending`),T()},!1),a.then(e=>O(a,e,void 0,t),e=>O(a,void 0,oe(e),t)))}Object.defineProperties(j,{state:{get:()=>E()},error:{get:()=>S()},loading:{get(){let e=E();return e===`pending`||e===`refreshing`}},latest:{get(){if(!g)return j();let e=S();if(e&&!o)throw e;return y()}}});let M=B;return _?c(()=>(M=B,te(!1))):te(!1),[j,{refetch:e=>b(M,()=>te(e)),mutate:x}]}function m(e){return A(e,!1)}function h(e){if(!Me&&H===null)return e();let t=H;H=null;try{return Me?Me.untrack(e):e()}finally{H=t}}function g(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=h(()=>t(o,i,n));return i=o,s}}function _(e){u(()=>h(e))}function v(e){return B===null||(B.cleanups===null?B.cleanups=[e]:B.cleanups.push(e)),e}function y(){return B}function b(e,t){let n=B,r=H;B=e,H=null;try{return A(t,!0)}catch(e){ce(e)}finally{B=n,H=r}}function x(e){if(V&&V.running)return e(),V.done;let t=H,n=B;return Promise.resolve().then(()=>{H=t,B=n;let r;return(je||Ie)&&(r=V||={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0},r.done||=new Promise(e=>r.resolve=e),r.running=!0),A(e,!1),H=B=null,r?r.done:void 0})}function S(e,t){let n=Symbol(`context`);return{id:n,Provider:ue(n),defaultValue:e}}function C(e){let t;return B&&B.context&&(t=B.context[e.id])!==void 0?t:e.defaultValue}function w(e){let t=d(e),n=d(()=>le(t()));return n.toArray=()=>{let e=n();return Array.isArray(e)?e:e==null?[]:[e]},n}function ee(){let e=V&&V.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===z)E(this);else{let e=U;U=null,A(()=>re(this),!1),U=e}if(H){let e=this.observers;if(!e||e[e.length-1]!==H){let t=e?e.length:0;H.sources?(H.sources.push(this),H.sourceSlots.push(t)):(H.sources=[this],H.sourceSlots=[t]),e?(e.push(H),this.observerSlots.push(H.sources.length-1)):(this.observers=[H],this.observerSlots=[H.sources.length-1])}}return e&&V.sources.has(this)?this.tValue:this.value}function T(e,t,n){let r=V&&V.running&&V.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(V){let r=V.running;(r||!n&&V.sources.has(e))&&(V.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&A(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=V&&V.running;r&&V.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?U.push(n):W.push(n),n.observers&&ie(n)),r?n.tState=z:n.state=z)}if(U.length>1e6)throw U=[],Error()},!1)}return t}function E(e){if(!e.fn)return;N(e);let t=Ne;D(e,V&&V.running&&V.sources.has(e)?e.tValue:e.value,t),V&&!V.running&&V.sources.has(e)&&queueMicrotask(()=>{A(()=>{V&&(V.running=!0),H=B=e,D(e,e.tValue,t),H=B=null},!1)})}function D(e,t,n){let r,i=B,a=H;H=B=e;try{r=e.fn(t)}catch(t){return e.pure&&(V&&V.running?(e.tState=z,e.tOwned&&e.tOwned.forEach(N),e.tOwned=void 0):(e.state=z,e.owned&&e.owned.forEach(N),e.owned=null)),e.updatedAt=n+1,ce(t)}finally{H=a,B=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?T(e,r,!0):V&&V.running&&e.pure?(V.sources.has(e)||(e.value=r),V.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function O(e,t,n,r=z,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:B,context:B?B.context:null,pure:n};if(V&&V.running&&(a.state=0,a.tState=r),B===null||B!==ke&&(V&&V.running&&B.pure?B.tOwned?B.tOwned.push(a):B.tOwned=[a]:B.owned?B.owned.push(a):B.owned=[a]),Me&&a.fn){let e=a.fn,[t,n]=s(void 0,{equals:!1}),r=Me.factory(e,n);v(()=>r.dispose());let i,o=()=>x(n).then(()=>{i&&=(i.dispose(),void 0)});a.fn=n=>(t(),V&&V.running?(i||=Me.factory(e,o),i.track(n)):r.track(n))}return a}function k(e){let t=V&&V.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===Oe)return re(e);if(e.suspense&&h(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Ne);){if(t&&V.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(V.disposed.has(t))return}if((t?e.tState:e.state)===z)E(e);else if((t?e.tState:e.state)===Oe){let t=U;U=null,A(()=>re(e,n[0]),!1),U=t}}}function A(e,t){if(U)return e();let n=!1;t||(U=[]),W?n=!0:W=[],Ne++;try{let t=e();return j(n),t}catch(e){n||(W=null),U=null,ce(e)}}function j(e){if(U&&=(je&&V&&V.running?M(U):te(U),null),e)return;let t;if(V){if(!V.promises.size&&!V.queue.size){let e=V.sources,n=V.disposed;W.push.apply(W,V.effects),t=V.resolve;for(let e of W)`tState`in e&&(e.state=e.tState),delete e.tState;V=null,A(()=>{for(let e of n)N(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)N(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}Fe(!1)},!1)}else if(V.running){V.running=!1,V.effects.push.apply(V.effects,W),W=null,Fe(!0);return}}let n=W;W=null,n.length&&A(()=>De(n),!1),t&&t()}function te(e){for(let t=0;t<e.length;t++)k(e[t])}function M(e){for(let t=0;t<e.length;t++){let n=e[t],r=V.queue;r.has(n)||(r.add(n),je(()=>{r.delete(n),A(()=>{V.running=!0,k(n)},!1),V&&(V.running=!1)}))}}function ne(e){let t,n=0;for(t=0;t<e.length;t++){let r=e[t];r.user?e[n++]=r:k(r)}if(R.context){if(R.count){R.effects||=[],R.effects.push(...e.slice(0,n));return}i()}for(R.effects&&(R.done||!R.count)&&(e=[...R.effects,...e],n+=R.effects.length,delete R.effects),t=0;t<n;t++)k(e[t])}function re(e,t){let n=V&&V.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===z?i!==t&&(!i.updatedAt||i.updatedAt<Ne)&&k(i):e===Oe&&re(i,t)}}}function ie(e){let t=V&&V.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=Oe:r.state=Oe,r.pure?U.push(r):W.push(r),r.observers&&ie(r))}}function N(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)N(e.tOwned[t]);delete e.tOwned}if(V&&V.running&&e.pure)ae(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)N(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}V&&V.running?e.tState=0:e.state=0}function ae(e,t){if(t||(e.tState=0,V.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ae(e.owned[t])}function oe(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function se(e,t,n){try{for(let n of t)n(e)}catch(e){ce(e,n&&n.owner||null)}}function ce(e,t=B){let n=Ee&&t&&t.context&&t.context[Ee],r=oe(e);if(!n)throw r;W?W.push({fn(){se(r,n,t)},state:z}):se(r,n,t)}function le(e){if(typeof e==`function`&&!e.length)return le(e());if(Array.isArray(e)){let t=[];for(let n=0;n<e.length;n++){let r=le(e[n]);if(Array.isArray(r))if(r.length<32768)t.push.apply(t,r);else for(let e=0;e<r.length;e++)t.push(r[e]);else t.push(r)}return t}return e}function ue(e,t){return function(t){let n;return l(()=>n=h(()=>(B.context={...B.context,[e]:t.value},w(()=>t.children))),void 0),n}}function de(e){for(let t=0;t<e.length;t++)e[t]()}function fe(e,t,n={}){let r=[],i=[],a=[],c=0,l=t.length>1?[]:null;return v(()=>de(a)),()=>{let u=e()||[],d=u.length,f,p;return u[we],h(()=>{let e,t,s,h,g,_,v,y,b;if(d===0)c!==0&&(de(a),a=[],r=[],i=[],c=0,l&&=[]),n.fallback&&(r=[Le],i[0]=o(e=>(a[0]=e,n.fallback())),c=1);else if(c===0){for(i=Array(d),p=0;p<d;p++)r[p]=u[p],i[p]=o(m);c=d}else{for(s=Array(d),h=Array(d),l&&(g=Array(d)),_=0,v=Math.min(c,d);_<v&&r[_]===u[_];_++);for(v=c-1,y=d-1;v>=_&&y>=_&&r[v]===u[y];v--,y--)s[y]=i[v],h[y]=a[v],l&&(g[y]=l[v]);for(e=new Map,t=Array(y+1),p=y;p>=_;p--)b=u[p],f=e.get(b),t[p]=f===void 0?-1:f,e.set(b,p);for(f=_;f<=v;f++)b=r[f],p=e.get(b),p!==void 0&&p!==-1?(s[p]=i[f],h[p]=a[f],l&&(g[p]=l[f]),p=t[p],e.set(b,p)):a[f]();for(p=_;p<d;p++)p in s?(i[p]=s[p],a[p]=h[p],l&&(l[p]=g[p],l[p](p))):i[p]=o(m);i=i.slice(0,c=d),r=u.slice(0)}return i});function m(e){if(a[p]=e,l){let[e,n]=s(p);return l[p]=n,t(u[p],e)}return t(u[p])}}}function P(e,t){if(Re&&R.context){let n=R.context;i(a());let r=h(()=>e(t||{}));return i(n),r}return h(()=>e(t||{}))}function pe(){return!0}function me(e){return(e=typeof e==`function`?e():e)?e:{}}function he(){for(let e=0,t=this.length;e<t;++e){let t=this[e]();if(t!==void 0)return t}}function F(...e){let t=!1;for(let n=0;n<e.length;n++){let r=e[n];t||=!!r&&Se in r,e[n]=typeof r==`function`?(t=!0,d(r)):r}if(Ce&&t)return new Proxy({get(t){for(let n=e.length-1;n>=0;n--){let r=me(e[n])[t];if(r!==void 0)return r}},has(t){for(let n=e.length-1;n>=0;n--)if(t in me(e[n]))return!0;return!1},keys(){let t=[];for(let n=0;n<e.length;n++)t.push(...Object.keys(me(e[n])));return[...new Set(t)]}},ze);let n={},r=Object.create(null);for(let t=e.length-1;t>=0;t--){let i=e[t];if(!i)continue;let a=Object.getOwnPropertyNames(i);for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===`__proto__`||t===`constructor`)continue;let o=Object.getOwnPropertyDescriptor(i,t);if(!r[t])r[t]=o.get?{enumerable:!0,configurable:!0,get:he.bind(n[t]=[o.get.bind(i)])}:o.value===void 0?void 0:o;else{let e=n[t];e&&(o.get?e.push(o.get.bind(i)):o.value!==void 0&&e.push(()=>o.value))}}}let i={},a=Object.keys(r);for(let e=a.length-1;e>=0;e--){let t=a[e],n=r[t];n&&n.get?Object.defineProperty(i,t,n):i[t]=n?n.value:void 0}return i}function ge(e,...t){let n=t.length;if(Ce&&Se in e){let r=n>1?t.flat():t[0],i=t.map(t=>new Proxy({get(n){return t.includes(n)?e[n]:void 0},has(n){return t.includes(n)&&n in e},keys(){return t.filter(t=>t in e)}},ze));return i.push(new Proxy({get(t){return r.includes(t)?void 0:e[t]},has(t){return r.includes(t)?!1:t in e},keys(){return Object.keys(e).filter(e=>!r.includes(e))}},ze)),i}let r=[];for(let e=0;e<=n;e++)r[e]={};for(let i of Object.getOwnPropertyNames(e)){let a=n;for(let e=0;e<t.length;e++)if(t[e].includes(i)){a=e;break}let o=Object.getOwnPropertyDescriptor(e,i);!o.get&&!o.set&&o.enumerable&&o.writable&&o.configurable?r[a][i]=o.value:Object.defineProperty(r[a],i,o)}return r}function _e(e){let t,n,r=r=>{let a=R.context;if(a){let[r,o]=s();R.count||=0,R.count++,(n||=e()).then(e=>{!R.done&&i(a),R.count--,o(()=>e.default),i()}),t=r}else if(!t){let[r]=p(()=>(n||=e()).then(e=>e.default));t=r}let o;return d(()=>(o=t())?h(()=>{if(!a||R.done)return o(r);let e=R.context;i(a);let t=o(r);return i(e),t}):``)};return r.preload=()=>n||((n=e()).then(e=>t=()=>e.default),n),r}function I(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return d(fe(()=>e.each,e.children,t||void 0))}function L(e){let t=e.keyed,n=d(()=>e.when,void 0,void 0),r=t?n:d(n,void 0,{equals:(e,t)=>!e==!t});return d(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?h(()=>a(t?i:()=>{if(!h(r))throw Be(`Show`);return n()})):a}return e.fallback},void 0,void 0)}function ve(e){let t=w(()=>e.children),n=d(()=>{let e=t(),n=Array.isArray(e)?e:[e],r=()=>void 0;for(let e=0;e<n.length;e++){let t=e,i=n[e],a=r,o=d(()=>a()?void 0:i.when,void 0,void 0),s=i.keyed?o:d(o,void 0,{equals:(e,t)=>!e==!t});r=()=>a()||(s()?[t,o,i]:void 0)}return r});return d(()=>{let t=n()();if(!t)return e.fallback;let[r,i,a]=t,o=a.children;return typeof o==`function`&&o.length>0?h(()=>o(a.keyed?i():()=>{if(h(n)()?.[0]!==r)throw Be(`Match`);return i()})):o},void 0,void 0)}function ye(e){return e}function be(){Ve&&[...Ve].forEach(e=>e())}var R,xe,Se,Ce,we,Te,Ee,De,z,Oe,ke,Ae,B,V,je,Me,H,U,W,Ne,Pe,Fe,Ie,Le,Re,ze,Be,Ve,G=t((()=>{R={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return r(this.context.count)},getNextContextId(){return r(this.context.count++)}},xe=(e,t)=>e===t,Se=Symbol(`solid-proxy`),Ce=typeof Proxy==`function`,we=Symbol(`solid-track`),Te={equals:xe},Ee=null,De=te,z=1,Oe=2,ke={owned:null,cleanups:null,context:null,owner:null},Ae={},B=null,V=null,je=null,Me=null,H=null,U=null,W=null,Ne=0,[Pe,Fe]=s(!1),Le=Symbol(`fallback`),Re=!1,ze={get(e,t,n){return t===Se?n:e.get(t)},has(e,t){return t===Se?!0:e.has(t)},set:pe,deleteProperty:pe,getOwnPropertyDescriptor(e,t){return{configurable:!0,enumerable:!0,get(){return e.get(t)},set:pe,deleteProperty:pe}},ownKeys(e){return e.keys()}},Be=e=>`Stale read from <${e}>.`}));function He(e,t){let n=yt[e];return typeof n==`object`?n[t]?n.$:void 0:n}function Ue(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;){if(t[o]===n[s]){o++,s++;continue}for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)(!l||!l.has(t[o]))&&t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null)if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&!((d=l.get(t[c]))==null||d!==r+u);)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++;else t[o++].remove()}}}function We(e,t,n,r={}){let i;return o(r=>{i=r,t===document?e():J(t,e(),t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function K(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>h(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function Ge(e,t=window.document){let n=t[Ct]||(t[Ct]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,st))}}function q(e,t,n){rt(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function Ke(e,t,n,r){rt(e)||(r==null?e.removeAttributeNS(t,n):e.setAttributeNS(t,n,r))}function qe(e,t,n){rt(e)||(n?e.setAttribute(t,``):e.removeAttribute(t))}function Je(e,t){rt(e)||(t==null?e.removeAttribute(`class`):e.className=t)}function Ye(e,t,n,r){if(r)Array.isArray(n)?(e[`$$${t}`]=n[0],e[`$$${t}Data`]=n[1]):e[`$$${t}`]=n;else if(Array.isArray(n)){let r=n[0];e.addEventListener(t,n[0]=t=>r.call(e,n[1],t))}else e.addEventListener(t,n,typeof n!=`function`&&n)}function Xe(e,t,n={}){let r=Object.keys(t||{}),i=Object.keys(n),a,o;for(a=0,o=i.length;a<o;a++){let r=i[a];!r||r===`undefined`||t[r]||(at(e,r,!1),delete n[r])}for(a=0,o=r.length;a<o;a++){let i=r[a],o=!!t[i];!i||i===`undefined`||n[i]===o||!o||(at(e,i,!0),n[i]=o)}return n}function Ze(e,t,n){if(!t)return n?q(e,`style`):t;let r=e.style;if(typeof t==`string`)return r.cssText=t;typeof n==`string`&&(r.cssText=n=void 0),n||={},t||={};let i,a;for(a in n)t[a]??r.removeProperty(a),delete n[a];for(a in t)i=t[a],i!==n[a]&&(r.setProperty(a,i),n[a]=i);return n}function Qe(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function $e(e,t={},n,r){let i={};return r||l(()=>i.children=ct(e,t.children,i.children)),l(()=>typeof t.ref==`function`&&et(t.ref,e)),l(()=>tt(e,t,n,!0,i,!0)),i}function et(e,t,n){return h(()=>e(t,n))}function J(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return ct(e,t,r,n);l(r=>ct(e,t(),r,n),r)}function tt(e,t,n,r,i={},a=!1){t||={};for(let r in i)if(!(r in t)){if(r===`children`)continue;i[r]=ot(e,r,null,i[r],n,a,t)}for(let o in t){if(o===`children`){r||ct(e,t.children);continue}let s=t[o];i[o]=ot(e,o,s,i[o],n,a,t)}}function nt(e){let t,n;return!rt()||!(t=R.registry.get(n=ft()))?e():(R.completed&&R.completed.add(t),R.registry.delete(n),t)}function rt(e){return!!R.context&&!R.done&&(!e||e.isConnected)}function it(e){return e.toLowerCase().replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function at(e,t,n){let r=t.trim().split(/\s+/);for(let t=0,i=r.length;t<i;t++)e.classList.toggle(r[t],n)}function ot(e,t,n,r,i,a,o){let s,c,l,u,d;if(t===`style`)return Ze(e,n,r);if(t===`classList`)return Xe(e,n,r);if(n===r)return r;if(t===`ref`)a||n(e);else if(t.slice(0,3)===`on:`){let i=t.slice(3);r&&e.removeEventListener(i,r,typeof r!=`function`&&r),n&&e.addEventListener(i,n,typeof n!=`function`&&n)}else if(t.slice(0,10)===`oncapture:`){let i=t.slice(10);r&&e.removeEventListener(i,r,!0),n&&e.addEventListener(i,n,!0)}else if(t.slice(0,2)===`on`){let i=t.slice(2).toLowerCase(),a=bt.has(i);if(!a&&r){let t=Array.isArray(r)?r[0]:r;e.removeEventListener(i,t)}(a||n)&&(Ye(e,i,n,a),a&&Ge([i]))}else if(t.slice(0,5)===`attr:`)q(e,t.slice(5),n);else if(t.slice(0,5)===`bool:`)qe(e,t.slice(5),n);else if((d=t.slice(0,5)===`prop:`)||(l=_t.has(t))||!i&&((u=He(t,e.tagName))||(c=gt.has(t)))||(s=e.nodeName.includes(`-`)||`is`in o)){if(d)t=t.slice(5),c=!0;else if(rt(e))return n;t===`class`||t===`className`?Je(e,n):s&&!c&&!l?e[it(t)]=n:e[u||t]=n}else{let r=i&&t.indexOf(`:`)>-1&&St[t.split(`:`)[0]];r?Ke(e,r,t,n):q(e,vt[t]||t,n)}return n}function st(e){if(R.registry&&R.events&&R.events.find(([t,n])=>n===e))return;let t=e.target,n=`$$${e.type}`,r=e.target,i=e.currentTarget,a=t=>Object.defineProperty(e,"target",{configurable:!0,value:t}),o=()=>{let r=t[n];if(r&&!t.disabled){let i=t[`${n}Data`];if(i===void 0?r.call(t,e):r.call(t,i,e),e.cancelBubble)return}return t.host&&typeof t.host!=`string`&&!t.host._$host&&t.contains(e.target)&&a(t.host),!0},s=()=>{for(;o()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),R.registry&&!R.done&&(R.done=_$HY.done=!0),e.composedPath){let n=e.composedPath();a(n[0]);for(let e=0;e<n.length-2&&(t=n[e],o());e++){if(t._$host){t=t._$host,s();break}if(t.parentNode===i)break}}else s();a(r)}function ct(e,t,n,r,i){let a=rt(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=dt(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=dt(e,n,r)}else if(o===`function`)return l(()=>{let i=t();for(;typeof i==`function`;)i=i();n=ct(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(lt(o,t,n,i))return l(()=>n=ct(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=dt(e,n,r),s)return n}else c?n.length===0?ut(e,o,r):Ue(e,n,o):(n&&dt(e),ut(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=dt(e,n,r,t);dt(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function lt(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(!(o==null||o===!0||o===!1))if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=lt(e,o,s)||i;else if(c===`function`)if(r){for(;typeof o==`function`;)o=o();i=lt(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0;else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}return i}function ut(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function dt(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}function ft(){return R.getNextContextId()}function pt(e,t=!1,n=void 0){return t?document.createElementNS(wt,e):document.createElement(e,{is:n})}function mt(e,t){let n=d(e);return d(()=>{let e=n();switch(typeof e){case`function`:return h(()=>e(t));case`string`:let n=xt.has(e),r=R.context?nt():pt(e,n,h(()=>t.is));return $e(r,t,n),r}})}function ht(e){let[,t]=ge(e,[`component`]);return mt(()=>e.component,t)}var gt,_t,vt,yt,bt,xt,St,Y,Ct,wt,X=t((()=>{G(),gt=new Set([`className`,`value`,`readOnly`,`noValidate`,`formNoValidate`,`isMap`,`noModule`,`playsInline`,`adAuctionHeaders`,`allowFullscreen`,`browsingTopics`,`defaultChecked`,`defaultMuted`,`defaultSelected`,`disablePictureInPicture`,`disableRemotePlayback`,`preservesPitch`,`shadowRootClonable`,`shadowRootCustomElementRegistry`,`shadowRootDelegatesFocus`,`shadowRootSerializable`,`sharedStorageWritable`,...`allowfullscreen.async.alpha.autofocus.autoplay.checked.controls.default.disabled.formnovalidate.hidden.indeterminate.inert.ismap.loop.multiple.muted.nomodule.novalidate.open.playsinline.readonly.required.reversed.seamless.selected.adauctionheaders.browsingtopics.credentialless.defaultchecked.defaultmuted.defaultselected.defer.disablepictureinpicture.disableremoteplayback.preservespitch.shadowrootclonable.shadowrootcustomelementregistry.shadowrootdelegatesfocus.shadowrootserializable.sharedstoragewritable`.split(`.`)]),_t=new Set([`innerHTML`,`textContent`,`innerText`,`children`]),vt=Object.assign(Object.create(null),{className:`class`,htmlFor:`for`}),yt=Object.assign(Object.create(null),{class:`className`,novalidate:{$:`noValidate`,FORM:1},formnovalidate:{$:`formNoValidate`,BUTTON:1,INPUT:1},ismap:{$:`isMap`,IMG:1},nomodule:{$:`noModule`,SCRIPT:1},playsinline:{$:`playsInline`,VIDEO:1},readonly:{$:`readOnly`,INPUT:1,TEXTAREA:1},adauctionheaders:{$:`adAuctionHeaders`,IFRAME:1},allowfullscreen:{$:`allowFullscreen`,IFRAME:1},browsingtopics:{$:`browsingTopics`,IMG:1},defaultchecked:{$:`defaultChecked`,INPUT:1},defaultmuted:{$:`defaultMuted`,AUDIO:1,VIDEO:1},defaultselected:{$:`defaultSelected`,OPTION:1},disablepictureinpicture:{$:`disablePictureInPicture`,VIDEO:1},disableremoteplayback:{$:`disableRemotePlayback`,AUDIO:1,VIDEO:1},preservespitch:{$:`preservesPitch`,AUDIO:1,VIDEO:1},shadowrootclonable:{$:`shadowRootClonable`,TEMPLATE:1},shadowrootdelegatesfocus:{$:`shadowRootDelegatesFocus`,TEMPLATE:1},shadowrootserializable:{$:`shadowRootSerializable`,TEMPLATE:1},sharedstoragewritable:{$:`sharedStorageWritable`,IFRAME:1,IMG:1}}),bt=new Set([`beforeinput`,`click`,`dblclick`,`contextmenu`,`focusin`,`focusout`,`input`,`keydown`,`keyup`,`mousedown`,`mousemove`,`mouseout`,`mouseover`,`mouseup`,`pointerdown`,`pointermove`,`pointerout`,`pointerover`,`pointerup`,`touchend`,`touchmove`,`touchstart`]),xt=new Set(`altGlyph.altGlyphDef.altGlyphItem.animate.animateColor.animateMotion.animateTransform.circle.clipPath.color-profile.cursor.defs.desc.ellipse.feBlend.feColorMatrix.feComponentTransfer.feComposite.feConvolveMatrix.feDiffuseLighting.feDisplacementMap.feDistantLight.feDropShadow.feFlood.feFuncA.feFuncB.feFuncG.feFuncR.feGaussianBlur.feImage.feMerge.feMergeNode.feMorphology.feOffset.fePointLight.feSpecularLighting.feSpotLight.feTile.feTurbulence.filter.font.font-face.font-face-format.font-face-name.font-face-src.font-face-uri.foreignObject.g.glyph.glyphRef.hkern.image.line.linearGradient.marker.mask.metadata.missing-glyph.mpath.path.pattern.polygon.polyline.radialGradient.rect.set.stop.svg.switch.symbol.text.textPath.tref.tspan.use.view.vkern`.split(`.`)),St={xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`},Y=e=>d(()=>e()),Ct=`_$DX_DELEGATE`,wt=`http://www.w3.org/2000/svg`}));X();function Tt(){let e=new Set;function t(t){return e.add(t),()=>e.delete(t)}let n=!1;function r(t,r){if(n)return!(n=!1);let i={to:t,options:r,defaultPrevented:!1,preventDefault:()=>i.defaultPrevented=!0};for(let a of e)a.listener({...i,from:a.location,retry:e=>{e&&(n=!0),a.navigate(t,{...r,resolve:!1})}});return!i.defaultPrevented}return{subscribe:t,confirm:r}}function Et(){(!window.history.state||window.history.state._depth==null)&&window.history.replaceState({...window.history.state,_depth:window.history.length-1},``),kt=window.history.state._depth}function Dt(e){return{...e,_depth:window.history.state&&window.history.state._depth}}function Ot(e,t){let n=!1;return()=>{let r=kt;Et();let i=r==null?null:kt-r;if(n){n=!1;return}i&&t(i)?(n=!0,window.history.go(-i)):e()}}var kt,At=t((()=>{Et()}));function jt(e,t=!1){let n=e.replace(Ht,`$1`);return n?t||/^[?#]/.test(n)?n:`/`+n:``}function Mt(e,t,n){if(Vt.test(t))return;let r=jt(e),i=n&&jt(n),a=``;return a=!i||t.startsWith(`/`)?r:i.toLowerCase().indexOf(r.toLowerCase())===0?i:r+i,(a||`/`)+jt(t,!a)}function Nt(e,t){if(e==null)throw Error(t);return e}function Pt(e,t){return jt(e).replace(/\/*(\*.*)?$/g,``)+jt(t)}function Ft(e){let t={};return e.searchParams.forEach((e,n)=>{n in t?Array.isArray(t[n])?t[n].push(e):t[n]=[t[n],e]:t[n]=e}),t}function It(e,t,n){let[r,i]=e.split(`/*`,2),a=r.split(`/`).filter(Boolean),o=a.length;return e=>{let r=e.split(`/`).filter(Boolean),s=r.length-o;if(s<0||s>0&&i===void 0&&!t)return null;let c={path:o?``:`/`,params:{}},l=e=>n===void 0?void 0:n[e];for(let e=0;e<o;e++){let t=a[e],n=t[0]===`:`,i=n?r[e]:r[e].toLowerCase(),o=n?t.slice(1):t.toLowerCase();if(n&&Lt(i,l(o)))c.params[o]=i;else if(n||!Lt(i,o))return null;c.path+=`/${i}`}if(i){let e=s?r.slice(-s).join(`/`):``;if(Lt(e,l(i)))c.params[i]=e;else return null}return c}}function Lt(e,t){let n=t=>t===e;return t===void 0?!0:typeof t==`string`?n(t):typeof t==`function`?t(e):Array.isArray(t)?t.some(n):t instanceof RegExp?t.test(e):!1}function Rt(e){let[t,n]=e.pattern.split(`/*`,2),r=t.split(`/`).filter(Boolean);return r.reduce((e,t)=>e+(t.startsWith(`:`)?2:3),r.length-(n===void 0?0:1))}function zt(e){let t=new Map,n=y();return new Proxy({},{get(r,i){return t.has(i)||b(n,()=>t.set(i,d(()=>e()[i]))),t.get(i)()},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}},ownKeys(){return Reflect.ownKeys(e())},has(t,n){return n in e()}})}function Bt(e){let t=/(\/?\:[^\/]+)\?/.exec(e);if(!t)return[e];let n=e.slice(0,t.index),r=e.slice(t.index+t[0].length),i=[n,n+=t[1]];for(;t=/^(\/\:[^\/]+)\?/.exec(r);)i.push(n+=t[1]),r=r.slice(t[0].length);return Bt(r).reduce((e,t)=>[...e,...i.map(e=>e+t)],[])}var Vt,Ht,Ut,Wt=t((()=>{G(),Vt=/^(?:[a-z0-9]+:)?\/\//i,Ht=/^\/+|(\/)\/+$/g,Ut=`http://sr`}));function Gt(e,t=``){let{component:n,preload:r,load:i,children:a,info:o}=e,s=!a||Array.isArray(a)&&!a.length,c={key:e,component:n,preload:r||i,info:o};return qt(e.path).reduce((n,r)=>{for(let i of Bt(r)){let a=Pt(t,i),o=s?a:a.split(`/*`,1)[0];o=o.split(`/`).map(e=>e.startsWith(`:`)||e.startsWith(`*`)?e:encodeURIComponent(e)).join(`/`),n.push({...c,originalPath:r,pattern:o,matcher:It(o,!s,e.matchFilters)})}return n},[])}function Kt(e,t=0){return{routes:e,score:Rt(e[e.length-1])*1e4-t,matcher(t){let n=[];for(let r=e.length-1;r>=0;r--){let i=e[r],a=i.matcher(t);if(!a)return null;n.unshift({...a,route:i})}return n}}}function qt(e){return Array.isArray(e)?e:[e]}function Jt(e,t=``,n=[],r=[]){let i=qt(e);for(let e=0,a=i.length;e<a;e++){let a=i[e];if(a&&typeof a==`object`){a.hasOwnProperty(`path`)||(a.path=``);let e=Gt(a,t);for(let t of e){n.push(t);let e=Array.isArray(a.children)&&a.children.length===0;if(a.children&&!e)Jt(a.children,t.pattern,n,r);else{let e=Kt([...n],r.length);r.push(e)}n.pop()}}}return n.length?r:r.sort((e,t)=>t.score-e.score)}function Yt(e,t){for(let n=0,r=e.length;n<r;n++){let r=e[n].matcher(t);if(r)return r}return[]}function Xt(e,t,n){let r=new URL(Ut),i=d(t=>{let n=e();try{return new URL(n,r)}catch{return console.error(`Invalid path ${n}`),t}},r,{equals:(e,t)=>e.href===t.href}),a=d(()=>i().pathname),o=d(()=>i().search,!0),s=d(()=>i().hash),c=()=>``,l=g(o,()=>Ft(i()));return{get pathname(){return a()},get search(){return o()},get hash(){return s()},get state(){return t()},get key(){return c()},query:n?n(l):zt(l)}}function Zt(){return fn}function Qt(e){pn=e}function $t(e,t,n,r={}){let{signal:[i,a],utils:o={}}=e,c=o.parsePath||(e=>e),u=o.renderPath||(e=>e),f=o.beforeLeave||Tt(),p=Mt(``,r.base||``);if(p===void 0)throw Error(`${p} is not a valid base path`);p&&!i().value&&a({value:p,replace:!0,scroll:!1});let[_,v]=s(!1),y,S=(e,t)=>{t.value===w()&&t.state===T()||(y===void 0&&v(!0),fn=e,y=t,x(()=>{y===t&&(ee(y.value),E(y.state),be(),k[1](e=>e.filter(e=>e.pending)))}).finally(()=>{y===t&&m(()=>{fn=void 0,e===`navigate`&&ie(y),v(!1),y=void 0})}))},[w,ee]=s(i().value),[T,E]=s(i().state),D=Xt(w,T,o.queryWrapper),O=[],k=s([]),A=d(()=>typeof r.transformUrl==`function`?Yt(t(),r.transformUrl(D.pathname)):Yt(t(),D.pathname)),j=()=>{let e=A(),t={};for(let n=0;n<e.length;n++)Object.assign(t,e[n].params);return t},te=o.paramsWrapper?o.paramsWrapper(j,t):zt(j),M={pattern:p,path:()=>p,outlet:()=>null,resolvePath(e){return Mt(p,e)}};return l(g(i,e=>S(`native`,e),{defer:!0})),{base:M,location:D,params:te,isRouting:_,renderPath:u,parsePath:c,navigatorFactory:re,matches:A,beforeLeave:f,preloadRoute:N,singleFlight:r.singleFlight===void 0?!0:r.singleFlight,submissions:k};function ne(e,t,n){h(()=>{if(typeof t==`number`){t&&(o.go?o.go(t):console.warn(`Router integration does not support relative routing`));return}let r=!t||t[0]===`?`,{replace:i,resolve:a,scroll:s,state:c}={replace:!1,resolve:!r,scroll:!0,...n},l=a?e.resolvePath(t):Mt(r&&D.pathname||``,t);if(l===void 0)throw Error(`Path '${t}' is not a routable path`);if(O.length>=tn)throw Error(`Too many redirects`);let u=w();(l!==u||c!==T())&&f.confirm(l,n)&&(O.push({value:u,replace:i,scroll:s,state:T()}),S(`navigate`,{value:l,state:c}))})}function re(e){return e=e||C(rn)||M,(t,n)=>ne(e,t,n)}function ie(e){let t=O[0];t&&(a({...e,replace:t.replace,scroll:t.scroll}),O.length=0)}function N(e,r){let i=Yt(t(),e.pathname),a=fn;fn=`preload`;for(let t in i){let{route:a,params:o}=i[t];a.component&&a.component.preload&&a.component.preload();let{preload:s}=a;pn=!0,r&&s&&b(n(),()=>s({params:o,location:{pathname:e.pathname,search:e.search,hash:e.hash,query:Ft(e),state:null,key:``},intent:`preload`})),pn=!1}fn=a}}function en(e,t,n,r){let{base:i,location:a,params:o}=e,{pattern:s,component:c,preload:l}=r().route,u=d(()=>r().path);c&&c.preload&&c.preload(),pn=!0;let f=l?l({params:o,location:a,intent:fn||`initial`}):void 0;return pn=!1,{parent:t,pattern:s,path:u,outlet:()=>c?P(c,{params:o,location:a,data:f,get children(){return n()}}):n(),resolvePath(e){return Mt(i.path(),e,u())}}}var tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn=t((()=>{G(),X(),At(),Wt(),tn=100,nn=S(),rn=S(),an=()=>Nt(C(nn),`<A> and 'use' router primitives can be only used inside a Route.`),on=()=>C(rn)||an().base,sn=e=>{let t=on();return d(()=>t.resolvePath(e()))},cn=e=>{let t=an();return d(()=>{let n=e();return n===void 0?n:t.renderPath(n)})},ln=()=>an().navigatorFactory(),un=()=>an().location,dn=()=>an().params}));function hn(e){let t=e.routerState.location,n=e.routerState.params,r=d(()=>e.preload&&h(()=>{Qt(!0),e.preload({params:n,location:t,intent:Zt()||`initial`}),Qt(!1)}));return P(L,{get when(){return e.root},keyed:!0,get fallback(){return e.children},children:i=>P(i,{params:n,location:t,get data(){return r()},get children(){return e.children}})})}function gn(e){let t=[],n,r=d(g(e.routerState.matches,(i,a,s)=>{let c=a&&i.length===a.length,l=[];for(let n=0,u=i.length;n<u;n++){let u=a&&a[n],d=i[n];s&&u&&d.route.key===u.route.key?l[n]=s[n]:(c=!1,t[n]&&t[n](),o(i=>{t[n]=i,l[n]=en(e.routerState,l[n-1]||e.routerState.base,vn(()=>r()[n+1]),()=>{let t=e.routerState.matches();return t[n]??t[0]})}))}return t.splice(i.length).forEach(e=>e()),s&&c?s:(n=l[0],l)}));return vn(()=>r()&&n)()}var _n,vn,yn,bn=t((()=>{X(),G(),mn(),_n=e=>t=>{let{base:n}=t,r=w(()=>t.children),i=d(()=>Jt(r(),t.base||``)),a,o=$t(e,i,()=>a,{base:n,singleFlight:t.singleFlight,transformUrl:t.transformUrl});return e.create&&e.create(o),P(nn.Provider,{value:o,get children(){return P(hn,{routerState:o,get root(){return t.root},get preload(){return t.rootPreload||t.rootLoad},get children(){return[Y(()=>(a=y())&&null),P(gn,{routerState:o,get branches(){return i()}})]}})}})},vn=e=>()=>P(L,{get when(){return e()},keyed:!0,children:e=>P(rn.Provider,{value:e,get children(){return e.outlet()}})}),yn=e=>{let t=w(()=>e.children);return F(e,{get children(){return t()}})}}));function xn([e,t],n,r){return[n?()=>n(e()):e,r?e=>t(r(e)):t]}function Sn(e){let t=!1,n=e=>typeof e==`string`?{value:e}:e,r=xn(s(n(e.get()),{equals:(e,t)=>e.value===t.value&&e.state===t.state}),void 0,n=>(!t&&e.set(n),R.registry&&!R.done&&(R.done=!0),n));return e.init&&v(e.init((i=e.get())=>{t=!0,r[1](n(i)),t=!1})),_n({signal:r,create:e.create,utils:e.utils})}function Cn(e,t,n){return e.addEventListener(t,n),()=>e.removeEventListener(t,n)}function wn(e,t){let n=e&&document.getElementById(e);n?n.scrollIntoView():t&&window.scrollTo(0,0)}var Tn=t((()=>{G(),bn()})),En,Dn=t((()=>{En=new Map}));function On(e=!0,t=!1,n=`/_server`,r){return i=>{let a=i.base.path(),o=i.navigatorFactory(i.base),s,c;function l(e){return e.namespaceURI===`http://www.w3.org/2000/svg`}function u(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;let n=e.composedPath().find(e=>e instanceof Node&&e.nodeName.toUpperCase()===`A`);if(!n||t&&!n.hasAttribute(`link`))return;let r=l(n),i=r?n.href.baseVal:n.href;if((r?n.target.baseVal:n.target)||!i&&!n.hasAttribute(`state`))return;let o=(n.getAttribute(`rel`)||``).split(/\s+/);if(n.hasAttribute(`download`)||o&&o.includes(`external`))return;let s=r?new URL(i,document.baseURI):new URL(i);if(!(s.origin!==window.location.origin||a&&s.pathname&&!s.pathname.toLowerCase().startsWith(a.toLowerCase())))return[n,s]}function d(e){let t=u(e);if(!t)return;let[n,r]=t,a=i.parsePath(r.pathname+r.search+r.hash),s=n.getAttribute(`state`);e.preventDefault(),o(a,{resolve:!1,replace:n.hasAttribute(`replace`),scroll:!n.hasAttribute(`noscroll`),state:s?JSON.parse(s):void 0})}function f(e){let t=u(e);if(!t)return;let[n,a]=t;r&&(a.pathname=r(a.pathname)),i.preloadRoute(a,n.getAttribute(`preload`)!==`false`)}function p(e){clearTimeout(s);let t=u(e);if(!t)return c=null;let[n,a]=t;c!==n&&(r&&(a.pathname=r(a.pathname)),s=setTimeout(()=>{i.preloadRoute(a,n.getAttribute(`preload`)!==`false`),c=n},20))}function m(e){if(e.defaultPrevented)return;let t=e.submitter&&e.submitter.hasAttribute(`formaction`)?e.submitter.getAttribute(`formaction`):e.target.getAttribute(`action`);if(!t)return;if(!t.startsWith(`https://action/`)){let e=new URL(t,Ut);if(t=i.parsePath(e.pathname+e.search),!t.startsWith(n))return}if(e.target.method.toUpperCase()!==`POST`)throw Error(`Only POST forms are supported for Actions`);let r=En.get(t);if(r){e.preventDefault();let t=new FormData(e.target,e.submitter);r.call({r:i,f:e.target},e.target.enctype===`multipart/form-data`?t:new URLSearchParams(t))}}Ge([`click`,`submit`]),document.addEventListener(`click`,d),e&&(document.addEventListener(`mousemove`,p,{passive:!0}),document.addEventListener(`focusin`,f,{passive:!0}),document.addEventListener(`touchstart`,f,{passive:!0})),document.addEventListener(`submit`,m),v(()=>{document.removeEventListener(`click`,d),e&&(document.removeEventListener(`mousemove`,p),document.removeEventListener(`focusin`,f),document.removeEventListener(`touchstart`,f)),document.removeEventListener(`submit`,m)})}}var kn=t((()=>{X(),G(),Dn(),Wt()}));function An(e){let t=e.replace(/^.*?#/,``);if(!t.startsWith(`/`)){let[,e=`/`]=window.location.hash.split(`#`,2);return`${e}#${t}`}return t}function jn(e){let t=()=>window.location.hash.slice(1),n=Tt();return Sn({get:t,set({value:e,replace:t,scroll:n,state:r}){t?window.history.replaceState(Dt(r),``,`#`+e):window.history.pushState(r,``,`#`+e);let i=e.indexOf(`#`);wn(i>=0?e.slice(i+1):``,n),Et()},init:e=>Cn(window,`hashchange`,Ot(e,e=>!n.confirm(e&&e<0?e:t()))),create:On(e.preload,e.explicitLinks,e.actionBase),utils:{go:e=>window.history.go(e),renderPath:e=>`#${e}`,parsePath:An,beforeLeave:n}})(e)}var Mn=t((()=>{kn(),Tn(),At()})),Nn=t((()=>{bn(),Tn(),X(),kn(),At(),Mn()}));function Pn(e){e=F({inactiveClass:`inactive`,activeClass:`active`},e);let[,t]=ge(e,[`href`,`state`,`class`,`activeClass`,`inactiveClass`,`end`]),n=sn(()=>e.href),r=cn(n),i=un(),a=d(()=>{let t=n();if(t===void 0)return[!1,!1];let r=jt(t.split(/[?#]/,1)[0]).toLowerCase(),a=decodeURI(jt(i.pathname).toLowerCase());return[e.end?r===a:a.startsWith(r+`/`)||a===r,r===a]});return(()=>{var n=Fn();return $e(n,F(t,{get href(){return r()||e.href},get state(){return JSON.stringify(e.state)},get classList(){return{...e.class&&{[e.class]:!0},[e.inactiveClass]:!a()[0],[e.activeClass]:a()[0],...t.classList}},link:``,get"aria-current"(){return a()[1]?`page`:void 0}}),!1,!1),n})()}var Fn,In=t((()=>{X(),G(),mn(),Wt(),Fn=K(`<a>`)})),Ln=t((()=>{G(),X(),Dn(),mn()})),Rn=t((()=>{Nn(),In(),At(),mn(),Wt(),Ln()})),zn,Bn=t((()=>{zn={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":2,"stroke-linecap":`round`,"stroke-linejoin":`round`}})),Vn,Hn,Un,Wn,Z,Q=t((()=>{X(),G(),Bn(),Vn=K(`<svg>`),Hn=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),Un=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),Wn=e=>{let[t,n]=ge(e,[`color`,`size`,`strokeWidth`,`children`,`class`,`name`,`iconNode`,`absoluteStrokeWidth`]);return(()=>{var e=Vn();return $e(e,F(zn,{get width(){return t.size??zn.width},get height(){return t.size??zn.height},get stroke(){return t.color??zn.stroke},get"stroke-width"(){return Y(()=>!!t.absoluteStrokeWidth)()?Number(t.strokeWidth??zn[`stroke-width`])*24/Number(t.size):Number(t.strokeWidth??zn[`stroke-width`])},get class(){return Un(`lucide`,`lucide-icon`,t.name==null?void 0:`lucide-${Hn(t?.name)}`,t.class==null?``:t.class)}},n),!0,!0),J(e,P(I,{get each(){return t.iconNode},children:([e,t])=>P(ht,F({component:e},t))})),e})()},Z=Wn})),Gn,Kn,qn,Jn=t((()=>{X(),Q(),Gn=[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]],Kn=e=>P(Z,F(e,{name:`Activity`,iconNode:Gn})),qn=Kn})),Yn,Xn,Zn,Qn=t((()=>{X(),Q(),Yn=[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]],Xn=e=>P(Z,F(e,{name:`ArrowLeft`,iconNode:Yn})),Zn=Xn})),$n,er,tr,nr=t((()=>{X(),Q(),$n=[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]],er=e=>P(Z,F(e,{name:`BookOpen`,iconNode:$n})),tr=er})),rr,ir,ar,or=t((()=>{X(),Q(),rr=[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]],ir=e=>P(Z,F(e,{name:`ChevronDown`,iconNode:rr})),ar=ir})),sr,cr,lr,ur=t((()=>{X(),Q(),sr=[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]],cr=e=>P(Z,F(e,{name:`ChevronRight`,iconNode:sr})),lr=cr})),dr,fr,pr,mr=t((()=>{X(),Q(),dr=[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]],fr=e=>P(Z,F(e,{name:`ChevronUp`,iconNode:dr})),pr=fr})),hr,gr,_r,vr=t((()=>{X(),Q(),hr=[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]],gr=e=>P(Z,F(e,{name:`CircleCheckBig`,iconNode:hr})),_r=gr})),yr,br,xr,Sr=t((()=>{X(),Q(),yr=[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]],br=e=>P(Z,F(e,{name:`CircleDashed`,iconNode:yr})),xr=br})),Cr,wr,Tr,Er=t((()=>{X(),Q(),Cr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]],wr=e=>P(Z,F(e,{name:`CircleX`,iconNode:Cr})),Tr=wr})),Dr,Or,kr,Ar=t((()=>{X(),Q(),Dr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]],Or=e=>P(Z,F(e,{name:`Clock`,iconNode:Dr})),kr=Or})),jr,Mr,Nr,Pr=t((()=>{X(),Q(),jr=[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]],Mr=e=>P(Z,F(e,{name:`CodeXml`,iconNode:jr})),Nr=Mr})),Fr,Ir,Lr,Rr=t((()=>{X(),Q(),Fr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M9 15h6`,key:`cctwl0`}],[`path`,{d:`M12 18v-6`,key:`17g6i2`}]],Ir=e=>P(Z,F(e,{name:`FilePlus`,iconNode:Fr})),Lr=Ir})),zr,Br,Vr,Hr=t((()=>{X(),Q(),zr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]],Br=e=>P(Z,F(e,{name:`FileText`,iconNode:zr})),Vr=Br})),Ur,Wr,Gr,Kr=t((()=>{X(),Q(),Ur=[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]],Wr=e=>P(Z,F(e,{name:`FolderOpen`,iconNode:Ur})),Gr=Wr})),qr,Jr,Yr,Xr=t((()=>{X(),Q(),qr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]],Jr=e=>P(Z,F(e,{name:`Globe`,iconNode:qr})),Yr=Jr})),Zr,Qr,$r,ei=t((()=>{X(),Q(),Zr=[[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}],[`path`,{d:`M10.41 10.41a2 2 0 1 1-2.83-2.83`,key:`1bzlo9`}],[`line`,{x1:`13.5`,x2:`6`,y1:`13.5`,y2:`21`,key:`1q0aeu`}],[`line`,{x1:`18`,x2:`21`,y1:`12`,y2:`15`,key:`5mozeu`}],[`path`,{d:`M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59`,key:`mmje98`}],[`path`,{d:`M21 15V5a2 2 0 0 0-2-2H9`,key:`43el77`}]],Qr=e=>P(Z,F(e,{name:`ImageOff`,iconNode:Zr})),$r=Qr})),ti,ni,ri,ii=t((()=>{X(),Q(),ti=[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]],ni=e=>P(Z,F(e,{name:`Image`,iconNode:ti})),ri=ni})),ai,oi,si,ci=t((()=>{X(),Q(),ai=[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]],oi=e=>P(Z,F(e,{name:`Languages`,iconNode:ai})),si=oi})),li,ui,di,fi=t((()=>{X(),Q(),li=[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]],ui=e=>P(Z,F(e,{name:`Layers`,iconNode:li})),di=ui})),pi,mi,hi,gi=t((()=>{X(),Q(),pi=[[`rect`,{width:`7`,height:`9`,x:`3`,y:`3`,rx:`1`,key:`10lvy0`}],[`rect`,{width:`7`,height:`5`,x:`14`,y:`3`,rx:`1`,key:`16une8`}],[`rect`,{width:`7`,height:`9`,x:`14`,y:`12`,rx:`1`,key:`1hutg5`}],[`rect`,{width:`7`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`ldoo1y`}]],mi=e=>P(Z,F(e,{name:`LayoutDashboard`,iconNode:pi})),hi=mi})),_i,vi,yi,bi=t((()=>{X(),Q(),_i=[[`path`,{d:`M12 20h9`,key:`t2du7b`}],[`path`,{d:`M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z`,key:`1ykcvy`}]],vi=e=>P(Z,F(e,{name:`PenLine`,iconNode:_i})),yi=vi})),xi,Si,Ci,wi=t((()=>{X(),Q(),xi=[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]],Si=e=>P(Z,F(e,{name:`Pen`,iconNode:xi})),Ci=Si})),Ti,Ei,Di,Oi=t((()=>{X(),Q(),Ti=[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]],Ei=e=>P(Z,F(e,{name:`Plus`,iconNode:Ti})),Di=Ei})),ki,Ai,ji,Mi=t((()=>{X(),Q(),ki=[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]],Ai=e=>P(Z,F(e,{name:`RefreshCw`,iconNode:ki})),ji=Ai})),Ni,Pi,Fi,Ii=t((()=>{X(),Q(),Ni=[[`path`,{d:`M3 7V5a2 2 0 0 1 2-2h2`,key:`aa7l1z`}],[`path`,{d:`M17 3h2a2 2 0 0 1 2 2v2`,key:`4qcy5o`}],[`path`,{d:`M21 17v2a2 2 0 0 1-2 2h-2`,key:`6vwrx8`}],[`path`,{d:`M7 21H5a2 2 0 0 1-2-2v-2`,key:`ioqczr`}],[`path`,{d:`M7 8h8`,key:`1jbsf9`}],[`path`,{d:`M7 12h10`,key:`b7w52i`}],[`path`,{d:`M7 16h6`,key:`1vyc9m`}]],Pi=e=>P(Z,F(e,{name:`ScanText`,iconNode:Ni})),Fi=Pi})),Li,Ri,zi,Bi=t((()=>{X(),Q(),Li=[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]],Ri=e=>P(Z,F(e,{name:`ShieldAlert`,iconNode:Li})),zi=Ri})),Vi,Hi,Ui,Wi=t((()=>{X(),Q(),Vi=[[`path`,{d:`M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z`,key:`4pj2yx`}],[`path`,{d:`M20 3v4`,key:`1olli1`}],[`path`,{d:`M22 5h-4`,key:`1gvqau`}],[`path`,{d:`M4 17v2`,key:`vumght`}],[`path`,{d:`M5 18H3`,key:`zchphs`}]],Hi=e=>P(Z,F(e,{name:`Sparkles`,iconNode:Vi})),Ui=Hi})),Gi,Ki,qi,Ji=t((()=>{X(),Q(),Gi=[[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6`,key:`4alrt4`}],[`path`,{d:`M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2`,key:`v07s0e`}],[`line`,{x1:`10`,x2:`10`,y1:`11`,y2:`17`,key:`1uufr5`}],[`line`,{x1:`14`,x2:`14`,y1:`11`,y2:`17`,key:`xtxkd`}]],Ki=e=>P(Z,F(e,{name:`Trash2`,iconNode:Gi})),qi=Ki})),Yi,Xi,Zi,Qi=t((()=>{X(),Q(),Yi=[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]],Xi=e=>P(Z,F(e,{name:`X`,iconNode:Yi})),Zi=Xi})),$i=t((()=>{Jn(),Qn(),nr(),or(),ur(),mr(),Sr(),Ar(),Rr(),Hr(),Kr(),Xr(),ei(),ii(),ci(),fi(),gi(),bi(),Oi(),Mi(),Ii(),Bi(),Wi(),Ji(),Qi()})),ea=t((()=>{vr()})),ta=t((()=>{Er()})),na=t((()=>{Pr()})),ra=t((()=>{wi()})),ia=t((()=>{ea(),ta(),na(),ra()})),aa=t((()=>{})),oa=t((()=>{})),sa=t((()=>{ia(),aa(),oa()})),ca=t((()=>{})),la=t((()=>{$i(),sa(),ca()}));X(),Rn(),la();var ua=K(`<div class="flex h-screen bg-slate-50 text-slate-800"><nav class="group flex w-14 flex-col gap-1 overflow-hidden bg-slate-900 px-2 py-4 transition-all duration-200 hover:w-48"><div class="mb-4 flex items-center gap-3 px-1"><span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-violet-600 text-xs font-bold text-white">W</span><span class="whitespace-nowrap text-sm font-semibold text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100">WebOCR</span></div></nav><main class="flex-1 overflow-y-auto">`),da=K(`<span class="flex h-8 w-8 shrink-0 items-center justify-center">`),fa=K(`<span class="whitespace-nowrap text-sm opacity-0 transition-opacity duration-200 group-hover:opacity-100">`),pa=[{href:`/`,label:`Dashboard`,Icon:hi},{href:`/jobs`,label:`Jobs`,Icon:ri},{href:`/library`,label:`Library`,Icon:tr}];function ma(e){return(()=>{var t=ua(),n=t.firstChild;n.firstChild;var r=n.nextSibling;return J(n,()=>pa.map(e=>P(Pn,{get href(){return e.href},get end(){return e.href===`/`},class:`flex items-center gap-3 rounded-lg px-1 py-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-white`,activeClass:`bg-slate-800 text-white!`,get children(){return[(()=>{var t=da();return J(t,P(e.Icon,{class:`h-5 w-5`})),t})(),(()=>{var t=fa();return J(t,()=>e.label),t})()]}})),null),J(r,()=>e.children),t})()}X(),G(),la();var ha=K(`<span class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700">`),ga=K(`<span class="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-500">`),_a=K(`<span class="inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-xs text-red-600">`),va=K(`<div class="min-h-screen bg-slate-50 px-4 py-10"><div class="mx-auto max-w-2xl space-y-8"><div class="flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div><h1 class="text-xl font-semibold text-slate-800">Web OCR Server</h1><p class="text-sm text-slate-500">ASP.NET Core · Manga-OCR · Opus-MT</p></div><div class=ml-auto></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">Server info</span></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">API Endpoints</span></div><ul class="divide-y divide-slate-50">`),ya=K(`<div class="flex items-center gap-2 px-5 py-4 text-sm text-red-600">`),ba=K(`<div class="px-5 py-4 text-sm text-slate-400">Loading…`),xa=K(`<dl class="divide-y divide-slate-50 text-sm"><div class="flex items-center gap-3 px-5 py-3"><dt class="w-36 shrink-0 text-slate-500">Version</dt><dd class="font-medium text-slate-800"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> OCR models</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> Translate</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-center gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> DeepL</dt><dd>`),Sa=K(`<li class="flex items-center gap-4 px-5 py-3.5 text-sm"><span></span><code class="w-28 shrink-0 text-slate-700"></code><span></span><span class=text-slate-500>`);function Ca(e){return P(L,{get when(){return e.ok!==null},get fallback(){return(()=>{var t=ga();return J(t,P(xr,{class:`h-3 w-3 animate-spin`}),null),J(t,()=>e.label,null),t})()},get children(){return P(L,{get when(){return e.ok},get fallback(){return(()=>{var t=_a();return J(t,P(Tr,{class:`h-3 w-3`}),null),J(t,()=>e.label,null),t})()},get children(){var t=ha();return J(t,P(_r,{class:`h-3 w-3`}),null),J(t,()=>e.label,null),t}})}})}var wa=[{method:`GET`,path:`/health`,desc:`Server status, version, model paths`,Icon:qn,color:`text-sky-600`},{method:`POST`,path:`/ocr`,desc:`Base64 image → Japanese text`,Icon:Fi,color:`text-violet-600`},{method:`POST`,path:`/translate`,desc:`Japanese → English (local Opus-MT or DeepL)`,Icon:si,color:`text-amber-600`},{method:`POST`,path:`/analyze`,desc:`Tokenise text + dictionary lookup`,Icon:tr,color:`text-emerald-600`}],Ta={GET:`bg-sky-50 text-sky-700`,POST:`bg-violet-50 text-violet-700`};function Ea(){let[e,t]=s(null),[n,r]=s(null);_(()=>{fetch(`/health`).then(e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);return e.json()}).then(t).catch(e=>r(String(e)))});let i=()=>{if(n())return!1;let t=e();return t?t.status===`ok`:null},a=()=>{if(n())return`error`;let t=e();return t?t.status:`connecting`};return(()=>{var t=va(),r=t.firstChild.firstChild,o=r.firstChild,s=o.nextSibling.nextSibling,c=r.nextSibling;c.firstChild;var u=c.nextSibling.firstChild.nextSibling;return J(o,P(Nr,{class:`h-6 w-6 text-slate-700`})),J(s,P(Ca,{get ok(){return i()},get label(){return a()}})),J(c,P(L,{get when(){return!n()},get fallback(){return(()=>{var e=ya();return J(e,P(zi,{class:`h-4 w-4 shrink-0`}),null),J(e,n,null),e})()},get children(){return P(L,{get when(){return e()},get fallback(){return ba()},children:e=>(()=>{var t=xa(),n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild,o=a.firstChild,s=a.nextSibling,c=i.nextSibling,l=c.firstChild,u=l.firstChild,d=l.nextSibling,f=c.nextSibling.firstChild,p=f.firstChild,m=f.nextSibling;return J(r,()=>e().version),J(a,P(Gr,{class:`h-3.5 w-3.5`}),o),J(s,()=>e().ocr_models_dir),J(l,P(Gr,{class:`h-3.5 w-3.5`}),u),J(d,()=>e().translate_models_dir),J(f,P(Yr,{class:`h-3.5 w-3.5`}),p),J(m,P(Ca,{get ok(){return e().deepl_available},get label(){return e().deepl_available?`configured`:`not configured`}})),t})()})}}),null),J(u,P(I,{each:wa,children:({method:e,path:t,desc:n,Icon:r,color:i})=>(()=>{var a=Sa(),o=a.firstChild,s=o.nextSibling,c=s.nextSibling,u=c.nextSibling;return J(o,e),J(s,t),Je(c,`shrink-0 ${i}`),J(c,P(r,{class:`h-4 w-4`})),J(u,n),l(()=>Je(o,`w-12 shrink-0 rounded px-1.5 py-0.5 text-center text-xs font-semibold ${Ta[e]??``}`)),a})()})),t})()}function Da(e){return e.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function Oa(e){return e.replace(/([A-Z])/g,e=>`_${e.toLowerCase()}`)}function ka(e){if(Array.isArray(e))return e.map(ka);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Da(n)]=ka(r);return t}return e}function Aa(e){if(Array.isArray(e))return e.map(Aa);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Oa(n)]=Aa(r);return t}return e}async function $(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`,...t?.headers},...t});if(!n.ok){let e=await n.text().catch(()=>n.statusText);throw Error(`API ${n.status}: ${e}`)}if(n.status!==204)return ka(await n.json())}function ja(e={}){let t=new URLSearchParams;e.page!==void 0&&t.set(`page`,String(e.page)),e.pageSize!==void 0&&t.set(`page_size`,String(e.pageSize)),e.status&&t.set(`status`,e.status),e.chapterId!==void 0&&t.set(`chapter_id`,String(e.chapterId));let n=t.toString();return $(`/api/portal/jobs${n?`?${n}`:``}`)}function Ma(e){return $(`/api/portal/jobs/${e}`)}function Na(e,t){return $(`/api/portal/jobs/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Pa(e){return $(`/api/portal/jobs/${e}/bubbles`)}function Fa(e,t){return $(`/api/portal/jobs/${e}/bubbles`,{method:`POST`,body:JSON.stringify(Aa(t))})}function Ia(e,t,n){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`PUT`,body:JSON.stringify(Aa(n))})}function La(e,t){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`DELETE`})}function Ra(e){return $(`/api/portal/jobs/${e}/redetect`,{method:`POST`})}function za(e){return $(`/api/portal/jobs/${e}/retranslate`,{method:`POST`})}function Ba(e){return $(`/api/portal/jobs/${e}/rerender`,{method:`POST`})}function Va(){return $(`/api/portal/volumes`)}function Ha(e){return $(`/api/portal/volumes`,{method:`POST`,body:JSON.stringify(Aa(e))})}function Ua(e,t){return $(`/api/portal/volumes/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Wa(e){return $(`/api/portal/volumes/${e}`,{method:`DELETE`})}function Ga(e={}){let t=new URLSearchParams;e.volumeId!==void 0&&t.set(`volume_id`,String(e.volumeId));let n=t.toString();return $(`/api/portal/chapters${n?`?${n}`:``}`)}function Ka(e){return $(`/api/portal/chapters`,{method:`POST`,body:JSON.stringify(Aa(e))})}function qa(e,t){return $(`/api/portal/chapters/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Ja(e){return $(`/api/portal/chapters/${e}`,{method:`DELETE`})}function Ya(e){return $(`/api/portal/chapters/${e}/jobs`)}function Xa(e){return`/api/portal/jobs/${e}/original`}function Za(e){return`/api/portal/jobs/${e}/result`}var Qa=t((()=>{})),$a=n({JobsListPage:()=>no,StatusBadge:()=>eo});function eo(e){let t=()=>{switch(e.status){case`done`:return{cls:`bg-green-100 text-green-700`,Icon:_r,label:`Done`};case`processing`:return{cls:`bg-yellow-100 text-yellow-700`,Icon:kr,label:`Processing`};case`error`:return{cls:`bg-red-100 text-red-700`,Icon:Tr,label:`Error`};default:return{cls:`bg-slate-100 text-slate-600`,Icon:kr,label:String(e.status)}}};return(()=>{var e=ro();return J(e,()=>P(t()?.Icon??kr,{class:`h-3 w-3`}),null),J(e,()=>t()?.label??``,null),l(()=>Je(e,`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${t()?.cls??``}`)),e})()}function to(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=io(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling.firstChild,s=o.nextSibling.firstChild,c=s.firstChild,u=s.nextSibling;return Ye(n,`click`,e.onClick,!0),J(a,P(eo,{get status(){return e.job.status}})),J(o,()=>e.job.title),J(s,P(di,{class:`h-3 w-3`}),c),J(s,()=>e.job.bubbleCount,c),J(u,()=>new Date(e.job.createdAt).toLocaleDateString()),l(n=>{var r=t(),a=e.job.title;return r!==n.e&&q(i,`src`,n.e=r),a!==n.t&&q(i,`alt`,n.t=a),n},{e:void 0,t:void 0}),n})()}function no(){let e=ln(),[t,n]=s(``),[r,i]=s(``),[a]=p(t,e=>ja({pageSize:100,status:e||void 0})),o=()=>{let e=r().toLowerCase();return(a()?.items??[]).filter(t=>!e||t.title.toLowerCase().includes(e))};return(()=>{var s=so(),c=s.firstChild,u=c.firstChild,d=c.nextSibling.firstChild,f=d.nextSibling;return J(u,P(ri,{class:`h-5 w-5 text-violet-600`})),d.$$input=e=>i(e.currentTarget.value),f.addEventListener(`change`,e=>n(e.currentTarget.value)),J(f,()=>fo.map(e=>(()=>{var t=co();return J(t,()=>e.label),l(()=>t.value=e.value),t})())),J(s,P(L,{get when(){return a.loading},get children(){var e=ao();return J(e,()=>Array.from({length:10}).map(()=>lo())),e}}),null),J(s,P(L,{get when(){return a.error},get children(){var e=oo();return e.firstChild,J(e,()=>String(a.error),null),e}}),null),J(s,P(L,{get when(){return Y(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return o().length>0},get fallback(){return(()=>{var e=uo(),t=e.firstChild;return J(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var t=ao();return J(t,P(I,{get each(){return o()},children:t=>P(to,{job:t,onClick:()=>e(`/jobs/${t.id}`)})})),t}})}}),null),l(()=>d.value=r()),l(()=>f.value=t()),s})()}var ro,io,ao,oo,so,co,lo,uo,fo,po=t((()=>{X(),G(),Rn(),la(),Qa(),ro=K(`<span>`),io=K(`<button class="group flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-violet-500"><div class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><div class="absolute right-2 top-2"></div></div><div class="flex flex-col gap-1 p-3"><p class="truncate text-sm font-medium text-slate-800"></p><div class="flex items-center gap-3 text-xs text-slate-500"><span class="flex items-center gap-1"> bubbles</span><span class=ml-auto>`,!0,!1,!1),ao=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),oo=K(`<div class="rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load jobs: `),so=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Jobs</h1></div><div class="mb-6 flex flex-wrap gap-3"><input type=search placeholder="Search jobs…"class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-400"><select class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-400">`),co=K(`<option>`),lo=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),uo=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No jobs yet.</p><p class="max-w-xs text-center text-xs text-slate-400">Upload pages via the extension or API to see translation jobs here.`),fo=[{value:``,label:`All statuses`},{value:`done`,label:`Done`},{value:`processing`,label:`Processing`},{value:`error`,label:`Error`}],Ge([`click`,`input`])}));function mo(e,t,n,r){let{x:i,y:a,w:o,h:s}=t;switch(e){case`TL`:i+=n,a+=r,o-=n,s-=r;break;case`T`:a+=r,s-=r;break;case`TR`:a+=r,o+=n,s-=r;break;case`L`:i+=n,o-=n;break;case`R`:o+=n;break;case`BL`:i+=n,o-=n,s+=r;break;case`B`:s+=r;break;case`BR`:o+=n,s+=r;break}return o<5&&(o=5),s<5&&(s=5),{x:i,y:a,w:o,h:s}}function ho(e){let t,n,[r,i]=s({scale:1,offsetX:0,offsetY:0}),[a,o]=s({kind:`none`});function c(){if(!t||!e.imageWidth||!e.imageHeight)return;let n=t.clientWidth,r=t.clientHeight;if(n===0||r===0)return;let a=n/e.imageWidth,o=r/e.imageHeight,s=Math.min(a,o),c=e.imageWidth*s,l=e.imageHeight*s;i({scale:s,offsetX:(n-c)/2,offsetY:(r-l)/2})}function u(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return{x:e*n+i,y:t*n+a}}function d(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return n===0?{x:0,y:0}:{x:(e-i)/n,y:(t-a)/n}}function f(e){let t=n.getBoundingClientRect();return d(e.clientX-t.left,e.clientY-t.top)}function p(e){let t=a();return t.kind===`moving`&&t.bubbleIndex===e.bubbleIndex?{x:e.bubbleX+(t.curImgX-t.startImgX),y:e.bubbleY+(t.curImgY-t.startImgY),w:e.bubbleW,h:e.bubbleH}:t.kind===`resizing`&&t.bubbleIndex===e.bubbleIndex?mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY):{x:e.bubbleX,y:e.bubbleY,w:e.bubbleW,h:e.bubbleH}}function m(){let e=a();return e.kind===`drawing`?{x:Math.min(e.startImgX,e.curImgX),y:Math.min(e.startImgY,e.curImgY),w:Math.abs(e.curImgX-e.startImgX),h:Math.abs(e.curImgY-e.startImgY)}:null}function h(e){let t=a();if(t.kind===`none`)return;e.preventDefault();let n=f(e);(t.kind===`moving`||t.kind===`resizing`||t.kind===`drawing`)&&o({...t,curImgX:n.x,curImgY:n.y})}function g(){let t=a();if(t.kind===`moving`){let n=t.curImgX-t.startImgX,r=t.curImgY-t.startImgY;(Math.abs(n)>1||Math.abs(r)>1)&&e.onMove(t.bubbleIndex,n,r)}else if(t.kind===`resizing`){let n=mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY);e.onResize(t.bubbleIndex,n.x,n.y,n.w,n.h)}else if(t.kind===`drawing`){let n=Math.min(t.startImgX,t.curImgX),r=Math.min(t.startImgY,t.curImgY),i=Math.abs(t.curImgX-t.startImgX),a=Math.abs(t.curImgY-t.startImgY);i>5&&a>5?e.onDraw(n,r,i,a):e.onSelect(null)}o({kind:`none`}),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)}function y(e){e.preventDefault(),g()}function b(){window.addEventListener(`mousemove`,h),window.addEventListener(`mouseup`,y)}function x(t){if(t.preventDefault(),!e.drawMode){e.onSelect(null);return}let n=f(t);o({kind:`drawing`,startImgX:n.x,startImgY:n.y,curImgX:n.x,curImgY:n.y}),b()}function S(t,n){t.preventDefault(),t.stopPropagation(),e.onSelect(n.bubbleIndex);let r=f(t);o({kind:`moving`,bubbleIndex:n.bubbleIndex,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}function C(e,t,n){e.preventDefault(),e.stopPropagation();let r=f(e);o({kind:`resizing`,bubbleIndex:t.bubbleIndex,handle:n,origX:t.bubbleX,origY:t.bubbleY,origW:t.bubbleW,origH:t.bubbleH,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}return _(()=>{c();let e=new ResizeObserver(()=>c());e.observe(t),v(()=>{e.disconnect(),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)})}),(()=>{var r=go(),i=r.firstChild,o=i.nextSibling,s=t;typeof s==`function`?et(s,r):t=r,i.addEventListener(`load`,c),q(i,`draggable`,!1),o.$$mousedown=x;var d=n;return typeof d==`function`?et(d,o):n=o,J(o,P(I,{get each(){return e.bubbles},children:t=>{let n=()=>p(t),r=()=>{let e=n(),t=u(e.x,e.y),r=u(e.x+e.w,e.y+e.h);return{x:t.x,y:t.y,w:r.x-t.x,h:r.y-t.y}},i=()=>e.selectedIndex===t.bubbleIndex,a=()=>t.isExcluded?`#9ca3af`:i()?`#7c3aed`:t.isManuallyAdded?`#10b981`:`#3b82f6`,o=()=>t.isExcluded?`rgba(0,0,0,0.15)`:i()?`rgba(124,58,237,0.1)`:`rgba(59,130,246,0.05)`;return(()=>{var e=vo(),s=e.firstChild,c=s.nextSibling,d=c.nextSibling;return s.$$mousedown=e=>S(e,t),J(e,P(L,{get when(){return t.isExcluded},get children(){var e=_o();return l(t=>{var n=r().x,i=r().y,a=r().x+r().w,o=r().y+r().h;return n!==t.e&&q(e,`x1`,t.e=n),i!==t.t&&q(e,`y1`,t.t=i),a!==t.a&&q(e,`x2`,t.a=a),o!==t.o&&q(e,`y2`,t.o=o),t},{e:void 0,t:void 0,a:void 0,o:void 0}),e}}),c),J(c,()=>t.bubbleIndex),J(d,()=>t.bubbleIndex),J(e,P(L,{get when(){return i()},get children(){return P(I,{each:xo,children:e=>{let[r,i]=So[e],a=()=>{let e=n();return u(e.x+r*e.w,e.y+i*e.h)};return(()=>{var n=yo();return n.$$mousedown=n=>C(n,t,e),l(t=>{var r=a().x-4,i=a().y-4,o=Co[e];return r!==t.e&&q(n,`x`,t.e=r),i!==t.t&&q(n,`y`,t.t=i),o!==t.a&&Qe(n,`cursor`,t.a=o),t},{e:void 0,t:void 0,a:void 0}),n})()}})}}),null),l(e=>{var t=r().x,n=r().y,l=r().w,u=r().h,f=o(),p=a(),m=i()?3:2,h=r().x+4,g=r().y+13,_=r().x+3,v=r().y+12;return t!==e.e&&q(s,`x`,e.e=t),n!==e.t&&q(s,`y`,e.t=n),l!==e.a&&q(s,`width`,e.a=l),u!==e.o&&q(s,`height`,e.o=u),f!==e.i&&q(s,`fill`,e.i=f),p!==e.n&&q(s,`stroke`,e.n=p),m!==e.s&&q(s,`stroke-width`,e.s=m),h!==e.h&&q(c,`x`,e.h=h),g!==e.r&&q(c,`y`,e.r=g),_!==e.d&&q(d,`x`,e.d=_),v!==e.l&&q(d,`y`,e.l=v),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0,h:void 0,r:void 0,d:void 0,l:void 0}),e})()}}),null),J(o,P(L,{get when(){return m()},children:e=>{let t=()=>{let t=e(),n=u(t.x,t.y),r=u(t.x+t.w,t.y+t.h);return{x:n.x,y:n.y,w:r.x-n.x,h:r.y-n.y}};return(()=>{var e=bo();return l(n=>{var r=t().x,i=t().y,a=t().w,o=t().h;return r!==n.e&&q(e,`x`,n.e=r),i!==n.t&&q(e,`y`,n.t=i),a!==n.a&&q(e,`width`,n.a=a),o!==n.o&&q(e,`height`,n.o=o),n},{e:void 0,t:void 0,a:void 0,o:void 0}),e})()}}),null),l(t=>{var n=e.imageUrl,r=a().kind===`moving`?`grabbing`:a().kind===`drawing`||e.drawMode?`crosshair`:`default`;return n!==t.e&&q(i,`src`,t.e=n),r!==t.t&&Qe(o,`cursor`,t.t=r),t},{e:void 0,t:void 0}),r})()}var go,_o,vo,yo,bo,xo,So,Co,wo=t((()=>{X(),G(),go=K(`<div class="relative overflow-hidden bg-slate-900 w-full h-full select-none"><img alt="manga page"class="w-full h-full object-contain pointer-events-none"><svg class="absolute inset-0 w-full h-full">`),_o=K(`<svg><line stroke=#9ca3af stroke-width=1 style=pointer-events:none></svg>`,!1,!0,!1),vo=K(`<svg><g><rect style=cursor:grab></rect><text font-size=10 fill=black style=pointer-events:none;user-select:none></text><text font-size=10 fill=white style=pointer-events:none;user-select:none></svg>`,!1,!0,!1),yo=K(`<svg><rect width=8 height=8 fill=white stroke=#7c3aed stroke-width=1.5></svg>`,!1,!0,!1),bo=K(`<svg><rect fill=rgba(16,185,129,0.1) stroke=#10b981 stroke-width=2 stroke-dasharray=4,2 style=pointer-events:none></svg>`,!1,!0,!1),xo=[`TL`,`T`,`TR`,`L`,`R`,`BL`,`B`,`BR`],So={TL:[0,0],T:[.5,0],TR:[1,0],L:[0,.5],R:[1,.5],BL:[0,1],B:[.5,1],BR:[1,1]},Co={TL:`nw-resize`,T:`n-resize`,TR:`ne-resize`,L:`w-resize`,R:`e-resize`,BL:`sw-resize`,B:`s-resize`,BR:`se-resize`},Ge([`mousedown`])}));function To(e){let t;return u(()=>{let n=e.selectedIndex;n!==null&&(t?.querySelector(`[data-bubble-idx="${n}"]`))?.scrollIntoView({behavior:`smooth`,block:`nearest`})}),(()=>{var n=Eo(),r=n.firstChild,i=r.firstChild,a=i.firstChild.nextSibling;a.nextSibling;var o=i.nextSibling,s=r.nextSibling;J(i,()=>e.bubbles.length,a),Ye(o,`click`,e.onAddBubble,!0),J(o,P(Di,{class:`h-3 w-3`}),null),J(o,P(yi,{class:`h-3 w-3`}),null);var c=t;return typeof c==`function`?et(c,s):t=s,J(s,P(L,{get when(){return e.bubbles.length>0},get fallback(){return Do()},get children(){return P(I,{get each(){return e.bubbles},children:t=>{let n=()=>e.selectedIndex===t.bubbleIndex;return(()=>{var r=Ao(),i=r.firstChild,a=i.firstChild;a.firstChild;var o=i.nextSibling;return r.$$click=()=>e.onSelect(n()?null:t.bubbleIndex),J(a,()=>t.bubbleIndex,null),J(i,P(L,{get when(){return t.isManuallyAdded},get children(){return Oo()}}),null),J(i,P(L,{get when(){return t.isExcluded},get children(){return ko()}}),null),J(o,()=>t.sourceText.slice(0,20)||`(empty)`),l(e=>{var i=t.bubbleIndex,s=`w-full border-b border-slate-100 px-3 py-2 text-left transition-colors ${n()?`border-l-2 border-l-violet-500 bg-violet-50`:`hover:bg-slate-50`} ${t.isExcluded?`opacity-50`:``}`,c=`font-mono text-xs font-medium ${n()?`text-violet-700`:`text-slate-500`}`,l=`mt-0.5 truncate text-xs ${t.isExcluded?`line-through text-slate-400`:`text-slate-600`}`;return i!==e.e&&q(r,`data-bubble-idx`,e.e=i),s!==e.t&&Je(r,e.t=s),c!==e.a&&Je(a,e.a=c),l!==e.o&&Je(o,e.o=l),e},{e:void 0,t:void 0,a:void 0,o:void 0}),r})()}})}})),n})()}var Eo,Do,Oo,ko,Ao,jo=t((()=>{X(),G(),la(),Eo=K(`<div class="flex flex-col h-full"><div class="flex items-center gap-2 border-b border-slate-100 px-3 py-2 shrink-0"><span class="flex-1 text-xs font-semibold uppercase tracking-wide text-slate-500">Bubbles (<!>)</span><button class="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium text-slate-600 hover:bg-slate-100 active:bg-slate-200 transition-colors"title="Draw a new bubble on the canvas"></button></div><div class="flex-1 overflow-y-auto">`),Do=K(`<div class="px-3 py-6 text-center text-xs text-slate-400">No bubbles detected`),Oo=K(`<span class="rounded bg-emerald-100 px-1 py-0.5 text-[10px] font-medium text-emerald-700">M`),ko=K(`<span class="rounded bg-slate-100 px-1 py-0.5 text-[10px] font-medium text-slate-500">×`),Ao=K(`<button><div class="flex items-center gap-1.5"><span>#</span></div><p>`),Ge([`click`])}));function Mo(e){return(()=>{var t=Po(),n=t.firstChild,r=n.nextSibling;return J(n,()=>e.label),r.addEventListener(`change`,t=>e.onChange(parseFloat(t.currentTarget.value)||0)),r.$$input=t=>e.onInput(parseFloat(t.currentTarget.value)||0),l(()=>r.value=e.value),t})()}function No(e){let[t,n]=s(0),[r,i]=s(0),[a,o]=s(0),[c,d]=s(0),[f,p]=s(``),[m,h]=s(``),[_,v]=s(!1);return u(g(()=>e.bubble,()=>{let t=e.bubble;t&&(n(t.bubbleX),i(t.bubbleY),o(t.bubbleW),d(t.bubbleH),p(t.sourceText),h(t.translatedText),v(t.isExcluded))})),(()=>{var s=Fo();return s.firstChild,J(s,P(L,{get when(){return e.bubble},get fallback(){return Io()},children:s=>(()=>{var u=Ro(),g=u.firstChild,y=g.firstChild;y.firstChild;var b=y.nextSibling,x=g.nextSibling,S=x.firstChild.nextSibling,C=x.nextSibling,w=C.firstChild.nextSibling,ee=C.nextSibling,T=ee.firstChild.nextSibling,E=ee.nextSibling,D=E.firstChild,O=E.nextSibling.firstChild,k=O.firstChild;return J(y,()=>s().bubbleIndex,null),J(g,P(L,{get when(){return s().isManuallyAdded},get children(){return Lo()}}),b),J(b,(()=>{var e=Y(()=>!!s().isManuallyAdded);return()=>e()?`N/A conf`:`${Math.round(s().confidence*100)}% conf`})()),J(S,P(Mo,{label:`X`,get value(){return t()},onInput:n,onChange:t=>e.onUpdate({bubbleX:t})}),null),J(S,P(Mo,{label:`Y`,get value(){return r()},onInput:i,onChange:t=>e.onUpdate({bubbleY:t})}),null),J(S,P(Mo,{label:`W`,get value(){return a()},onInput:o,onChange:t=>e.onUpdate({bubbleW:t})}),null),J(S,P(Mo,{label:`H`,get value(){return c()},onInput:d,onChange:t=>e.onUpdate({bubbleH:t})}),null),w.addEventListener(`blur`,t=>e.onUpdate({sourceText:t.currentTarget.value})),w.$$input=e=>p(e.currentTarget.value),T.addEventListener(`blur`,t=>e.onUpdate({translatedText:t.currentTarget.value})),T.$$input=e=>h(e.currentTarget.value),D.addEventListener(`change`,t=>{let n=t.currentTarget.checked;v(n),e.onUpdate({isExcluded:n})}),Ye(O,`click`,e.onDelete,!0),J(O,P(qi,{class:`h-3.5 w-3.5`}),k),l(()=>w.value=f()),l(()=>T.value=m()),l(()=>D.checked=_()),u})()}),null),s})()}var Po,Fo,Io,Lo,Ro,zo=t((()=>{X(),G(),la(),Po=K(`<label class="flex flex-col gap-0.5"><span class="text-[10px] text-slate-400"></span><input type=number step=0.1 class="rounded border border-slate-200 px-2 py-1 text-xs focus:border-violet-400 focus:outline-none">`),Fo=K(`<div class="flex h-full flex-col"><div class="shrink-0 border-b border-slate-100 px-3 py-2"><span class="text-xs font-semibold uppercase tracking-wide text-slate-500">Editor`),Io=K(`<div class="flex flex-1 items-center justify-center text-xs text-slate-400">Select a bubble to edit`),Lo=K(`<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700">Manual`),Ro=K(`<div class="flex flex-1 flex-col gap-4 overflow-y-auto p-3"><div class="flex items-center gap-2"><span class="text-sm font-medium text-slate-700">Bubble #</span><span class="ml-auto text-[10px] text-slate-400"></span></div><div><p class="mb-1.5 text-xs font-medium text-slate-500">Position &amp; Size (px)</p><div class="grid grid-cols-2 gap-1.5"></div></div><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Source</span><textarea rows=3 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Translation</span><textarea rows=4 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><div class="flex items-center gap-2"><input id=exclude-check type=checkbox class="h-3.5 w-3.5 rounded accent-violet-600"><label for=exclude-check class="cursor-pointer text-xs text-slate-600">Exclude from render</label></div><div class="mt-auto border-t border-slate-100 pt-3"><button class="flex w-full items-center justify-center gap-1.5 rounded-lg bg-red-50 px-3 py-2 text-xs font-medium text-red-600 transition-colors hover:bg-red-100 active:bg-red-200">Delete bubble`),Ge([`input`,`click`])})),Bo=n({StudioPage:()=>Vo});function Vo(){let e=dn(),t=ln(),[n]=p(()=>e.id,Ma),[r,{refetch:i}]=p(()=>e.id,Pa),[a,o]=s(null),[c,u]=s(`result`),[d,f]=s(!1),[m,h]=s(!1),[g,_]=s(!1),[v,y]=s(!1),b=()=>r()??[],x=()=>{let e=a();return e===null?null:b().find(t=>t.bubbleIndex===e)??null};function S(e){o(e===a()?null:e)}async function C(t,n,r){let a=b().find(e=>e.bubbleIndex===t);a&&(await Ia(e.id,t,{bubbleX:a.bubbleX+n,bubbleY:a.bubbleY+r,bubbleW:a.bubbleW,bubbleH:a.bubbleH}),i())}async function w(t,n,r,a,o){await Ia(e.id,t,{bubbleX:n,bubbleY:r,bubbleW:a,bubbleH:o}),i()}async function ee(t,n,r,a){let s=await Fa(e.id,{x:t,y:n,w:r,h:a});await i(),o(s.bubbleIndex)}async function T(t){let n=x();n&&(await Ia(e.id,n.bubbleIndex,t),i())}async function E(){let t=x();t&&(await La(e.id,t.bubbleIndex),o(null),i())}async function D(){for(let t=0;t<120;t++)if(await new Promise(e=>setTimeout(e,1500)),(await Ma(e.id)).status!==`processing`)return}async function O(){f(!0);try{await Ra(e.id),await D(),await i()}finally{f(!1)}}async function k(){h(!0);try{await za(e.id),await D(),await i()}finally{h(!1)}}async function A(){_(!0);try{await Ba(e.id),await D(),await i()}finally{_(!1)}}let j=()=>({bubbles:b(),selectedIndex:a(),drawMode:v(),onSelect:S,onMove:C,onResize:w,onDraw:async(e,t,n,r)=>{y(!1),await ee(e,t,n,r)}});return(()=>{var r=Wo(),i=r.firstChild,o=i.firstChild,s=o.nextSibling,f=s.nextSibling.nextSibling,p=f.firstChild,h=f.nextSibling,_=h.firstChild,v=h.nextSibling,C=v.firstChild;return o.$$click=()=>t(`/jobs`),J(o,P(Zn,{class:`h-4 w-4`})),J(i,P(L,{get when(){return n()},get fallback(){return Go()},children:e=>[(()=>{var t=Ko();return J(t,()=>e().title),t})(),P(eo,{get status(){return e().status}})]}),s),J(s,()=>[`original`,`result`,`sidebyside`].map(e=>(()=>{var t=qo();return t.$$click=()=>u(e),J(t,e===`original`?`Original`:e===`result`?`Result`:`Side by side`),l(()=>Je(t,`px-2.5 py-1.5 font-medium transition-colors ${c()===e?`bg-violet-600 text-white`:`bg-white text-slate-600 hover:bg-slate-50`}`)),t})())),f.$$click=O,J(f,P(L,{get when(){return d()},get fallback(){return P(Fi,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),p),h.$$click=k,J(h,P(L,{get when(){return m()},get fallback(){return P(Ui,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),_),v.$$click=A,J(v,P(L,{get when(){return g()},get fallback(){return P(ji,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),C),J(r,P(L,{get when(){return n.loading},get children(){return Ho()}}),null),J(r,P(L,{get when(){return n.error},get children(){var e=Uo();return e.firstChild,J(e,()=>String(n.error),null),e}}),null),J(r,P(L,{get when(){return Y(()=>!n.loading&&!n.error)()&&n()},children:t=>(()=>{var n=Yo(),r=n.firstChild,i=r.nextSibling,o=i.nextSibling;return J(r,P(To,{get bubbles(){return b()},get selectedIndex(){return a()},onSelect:S,onAddBubble:()=>y(!0)})),J(i,P(ve,{get children(){return[P(ye,{get when(){return c()===`original`},get children(){return P(ho,F(j,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}}),P(ye,{get when(){return c()===`result`},get children(){return P(L,{get when(){return t().resultImagePath},get fallback(){return(()=>{var e=Xo(),t=e.firstChild;return J(e,P($r,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){return P(ho,F(j,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}})}}),P(ye,{get when(){return c()===`sidebyside`},get children(){var n=Jo(),r=n.firstChild,i=r.nextSibling;return J(r,P(ho,F(j,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))),J(i,P(L,{get when(){return t().resultImagePath},get fallback(){return(()=>{var e=Zo(),t=e.firstChild;return J(e,P($r,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){return P(ho,F(j,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}})),n}})]}})),J(o,P(No,{get bubble(){return x()},onUpdate:T,onDelete:E})),n})()}),null),l(e=>{var t=d(),n=m(),r=g();return t!==e.e&&(f.disabled=e.e=t),n!==e.t&&(h.disabled=e.t=n),r!==e.a&&(v.disabled=e.a=r),e},{e:void 0,t:void 0,a:void 0}),r})()}var Ho,Uo,Wo,Go,Ko,qo,Jo,Yo,Xo,Zo,Qo=t((()=>{X(),G(),Rn(),la(),Qa(),wo(),jo(),zo(),po(),Ho=K(`<div class="flex flex-1 items-center justify-center"><p class="text-sm text-slate-400">Loading job…`),Uo=K(`<div class="m-6 rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load job: `),Wo=K(`<div class="flex h-screen flex-col bg-slate-50"><header class="flex shrink-0 items-center gap-2 border-b border-slate-200 bg-white px-3 py-2 shadow-sm"><button class="flex items-center gap-1 rounded p-1 text-slate-500 hover:bg-slate-100 transition-colors"title="Back to jobs"aria-label="Back to jobs"></button><div class="ml-4 flex overflow-hidden rounded-lg border border-slate-200 text-xs"></div><div class=flex-1></div><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-detect bubbles"aria-label="Re-detect bubbles">Re-detect</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title=Re-translate aria-label=Re-translate>Re-translate</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-render image"aria-label="Re-render image">Re-render`),Go=K(`<div class="h-4 w-40 animate-pulse rounded bg-slate-200">`),Ko=K(`<h1 class="max-w-xs truncate text-sm font-semibold text-slate-800">`),qo=K(`<button>`),Jo=K(`<div class="flex h-full w-full"><div class="flex-1 overflow-hidden border-r border-slate-700"></div><div class="flex-1 overflow-hidden">`),Yo=K(`<div class="flex flex-1 overflow-hidden"><aside class="flex w-52 shrink-0 flex-col border-r border-slate-200 bg-white"></aside><main class="relative flex flex-1 overflow-hidden"></main><aside class="flex w-64 shrink-0 flex-col border-l border-slate-200 bg-white">`),Xo=K(`<div class="flex flex-1 flex-col items-center justify-center gap-3 text-slate-400"><p class=text-sm>No result image yet</p><p class=text-xs>Run Re-render to generate the translated image.`),Zo=K(`<div class="flex h-full flex-col items-center justify-center gap-3 text-slate-400"><p class=text-sm>No result image yet</p><p class=text-xs>Run Re-render to generate the translated image.`),Ge([`click`])}));function $o(e){return u(()=>{if(!e.open){document.body.style.overflow=``;return}document.body.style.overflow=`hidden`;let t=t=>{t.key===`Escape`&&e.onClose()};return document.addEventListener(`keydown`,t),()=>{document.body.style.overflow=``,document.removeEventListener(`keydown`,t)}}),P(L,{get when(){return e.open},get children(){var t=es(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>{t.target===t.currentTarget&&e.onClose()},J(r,()=>e.title),Ye(i,`click`,e.onClose,!0),J(i,P(Zi,{class:`h-4 w-4`})),J(n,()=>e.children,null),t}})}var es,ts=t((()=>{X(),G(),la(),es=K(`<div role=dialog aria-modal=true aria-labelledby=modal-title class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"><div class="w-full max-w-md rounded-2xl bg-white p-6 shadow-xl"><div class="mb-4 flex items-center justify-between"><h2 id=modal-title class="text-base font-semibold text-slate-800"></h2><button class="rounded-lg p-1 text-slate-400 hover:bg-slate-100 hover:text-slate-600"aria-label=Close>`),Ge([`click`])}));function ns(e){return P($o,{get open(){return e.open},get title(){return e.title},get onClose(){return e.onCancel},get children(){return[(()=>{var t=rs();return J(t,()=>e.message),t})(),(()=>{var t=is(),n=t.firstChild,r=n.nextSibling;return Ye(n,`click`,e.onCancel,!0),Ye(r,`click`,e.onConfirm,!0),J(r,(()=>{var t=Y(()=>!!e.loading);return()=>t()?`Deleting…`:e.confirmLabel??`Delete`})()),l(t=>{var i=e.loading,a=e.confirmClass??`rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:opacity-50`,o=e.loading;return i!==t.e&&(n.disabled=t.e=i),a!==t.t&&Je(r,t.t=a),o!==t.a&&(r.disabled=t.a=o),t},{e:void 0,t:void 0,a:void 0}),t})()]}})}var rs,is,as=t((()=>{X(),ts(),rs=K(`<p class="mb-6 text-sm text-slate-600">`),is=K(`<div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 disabled:opacity-50">Cancel</button><button>`),Ge([`click`])})),os=n({LibraryPage:()=>ss});function ss(){let e=ln(),[t,{refetch:n}]=p(Va),[r,{refetch:i}]=p(()=>Ga()),a=()=>(r()??[]).filter(e=>!e.volumeId),[o,c]=s(null),[u,d]=s(``),[f,m]=s(``);function h(){d(``),m(``),c({mode:`create`})}function g(e){d(e.title),m(e.synopsis??``),c({mode:`edit`,vol:e})}let[_,v]=s(null),[y,b]=s(``),[x,S]=s(``),[C,w]=s(void 0);function ee(){b(``),S(``),w(void 0),v({mode:`create`})}function T(e){b(e.title),S(e.chapterNumber),w(e.volumeId),v({mode:`edit`,ch:e})}let[E,D]=s(null),[O,k]=s(null),[A,j]=s(!1),[te,M]=s(null);async function ne(){j(!0),M(null);try{let e=o();if(!e)return;e.mode===`create`?await Ha({title:u(),synopsis:f()||void 0}):await Ua(e.vol.id,{title:u(),synopsis:f()||void 0}),c(null),n()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function re(){M(null);try{let e=E();if(!e)return;await Wa(e.id),D(null),n()}catch(e){M(e instanceof Error?e.message:String(e)),D(null)}}async function ie(){j(!0),M(null);try{let e=_();if(!e)return;e.mode===`create`?await Ka({title:y(),chapterNumber:x(),volumeId:C()}):await qa(e.ch.id,{title:y(),chapterNumber:x(),volumeId:C()??null}),v(null),i()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function N(){M(null);try{let e=O();if(!e)return;await Ja(e.id),k(null),i()}catch(e){M(e instanceof Error?e.message:String(e)),k(null)}}return(()=>{var n=hs(),i=n.firstChild,s=i.firstChild,p=s.nextSibling.nextSibling.firstChild,j=p.firstChild,ae=p.nextSibling,oe=ae.firstChild,se=i.nextSibling;se.firstChild;var ce=se.nextSibling;return ce.firstChild,J(n,P(L,{get when(){return te()},get children(){var e=cs(),t=e.firstChild,n=t.nextSibling;return J(t,te),n.$$click=()=>M(null),e}}),i),J(s,P(tr,{class:`h-5 w-5 text-violet-600`})),p.$$click=h,J(p,P(Di,{class:`h-3.5 w-3.5`}),j),ae.$$click=ee,J(ae,P(Di,{class:`h-3.5 w-3.5`}),oe),J(se,P(L,{get when(){return t.loading},get children(){var e=ls();return J(e,()=>Array.from({length:4}).map(()=>gs())),e}}),null),J(se,P(L,{get when(){return t.error},get children(){return us()}}),null),J(se,P(L,{get when(){return Y(()=>!t.loading)()&&!t.error},get children(){return P(L,{get when(){return(t()??[]).length>0},get fallback(){return(()=>{var e=_s(),t=e.firstChild;return J(e,P(Gr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var n=ls();return J(n,P(I,{get each(){return t()},children:t=>(()=>{var n=vs(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling,s=o.firstChild,c=s.nextSibling.firstChild,l=c.nextSibling,u=l.firstChild;return i.$$click=e=>{e.stopPropagation(),g(t)},J(i,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),a.$$click=e=>{e.stopPropagation(),D(t)},J(a,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),o.$$click=()=>e(`/library/${t.id}`),J(s,P(tr,{class:`h-6 w-6 text-violet-500`})),J(c,()=>t.title),J(l,()=>t.chapterCount??0,u),J(o,P(lr,{class:`ml-auto h-4 w-4 shrink-0 text-slate-300 transition group-hover:translate-x-0.5 group-hover:text-slate-500`}),null),n})()})),n}})}}),null),J(ce,P(L,{get when(){return r.loading},get children(){var e=ds();return J(e,()=>Array.from({length:3}).map(()=>ys())),e}}),null),J(ce,P(L,{get when(){return!r.loading},get children(){return P(L,{get when(){return a().length>0},get fallback(){return bs()},get children(){var t=fs();return J(t,P(I,{get each(){return a()},children:t=>(()=>{var n=xs(),r=n.firstChild,i=r.firstChild;i.firstChild;var a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=r.nextSibling.firstChild,l=c.nextSibling;return r.$$click=()=>e(`/library/chapters/${t.id}`),J(i,()=>t.chapterNumber,null),J(a,()=>t.title),J(o,()=>t.pageCount??0,s),J(r,P(lr,{class:`h-4 w-4 text-slate-300`}),null),c.$$click=()=>T(t),J(c,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),l.$$click=()=>k(t),J(l,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),n})()})),t}})}}),null),J(n,P($o,{get open(){return o()!==null},get title(){return o()?.mode===`create`?`New Volume`:`Edit Volume`},onClose:()=>c(null),get children(){var e=ps(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>d(e.currentTarget.value),i.$$input=e=>m(e.currentTarget.value),a.$$click=()=>c(null),o.$$click=ne,J(o,()=>A()?`Saving…`:`Save`),l(()=>o.disabled=A()||!u().trim()),l(()=>n.value=u()),l(()=>i.value=f()),e}}),null),J(n,P($o,{get open(){return _()!==null},get title(){return _()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>v(null),get children(){var e=ms(),n=e.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling,s=o.firstChild.nextSibling;s.firstChild;var c=o.nextSibling.firstChild,u=c.nextSibling;return r.$$input=e=>b(e.currentTarget.value),a.$$input=e=>S(e.currentTarget.value),s.addEventListener(`change`,e=>{let t=e.currentTarget.value;w(t?Number(t):void 0)}),J(s,P(I,{get each(){return t()??[]},children:e=>(()=>{var t=Ss();return J(t,()=>e.title),l(()=>t.value=e.id),t})()}),null),c.$$click=()=>v(null),u.$$click=ie,J(u,()=>A()?`Saving…`:`Save`),l(()=>u.disabled=A()||!y().trim()||!x().trim()),l(()=>r.value=y()),l(()=>a.value=x()),l(()=>s.value=C()??``),e}}),null),J(n,P(ns,{get open(){return E()!==null},title:`Delete Volume`,get message(){return`Delete "${E()?.title}"? Chapters inside will be ungrouped but not deleted.`},onConfirm:re,onCancel:()=>D(null)}),null),J(n,P(ns,{get open(){return O()!==null},title:`Delete Chapter`,get message(){return`Delete "${O()?.title}"? This cannot be undone.`},onConfirm:N,onCancel:()=>k(null)}),null),n})()}var cs,ls,us,ds,fs,ps,ms,hs,gs,_s,vs,ys,bs,xs,Ss,Cs=t((()=>{X(),G(),Rn(),la(),Qa(),ts(),as(),cs=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),ls=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">`),us=K(`<p class="text-sm text-red-500">Failed to load volumes.`),ds=K(`<div class=space-y-2>`),fs=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),ps=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Volume title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3 placeholder="Brief description…"></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),ms=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Volume (optional)</label><select class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"><option value>No volume / Standalone</option></select></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),hs=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Library</h1><div class="ml-auto flex gap-2"><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> New Volume</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 hover:bg-slate-50"> New Chapter</button></div></div><section class=mb-10><h2 class="mb-3 text-sm font-semibold text-slate-600">Volumes</h2></section><section><h2 class="mb-3 text-sm font-semibold text-slate-600">Standalone Chapters`),gs=K(`<div class="h-32 animate-pulse rounded-2xl bg-slate-200">`),_s=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-16 text-slate-400"><p class=text-sm>No volumes yet.`),vs=K(`<div class="group relative flex flex-col gap-2 rounded-2xl bg-white p-4 text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-slate-50"title="Edit volume"></button><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-red-50"title="Delete volume"></button></div><button class="flex flex-col gap-2 text-left"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-violet-50"></div><div class="min-w-0 pr-10"><p class="truncate text-sm font-semibold text-slate-800"></p><p class="text-xs text-slate-500"> chapters`),ys=K(`<div class="h-12 animate-pulse rounded-xl bg-slate-200">`),bs=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-12 text-slate-400"><p class=text-sm>No standalone chapters.`),xs=K(`<li class="group flex items-center"><button class="flex flex-1 items-center gap-4 px-5 py-3.5 text-left transition hover:bg-slate-50"><span class="w-14 shrink-0 text-right text-xs font-mono text-slate-400">#</span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-3 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),Ss=K(`<option>`),Ge([`click`,`input`])})),ws=n({VolumePage:()=>Ts});function Ts(){let e=dn(),t=ln(),n=()=>Number(e.volumeId),[r,{refetch:i}]=p(Va),a=()=>r()?.find(e=>e.id===n()),[o,{refetch:c}]=p(n,e=>Ga({volumeId:e})),[u,d]=s(!1),[f,m]=s(``),[h,g]=s(``),[_,v]=s(!1),[y,b]=s(null);function x(){let e=a();e&&(m(e.title),g(e.synopsis??``),d(!0))}async function S(){v(!0),b(null);try{await Ua(n(),{title:f(),synopsis:h()||void 0}),d(!1),i()}catch(e){b(e instanceof Error?e.message:String(e))}finally{v(!1)}}let[C,w]=s(!1);async function ee(){b(null);try{await Wa(n()),w(!1),t(`/library`)}catch(e){b(e instanceof Error?e.message:String(e)),w(!1)}}let[T,E]=s(null),[D,O]=s(``),[k,A]=s(``),[j,te]=s(!1);function M(){O(``),A(``),E({mode:`create`})}function ne(e){O(e.title),A(e.chapterNumber),E({mode:`edit`,ch:e})}async function re(){te(!0),b(null);try{let e=T();if(!e)return;e.mode===`create`?await Ka({title:D(),chapterNumber:k(),volumeId:n()}):await qa(e.ch.id,{title:D(),chapterNumber:k()}),E(null),c()}catch(e){b(e instanceof Error?e.message:String(e))}finally{te(!1)}}let[ie,N]=s(null);async function ae(){b(null);try{let e=ie();if(!e)return;await Ja(e.id),N(null),c()}catch(e){b(e instanceof Error?e.message:String(e)),N(null)}}async function oe(e,t){b(null);try{let n=o()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];if(!i)return;await Promise.all([qa(e.id,{sortOrder:i.sortOrder}),qa(i.id,{sortOrder:e.sortOrder})]),c()}catch(e){b(e instanceof Error?e.message:String(e))}}return(()=>{var e=Ms(),n=e.firstChild,r=n.firstChild,i=n.nextSibling.firstChild,s=i.nextSibling,c=s.nextSibling.firstChild,p=c.nextSibling,v=p.nextSibling,te=v.firstChild;return J(e,P(L,{get when(){return y()},get children(){var e=Es(),t=e.firstChild,n=t.nextSibling;return J(t,y),n.$$click=()=>b(null),e}}),n),n.$$click=()=>t(`/library`),J(n,P(Zn,{class:`h-4 w-4`}),r),J(i,P(tr,{class:`h-5 w-5 text-violet-600`})),J(s,P(L,{get when(){return a()},get fallback(){return Ns()},children:e=>[(()=>{var t=Ps();return J(t,()=>e().title),t})(),P(L,{get when(){return e().synopsis},get children(){var t=Fs();return J(t,()=>e().synopsis),t}})]})),c.$$click=x,J(c,P(Ci,{class:`h-4 w-4`})),p.$$click=()=>w(!0),J(p,P(qi,{class:`h-4 w-4`})),v.$$click=M,J(v,P(Di,{class:`h-3.5 w-3.5`}),te),J(e,P(L,{get when(){return o.loading},get children(){var e=Ds();return J(e,()=>Array.from({length:4}).map(()=>Is())),e}}),null),J(e,P(L,{get when(){return o.error},get children(){return Os()}}),null),J(e,P(L,{get when(){return Y(()=>!o.loading)()&&!o.error},get children(){return P(L,{get when(){return(o()??[]).length>0},get fallback(){return(()=>{var e=Ls(),t=e.firstChild;return J(e,P(Vr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var e=ks();return J(e,P(I,{get each(){return o()},children:(e,n)=>{let r=()=>o()??[],i=()=>n()===0,a=()=>n()===r().length-1;return(()=>{var n=Rs(),r=n.firstChild,o=r.firstChild,s=o.nextSibling,c=r.nextSibling,u=c.firstChild,d=u.nextSibling,f=d.nextSibling,p=f.firstChild,m=c.nextSibling.firstChild,h=m.nextSibling;return o.$$click=()=>oe(e,`up`),J(o,P(pr,{class:`h-3.5 w-3.5`})),s.$$click=()=>oe(e,`down`),J(s,P(ar,{class:`h-3.5 w-3.5`})),c.$$click=()=>t(`/library/chapters/${e.id}`),J(u,()=>e.chapterNumber),J(d,()=>e.title),J(f,()=>e.pageCount??0,p),J(c,P(lr,{class:`h-4 w-4 text-slate-300`}),null),m.$$click=()=>ne(e),J(m,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),h.$$click=()=>N(e),J(h,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),l(e=>{var t=i(),n=a();return t!==e.e&&(o.disabled=e.e=t),n!==e.t&&(s.disabled=e.t=n),e},{e:void 0,t:void 0}),n})()}})),e}})}}),null),J(e,P($o,{get open(){return u()},title:`Edit Volume`,onClose:()=>d(!1),get children(){var e=As(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>m(e.currentTarget.value),i.$$input=e=>g(e.currentTarget.value),a.$$click=()=>d(!1),o.$$click=S,J(o,()=>_()?`Saving…`:`Save`),l(()=>o.disabled=_()||!f().trim()),l(()=>n.value=f()),l(()=>i.value=h()),e}}),null),J(e,P($o,{get open(){return T()!==null},get title(){return T()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>E(null),get children(){var e=js(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>O(e.currentTarget.value),i.$$input=e=>A(e.currentTarget.value),a.$$click=()=>E(null),o.$$click=re,J(o,()=>j()?`Saving…`:`Save`),l(()=>o.disabled=j()||!D().trim()||!k().trim()),l(()=>n.value=D()),l(()=>i.value=k()),e}}),null),J(e,P(ns,{get open(){return C()},title:`Delete Volume`,get message(){return`Delete "${a()?.title}"? This will not delete the chapters — they will just be ungrouped.`},onConfirm:ee,onCancel:()=>w(!1)}),null),J(e,P(ns,{get open(){return ie()!==null},title:`Delete Chapter`,get message(){return`Delete "${ie()?.title}"? This cannot be undone.`},onConfirm:ae,onCancel:()=>N(null)}),null),e})()}var Es,Ds,Os,ks,As,js,Ms,Ns,Ps,Fs,Is,Ls,Rs,zs=t((()=>{X(),G(),Rn(),la(),Qa(),ts(),as(),Es=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),Ds=K(`<div class=space-y-2>`),Os=K(`<p class="text-sm text-red-500">Failed to load chapters.`),ks=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),As=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),js=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Ms=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"> Library</button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><div class="flex items-center gap-2"><button class="rounded-lg p-1.5 text-slate-400 hover:bg-slate-100 hover:text-slate-600"title="Edit volume"></button><button class="rounded-lg p-1.5 text-slate-400 hover:bg-red-50 hover:text-red-500"title="Delete volume"></button><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add Chapter`),Ns=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),Ps=K(`<h1 class="text-xl font-semibold text-slate-800">`),Fs=K(`<p class="text-sm text-slate-500">`),Is=K(`<div class="h-14 animate-pulse rounded-xl bg-slate-200">`),Ls=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-20 text-slate-400"><p class=text-sm>No chapters yet. Add the first one.`),Rs=K(`<li class="group flex items-center"><div class="flex flex-col items-center px-2"><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button></div><button class="flex flex-1 items-center gap-4 py-4 pr-4 text-left transition hover:bg-slate-50"><span class="w-16 shrink-0 rounded-lg bg-slate-100 px-2 py-1 text-center text-xs font-mono text-slate-600"></span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-2 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),Ge([`click`,`input`])})),Bs=n({ChapterPage:()=>Us});function Vs(e){switch(e.status){case`done`:return P(_r,{class:`h-4 w-4 text-green-500`});case`processing`:return P(kr,{class:`h-4 w-4 text-yellow-500`});case`error`:return P(Tr,{class:`h-4 w-4 text-red-500`});default:return P(kr,{class:`h-4 w-4 text-slate-400`})}}function Hs(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=Ws(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=s.nextSibling,u=o.nextSibling,d=r.nextSibling.firstChild;return r.$$keydown=t=>t.key===`Enter`&&e.onClick(),Ye(r,`click`,e.onClick,!0),J(a,P(Vs,{get status(){return e.job.status}})),s.$$click=t=>{t.stopPropagation(),e.onMove(`up`)},J(s,P(pr,{class:`h-3.5 w-3.5 text-slate-600`})),c.$$click=t=>{t.stopPropagation(),e.onMove(`down`)},J(c,P(ar,{class:`h-3.5 w-3.5 text-slate-600`})),u.$$click=t=>{t.stopPropagation(),e.onUnassign()},J(u,P(Zi,{class:`h-3.5 w-3.5`})),J(d,()=>e.job.title),l(n=>{var a=`Open ${e.job.title} in studio`,o=t(),l=e.job.title,u=e.isFirst,d=e.isLast;return a!==n.e&&q(r,`aria-label`,n.e=a),o!==n.t&&q(i,`src`,n.t=o),l!==n.a&&q(i,`alt`,n.a=l),u!==n.o&&(s.disabled=n.o=u),d!==n.i&&(c.disabled=n.i=d),n},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0}),n})()}function Us(){let e=dn(),t=ln(),n=()=>Number(e.chapterId),[r]=p(()=>Ga()),i=()=>r()?.find(e=>e.id===n()),[a,{refetch:o}]=p(n,Ya),[c,u]=s(!1),[d,f]=s([]),[m,h]=s(new Set),[g,_]=s(!1),[v,y]=s(!1);async function b(){_(!0),h(new Set),u(!0);try{let e=[],t=1;for(;;){let n=await ja({page:t,pageSize:200});if(e.push(...n.items.filter(e=>!e.chapterId)),n.items.length<200)break;t++}f(e)}finally{_(!1)}}function x(e){h(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}async function S(){y(!0);try{let e=[...m()],t=a()?.length??0;await Promise.all(e.map((e,r)=>Na(e,{chapterId:n(),pageOrder:t+r}))),u(!1),h(new Set),o()}finally{y(!1)}}async function C(e,t){let n=a()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];i&&(await Promise.all([Na(e.id,{pageOrder:i.pageOrder}),Na(i.id,{pageOrder:e.pageOrder})]),o())}async function w(e){await Na(e,{chapterId:null}),o()}return(()=>{var e=Zs(),n=e.firstChild,r=n.nextSibling.firstChild,o=r.nextSibling,s=o.nextSibling,f=s.firstChild;return n.$$click=()=>{let e=i();e?.volumeId?t(`/library/${e.volumeId}`):t(`/library`)},J(n,P(Zn,{class:`h-4 w-4`}),null),J(n,P(L,{get when(){return i()?.volumeId},fallback:`Library`,children:`Volume`}),null),J(r,P(ri,{class:`h-5 w-5 text-violet-600`})),J(o,P(L,{get when(){return i()},get fallback(){return Qs()},children:e=>(()=>{var t=$s(),n=t.firstChild.nextSibling;return n.nextSibling,J(t,()=>e().chapterNumber,n),J(t,()=>e().title,null),t})()})),s.$$click=b,J(s,P(Lr,{class:`h-3.5 w-3.5`}),f),J(e,P(L,{get when(){return a.loading},get children(){var e=Gs();return J(e,()=>Array.from({length:8}).map(()=>ec())),e}}),null),J(e,P(L,{get when(){return a.error},get children(){return Ks()}}),null),J(e,P(L,{get when(){return Y(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return(a()??[]).length>0},get fallback(){return(()=>{var e=tc(),t=e.firstChild;return J(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var e=Gs();return J(e,P(I,{get each(){return a()},children:(e,n)=>{let r=()=>a()??[];return P(Hs,{job:e,get isFirst(){return n()===0},get isLast(){return n()===r().length-1},onMove:t=>C(e,t),onUnassign:()=>w(e.id),onClick:()=>t(`/jobs/${e.id}`)})}})),e}})}}),null),J(e,P($o,{get open(){return c()},title:`Add Pages to Chapter`,onClose:()=>u(!1),get children(){var e=Xs(),t=e.firstChild.nextSibling,n=t.firstChild,r=n.nextSibling;return J(e,P(L,{get when(){return g()},get children(){var e=qs();return J(e,()=>Array.from({length:4}).map(()=>nc())),e}}),t),J(e,P(L,{get when(){return Y(()=>!g())()&&d().length===0},get children(){return Js()}}),t),J(e,P(L,{get when(){return Y(()=>!g())()&&d().length>0},get children(){var e=Ys();return J(e,P(I,{get each(){return d()},children:e=>{let t=()=>m().has(e.id);return(()=>{var n=rc(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.firstChild,s=o.nextSibling;return i.addEventListener(`change`,()=>x(e.id)),J(o,()=>e.title),J(s,()=>new Date(e.createdAt).toLocaleDateString()),J(r,P(Vs,{get status(){return e.status}}),null),l(t=>{var n=Xa(e.id),r=e.title;return n!==t.e&&q(a,`src`,t.e=n),r!==t.t&&q(a,`alt`,t.t=r),t},{e:void 0,t:void 0}),l(()=>i.checked=t()),n})()}})),e}}),t),n.$$click=()=>u(!1),r.$$click=S,J(r,(()=>{var e=Y(()=>!!v());return()=>e()?`Assigning…`:`Assign ${m().size>0?m().size:``} selected`})()),l(()=>r.disabled=v()||m().size===0),e}}),null),e})()}var Ws,Gs,Ks,qs,Js,Ys,Xs,Zs,Qs,$s,ec,tc,nc,rc,ic=t((()=>{X(),G(),Rn(),la(),Qa(),ts(),Ws=K(`<div class="group relative flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="relative aspect-3/4 w-full cursor-pointer overflow-hidden bg-slate-100"role=button tabindex=0><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><span class="absolute left-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow"></span><div class="absolute right-2 top-2 flex flex-col gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move up"></button><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move down"></button></div><button class="absolute bottom-2 right-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500/90 text-white shadow opacity-0 transition-opacity group-hover:opacity-100 hover:bg-red-600"title="Remove from chapter"></button></div><div class=p-3><p class="truncate text-xs font-medium text-slate-700">`,!0,!1,!1),Gs=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),Ks=K(`<p class="text-sm text-red-500">Failed to load pages.`),qs=K(`<div class=space-y-2>`),Js=K(`<p class="py-6 text-center text-sm text-slate-400">No unassigned pages found.`),Ys=K(`<ul class="max-h-80 overflow-y-auto divide-y divide-slate-100 rounded-lg border border-slate-200">`),Xs=K(`<div class="flex flex-col gap-3"><p class="text-xs text-slate-500">Select unassigned jobs to add to this chapter.</p><div class="flex justify-end gap-2 pt-1"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Zs=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"></button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><button class="ml-auto flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add pages`),Qs=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),$s=K(`<h1 class="text-xl font-semibold text-slate-800">Ch. <!> — `),ec=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),tc=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No pages in this chapter yet.`),nc=K(`<div class="h-14 animate-pulse rounded-lg bg-slate-200">`),rc=K(`<li><label class="flex cursor-pointer items-center gap-3 px-3 py-2.5 hover:bg-slate-50"><input type=checkbox class="h-4 w-4 accent-violet-600"><img class="h-10 w-8 rounded object-cover bg-slate-100"loading=lazy><div class="min-w-0 flex-1"><p class="truncate text-sm font-medium text-slate-800"></p><p class="text-xs text-slate-400">`,!0,!1,!1),Ge([`click`,`keydown`])}));X(),G(),Rn();var ac=_e(()=>Promise.resolve().then(()=>(po(),$a)).then(e=>({default:e.JobsListPage}))),oc=_e(()=>Promise.resolve().then(()=>(Qo(),Bo)).then(e=>({default:e.StudioPage}))),sc=_e(()=>Promise.resolve().then(()=>(Cs(),os)).then(e=>({default:e.LibraryPage}))),cc=_e(()=>Promise.resolve().then(()=>(zs(),ws)).then(e=>({default:e.VolumePage}))),lc=_e(()=>Promise.resolve().then(()=>(ic(),Bs)).then(e=>({default:e.ChapterPage})));function uc(){return P(jn,{get children(){return P(yn,{path:`/`,component:e=>P(ma,{get children(){return e.children}}),get children(){return[P(yn,{path:`/`,component:Ea}),P(yn,{path:`/jobs`,component:ac}),P(yn,{path:`/jobs/:id`,component:oc}),P(yn,{path:`/library`,component:sc}),P(yn,{path:`/library/:volumeId`,component:cc}),P(yn,{path:`/library/chapters/:chapterId`,component:lc})]}})}})}var dc=new Map;window.AppBridge={mount(e,t={}){if(dc.has(e))return;let n=We(()=>P(uc,{}),e);dc.set(e,n)},unmount(e){dc.get(e)?.(),dc.delete(e)}}})();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Surface Studio mutation failures to the user.

The mutation handlers await API calls without catching failures. A failed request or polling error becomes an unhandled promise rejection, while finally merely re-enables the button and leaves the editor without an error message.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🪛 OpenGrep (1.25.0)

[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update the Studio mutation handlers in
the StudioPage flow to catch rejected API requests and polling errors, store a
user-visible error state, and render that message in the editor. Keep the
existing finally cleanup that re-enables controls, but ensure every awaited
mutation path handles failures instead of producing unhandled promise
rejections.

@deckyfx

deckyfx commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/wwwroot/js/app.js`:
- Line 1: Update ChapterPage’s load, assign, reorder, and unassign action
handlers to catch rejected API promises and write the failure to the component’s
existing error state. Ensure each handler surfaces the error before its
loading-state cleanup runs, preserving the existing reset behavior through
finally or equivalent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d92c595-6960-48b8-b44c-d807d9fdb692

📥 Commits

Reviewing files that changed from the base of the PR and between 65a069c and 7261fcf.

📒 Files selected for processing (53)
  • .gitignore
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
🚧 Files skipped from review as they are similar to previous changes (44)
  • extension/static/popup.css
  • .gitignore
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/components/Layout.tsx
  • extension/src/popup.ts
  • extension/static/manifest.json
  • extension/static/popup.html
  • extension/build.ts
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • docs/manga-page-translation.md
  • server/src/ModelSettingsStore.cs
  • server/ClientApp/src/components/BubbleList.tsx
  • extension/static/content.css
  • server/package.json
  • server/server-csharp.csproj
  • server/ClientApp/src/types.ts
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/src/Data/AppDbContext.cs
  • server/ClientApp/src/components/Modal.tsx
  • server/src/ServiceExtensions.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/src/Services/TypesettingService.cs
  • server/Program.cs
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/src/Routes/TranslatePage.cs
  • server/ClientApp/src/pages/JobsListPage.tsx
  • extension/src/types.ts
  • server/ClientApp/src/pages/LibraryPage.tsx
  • docs/portal-plan.md
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/src/Services/PageTranslationService.cs
  • server/src/BootExtensions.cs
  • server/ClientApp/src/api.ts
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/src/Routes/PortalRoutes.cs
  • extension/src/background.ts
  • extension/src/content.ts
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Config.cs

Comment thread server/wwwroot/js/app.js Outdated
@@ -0,0 +1 @@
(function(){var e=Object.defineProperty,t=(e,t)=>()=>(e&&(t=e(e=0)),t),n=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};function r(e){let t=String(e),n=t.length-1;return R.context.id+(n?String.fromCharCode(96+n):``)+t}function i(e){R.context=e}function a(){return{...R.context,id:R.getNextContextId(),count:0}}function o(e,t){let n=H,r=B,i=e.length===0,a=t===void 0?r:t,o=i?ke:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(()=>h(()=>N(o)));B=o,H=null;try{return A(s,!0)}finally{H=n,B=r}}function s(e,t){t=t?Object.assign({},Te,t):Te;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[ee.bind(n),e=>(typeof e==`function`&&(e=V&&V.running&&V.sources.has(n)?e(n.tValue):e(n.value)),T(n,e))]}function c(e,t,n){let r=O(e,t,!0,z);je&&V&&V.running?U.push(r):E(r)}function l(e,t,n){let r=O(e,t,!1,z);je&&V&&V.running?U.push(r):E(r)}function u(e,t,n){De=ne;let r=O(e,t,!1,z),i=Ie&&C(Ie);i&&(r.suspense=i),(!n||!n.render)&&(r.user=!0),W?W.push(r):E(r)}function d(e,t,n){n=n?Object.assign({},Te,n):Te;let r=O(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,je&&V&&V.running?(r.tState=z,U.push(r)):E(r),ee.bind(r)}function f(e){return e&&typeof e==`object`&&`then`in e}function p(e,t,n){let r,i,a;typeof t==`function`?(r=e,i=t,a=n||{}):(r=!0,i=e,a=t||{});let o=null,l=Ae,u=null,p=!1,m=!1,g=`initialValue`in a,_=typeof r==`function`&&d(r),v=new Set,[y,x]=(a.storage||s)(a.initialValue),[S,w]=s(void 0),[ee,T]=s(void 0,{equals:!1}),[E,D]=s(g?`ready`:`unresolved`);R.context&&(u=R.getNextContextId(),a.ssrLoadFrom===`initial`?l=a.initialValue:R.load&&R.has(u)&&(l=R.load(u)));function O(e,t,n,r){return o===e&&(o=null,r!==void 0&&(g=!0),(e===l||t===l)&&a.onHydrated&&queueMicrotask(()=>a.onHydrated(r,{value:t})),l=Ae,V&&e&&p?(V.promises.delete(e),p=!1,A(()=>{V.running=!0,k(t,n)},!1)):k(t,n)),t}function k(e,t){A(()=>{t===void 0&&x(()=>e),D(t===void 0?g?`ready`:`unresolved`:`errored`),w(t);for(let e of v.keys())e.decrement();v.clear()},!1)}function j(){let e=Ie&&C(Ie),t=y(),n=S();if(n!==void 0&&!o)throw n;return H&&!H.user&&e&&c(()=>{ee(),o&&(e.resolved&&V&&p?V.promises.add(o):v.has(e)||(e.increment(),v.add(e)))}),t}function te(e=!0){if(e!==!1&&m)return;m=!1;let t=_?_():r;if(p=V&&V.running,t==null||t===!1){O(o,h(y));return}V&&o&&V.promises.delete(o);let n,a=l===Ae?h(()=>{try{return i(t,{value:y(),refetching:e})}catch(e){n=e}}):l;if(n!==void 0){O(o,void 0,oe(n),t);return}else if(!f(a))return O(o,a,void 0,t),a;return o=a,`v`in a?(a.s===1?O(o,a.v,void 0,t):O(o,void 0,oe(a.v),t),a):(m=!0,queueMicrotask(()=>m=!1),A(()=>{D(g?`refreshing`:`pending`),T()},!1),a.then(e=>O(a,e,void 0,t),e=>O(a,void 0,oe(e),t)))}Object.defineProperties(j,{state:{get:()=>E()},error:{get:()=>S()},loading:{get(){let e=E();return e===`pending`||e===`refreshing`}},latest:{get(){if(!g)return j();let e=S();if(e&&!o)throw e;return y()}}});let M=B;return _?c(()=>(M=B,te(!1))):te(!1),[j,{refetch:e=>b(M,()=>te(e)),mutate:x}]}function m(e){return A(e,!1)}function h(e){if(!Me&&H===null)return e();let t=H;H=null;try{return Me?Me.untrack(e):e()}finally{H=t}}function g(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=h(()=>t(o,i,n));return i=o,s}}function _(e){u(()=>h(e))}function v(e){return B===null||(B.cleanups===null?B.cleanups=[e]:B.cleanups.push(e)),e}function y(){return B}function b(e,t){let n=B,r=H;B=e,H=null;try{return A(t,!0)}catch(e){ce(e)}finally{B=n,H=r}}function x(e){if(V&&V.running)return e(),V.done;let t=H,n=B;return Promise.resolve().then(()=>{H=t,B=n;let r;return(je||Ie)&&(r=V||={sources:new Set,effects:[],promises:new Set,disposed:new Set,queue:new Set,running:!0},r.done||=new Promise(e=>r.resolve=e),r.running=!0),A(e,!1),H=B=null,r?r.done:void 0})}function S(e,t){let n=Symbol(`context`);return{id:n,Provider:ue(n),defaultValue:e}}function C(e){let t;return B&&B.context&&(t=B.context[e.id])!==void 0?t:e.defaultValue}function w(e){let t=d(e),n=d(()=>le(t()));return n.toArray=()=>{let e=n();return Array.isArray(e)?e:e==null?[]:[e]},n}function ee(){let e=V&&V.running;if(this.sources&&(e?this.tState:this.state))if((e?this.tState:this.state)===z)E(this);else{let e=U;U=null,A(()=>re(this),!1),U=e}if(H){let e=this.observers;if(!e||e[e.length-1]!==H){let t=e?e.length:0;H.sources?(H.sources.push(this),H.sourceSlots.push(t)):(H.sources=[this],H.sourceSlots=[t]),e?(e.push(H),this.observerSlots.push(H.sources.length-1)):(this.observers=[H],this.observerSlots=[H.sources.length-1])}}return e&&V.sources.has(this)?this.tValue:this.value}function T(e,t,n){let r=V&&V.running&&V.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(V){let r=V.running;(r||!n&&V.sources.has(e))&&(V.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&A(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=V&&V.running;r&&V.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?U.push(n):W.push(n),n.observers&&ie(n)),r?n.tState=z:n.state=z)}if(U.length>1e6)throw U=[],Error()},!1)}return t}function E(e){if(!e.fn)return;N(e);let t=Ne;D(e,V&&V.running&&V.sources.has(e)?e.tValue:e.value,t),V&&!V.running&&V.sources.has(e)&&queueMicrotask(()=>{A(()=>{V&&(V.running=!0),H=B=e,D(e,e.tValue,t),H=B=null},!1)})}function D(e,t,n){let r,i=B,a=H;H=B=e;try{r=e.fn(t)}catch(t){return e.pure&&(V&&V.running?(e.tState=z,e.tOwned&&e.tOwned.forEach(N),e.tOwned=void 0):(e.state=z,e.owned&&e.owned.forEach(N),e.owned=null)),e.updatedAt=n+1,ce(t)}finally{H=a,B=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?T(e,r,!0):V&&V.running&&e.pure?(V.sources.has(e)||(e.value=r),V.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function O(e,t,n,r=z,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:B,context:B?B.context:null,pure:n};if(V&&V.running&&(a.state=0,a.tState=r),B===null||B!==ke&&(V&&V.running&&B.pure?B.tOwned?B.tOwned.push(a):B.tOwned=[a]:B.owned?B.owned.push(a):B.owned=[a]),Me&&a.fn){let e=a.fn,[t,n]=s(void 0,{equals:!1}),r=Me.factory(e,n);v(()=>r.dispose());let i,o=()=>x(n).then(()=>{i&&=(i.dispose(),void 0)});a.fn=n=>(t(),V&&V.running?(i||=Me.factory(e,o),i.track(n)):r.track(n))}return a}function k(e){let t=V&&V.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===Oe)return re(e);if(e.suspense&&h(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<Ne);){if(t&&V.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(V.disposed.has(t))return}if((t?e.tState:e.state)===z)E(e);else if((t?e.tState:e.state)===Oe){let t=U;U=null,A(()=>re(e,n[0]),!1),U=t}}}function A(e,t){if(U)return e();let n=!1;t||(U=[]),W?n=!0:W=[],Ne++;try{let t=e();return j(n),t}catch(e){n||(W=null),U=null,ce(e)}}function j(e){if(U&&=(je&&V&&V.running?M(U):te(U),null),e)return;let t;if(V){if(!V.promises.size&&!V.queue.size){let e=V.sources,n=V.disposed;W.push.apply(W,V.effects),t=V.resolve;for(let e of W)`tState`in e&&(e.state=e.tState),delete e.tState;V=null,A(()=>{for(let e of n)N(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)N(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}Fe(!1)},!1)}else if(V.running){V.running=!1,V.effects.push.apply(V.effects,W),W=null,Fe(!0);return}}let n=W;W=null,n.length&&A(()=>De(n),!1),t&&t()}function te(e){for(let t=0;t<e.length;t++)k(e[t])}function M(e){for(let t=0;t<e.length;t++){let n=e[t],r=V.queue;r.has(n)||(r.add(n),je(()=>{r.delete(n),A(()=>{V.running=!0,k(n)},!1),V&&(V.running=!1)}))}}function ne(e){let t,n=0;for(t=0;t<e.length;t++){let r=e[t];r.user?e[n++]=r:k(r)}if(R.context){if(R.count){R.effects||=[],R.effects.push(...e.slice(0,n));return}i()}for(R.effects&&(R.done||!R.count)&&(e=[...R.effects,...e],n+=R.effects.length,delete R.effects),t=0;t<n;t++)k(e[t])}function re(e,t){let n=V&&V.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===z?i!==t&&(!i.updatedAt||i.updatedAt<Ne)&&k(i):e===Oe&&re(i,t)}}}function ie(e){let t=V&&V.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=Oe:r.state=Oe,r.pure?U.push(r):W.push(r),r.observers&&ie(r))}}function N(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)N(e.tOwned[t]);delete e.tOwned}if(V&&V.running&&e.pure)ae(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)N(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}V&&V.running?e.tState=0:e.state=0}function ae(e,t){if(t||(e.tState=0,V.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ae(e.owned[t])}function oe(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function se(e,t,n){try{for(let n of t)n(e)}catch(e){ce(e,n&&n.owner||null)}}function ce(e,t=B){let n=Ee&&t&&t.context&&t.context[Ee],r=oe(e);if(!n)throw r;W?W.push({fn(){se(r,n,t)},state:z}):se(r,n,t)}function le(e){if(typeof e==`function`&&!e.length)return le(e());if(Array.isArray(e)){let t=[];for(let n=0;n<e.length;n++){let r=le(e[n]);if(Array.isArray(r))if(r.length<32768)t.push.apply(t,r);else for(let e=0;e<r.length;e++)t.push(r[e]);else t.push(r)}return t}return e}function ue(e,t){return function(t){let n;return l(()=>n=h(()=>(B.context={...B.context,[e]:t.value},w(()=>t.children))),void 0),n}}function de(e){for(let t=0;t<e.length;t++)e[t]()}function fe(e,t,n={}){let r=[],i=[],a=[],c=0,l=t.length>1?[]:null;return v(()=>de(a)),()=>{let u=e()||[],d=u.length,f,p;return u[we],h(()=>{let e,t,s,h,g,_,v,y,b;if(d===0)c!==0&&(de(a),a=[],r=[],i=[],c=0,l&&=[]),n.fallback&&(r=[Le],i[0]=o(e=>(a[0]=e,n.fallback())),c=1);else if(c===0){for(i=Array(d),p=0;p<d;p++)r[p]=u[p],i[p]=o(m);c=d}else{for(s=Array(d),h=Array(d),l&&(g=Array(d)),_=0,v=Math.min(c,d);_<v&&r[_]===u[_];_++);for(v=c-1,y=d-1;v>=_&&y>=_&&r[v]===u[y];v--,y--)s[y]=i[v],h[y]=a[v],l&&(g[y]=l[v]);for(e=new Map,t=Array(y+1),p=y;p>=_;p--)b=u[p],f=e.get(b),t[p]=f===void 0?-1:f,e.set(b,p);for(f=_;f<=v;f++)b=r[f],p=e.get(b),p!==void 0&&p!==-1?(s[p]=i[f],h[p]=a[f],l&&(g[p]=l[f]),p=t[p],e.set(b,p)):a[f]();for(p=_;p<d;p++)p in s?(i[p]=s[p],a[p]=h[p],l&&(l[p]=g[p],l[p](p))):i[p]=o(m);i=i.slice(0,c=d),r=u.slice(0)}return i});function m(e){if(a[p]=e,l){let[e,n]=s(p);return l[p]=n,t(u[p],e)}return t(u[p])}}}function P(e,t){if(Re&&R.context){let n=R.context;i(a());let r=h(()=>e(t||{}));return i(n),r}return h(()=>e(t||{}))}function pe(){return!0}function me(e){return(e=typeof e==`function`?e():e)?e:{}}function he(){for(let e=0,t=this.length;e<t;++e){let t=this[e]();if(t!==void 0)return t}}function F(...e){let t=!1;for(let n=0;n<e.length;n++){let r=e[n];t||=!!r&&Se in r,e[n]=typeof r==`function`?(t=!0,d(r)):r}if(Ce&&t)return new Proxy({get(t){for(let n=e.length-1;n>=0;n--){let r=me(e[n])[t];if(r!==void 0)return r}},has(t){for(let n=e.length-1;n>=0;n--)if(t in me(e[n]))return!0;return!1},keys(){let t=[];for(let n=0;n<e.length;n++)t.push(...Object.keys(me(e[n])));return[...new Set(t)]}},ze);let n={},r=Object.create(null);for(let t=e.length-1;t>=0;t--){let i=e[t];if(!i)continue;let a=Object.getOwnPropertyNames(i);for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===`__proto__`||t===`constructor`)continue;let o=Object.getOwnPropertyDescriptor(i,t);if(!r[t])r[t]=o.get?{enumerable:!0,configurable:!0,get:he.bind(n[t]=[o.get.bind(i)])}:o.value===void 0?void 0:o;else{let e=n[t];e&&(o.get?e.push(o.get.bind(i)):o.value!==void 0&&e.push(()=>o.value))}}}let i={},a=Object.keys(r);for(let e=a.length-1;e>=0;e--){let t=a[e],n=r[t];n&&n.get?Object.defineProperty(i,t,n):i[t]=n?n.value:void 0}return i}function ge(e,...t){let n=t.length;if(Ce&&Se in e){let r=n>1?t.flat():t[0],i=t.map(t=>new Proxy({get(n){return t.includes(n)?e[n]:void 0},has(n){return t.includes(n)&&n in e},keys(){return t.filter(t=>t in e)}},ze));return i.push(new Proxy({get(t){return r.includes(t)?void 0:e[t]},has(t){return r.includes(t)?!1:t in e},keys(){return Object.keys(e).filter(e=>!r.includes(e))}},ze)),i}let r=[];for(let e=0;e<=n;e++)r[e]={};for(let i of Object.getOwnPropertyNames(e)){let a=n;for(let e=0;e<t.length;e++)if(t[e].includes(i)){a=e;break}let o=Object.getOwnPropertyDescriptor(e,i);!o.get&&!o.set&&o.enumerable&&o.writable&&o.configurable?r[a][i]=o.value:Object.defineProperty(r[a],i,o)}return r}function _e(e){let t,n,r=r=>{let a=R.context;if(a){let[r,o]=s();R.count||=0,R.count++,(n||=e()).then(e=>{!R.done&&i(a),R.count--,o(()=>e.default),i()}),t=r}else if(!t){let[r]=p(()=>(n||=e()).then(e=>e.default));t=r}let o;return d(()=>(o=t())?h(()=>{if(!a||R.done)return o(r);let e=R.context;i(a);let t=o(r);return i(e),t}):``)};return r.preload=()=>n||((n=e()).then(e=>t=()=>e.default),n),r}function I(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return d(fe(()=>e.each,e.children,t||void 0))}function L(e){let t=e.keyed,n=d(()=>e.when,void 0,void 0),r=t?n:d(n,void 0,{equals:(e,t)=>!e==!t});return d(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?h(()=>a(t?i:()=>{if(!h(r))throw Be(`Show`);return n()})):a}return e.fallback},void 0,void 0)}function ve(e){let t=w(()=>e.children),n=d(()=>{let e=t(),n=Array.isArray(e)?e:[e],r=()=>void 0;for(let e=0;e<n.length;e++){let t=e,i=n[e],a=r,o=d(()=>a()?void 0:i.when,void 0,void 0),s=i.keyed?o:d(o,void 0,{equals:(e,t)=>!e==!t});r=()=>a()||(s()?[t,o,i]:void 0)}return r});return d(()=>{let t=n()();if(!t)return e.fallback;let[r,i,a]=t,o=a.children;return typeof o==`function`&&o.length>0?h(()=>o(a.keyed?i():()=>{if(h(n)()?.[0]!==r)throw Be(`Match`);return i()})):o},void 0,void 0)}function ye(e){return e}function be(){Ve&&[...Ve].forEach(e=>e())}var R,xe,Se,Ce,we,Te,Ee,De,z,Oe,ke,Ae,B,V,je,Me,H,U,W,Ne,Pe,Fe,Ie,Le,Re,ze,Be,Ve,G=t((()=>{R={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return r(this.context.count)},getNextContextId(){return r(this.context.count++)}},xe=(e,t)=>e===t,Se=Symbol(`solid-proxy`),Ce=typeof Proxy==`function`,we=Symbol(`solid-track`),Te={equals:xe},Ee=null,De=te,z=1,Oe=2,ke={owned:null,cleanups:null,context:null,owner:null},Ae={},B=null,V=null,je=null,Me=null,H=null,U=null,W=null,Ne=0,[Pe,Fe]=s(!1),Le=Symbol(`fallback`),Re=!1,ze={get(e,t,n){return t===Se?n:e.get(t)},has(e,t){return t===Se?!0:e.has(t)},set:pe,deleteProperty:pe,getOwnPropertyDescriptor(e,t){return{configurable:!0,enumerable:!0,get(){return e.get(t)},set:pe,deleteProperty:pe}},ownKeys(e){return e.keys()}},Be=e=>`Stale read from <${e}>.`}));function He(e,t){let n=yt[e];return typeof n==`object`?n[t]?n.$:void 0:n}function Ue(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;){if(t[o]===n[s]){o++,s++;continue}for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)(!l||!l.has(t[o]))&&t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null)if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&!((d=l.get(t[c]))==null||d!==r+u);)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++;else t[o++].remove()}}}function We(e,t,n,r={}){let i;return o(r=>{i=r,t===document?e():J(t,e(),t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function K(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>h(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function Ge(e,t=window.document){let n=t[Ct]||(t[Ct]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,st))}}function q(e,t,n){rt(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function Ke(e,t,n,r){rt(e)||(r==null?e.removeAttributeNS(t,n):e.setAttributeNS(t,n,r))}function qe(e,t,n){rt(e)||(n?e.setAttribute(t,``):e.removeAttribute(t))}function Je(e,t){rt(e)||(t==null?e.removeAttribute(`class`):e.className=t)}function Ye(e,t,n,r){if(r)Array.isArray(n)?(e[`$$${t}`]=n[0],e[`$$${t}Data`]=n[1]):e[`$$${t}`]=n;else if(Array.isArray(n)){let r=n[0];e.addEventListener(t,n[0]=t=>r.call(e,n[1],t))}else e.addEventListener(t,n,typeof n!=`function`&&n)}function Xe(e,t,n={}){let r=Object.keys(t||{}),i=Object.keys(n),a,o;for(a=0,o=i.length;a<o;a++){let r=i[a];!r||r===`undefined`||t[r]||(at(e,r,!1),delete n[r])}for(a=0,o=r.length;a<o;a++){let i=r[a],o=!!t[i];!i||i===`undefined`||n[i]===o||!o||(at(e,i,!0),n[i]=o)}return n}function Ze(e,t,n){if(!t)return n?q(e,`style`):t;let r=e.style;if(typeof t==`string`)return r.cssText=t;typeof n==`string`&&(r.cssText=n=void 0),n||={},t||={};let i,a;for(a in n)t[a]??r.removeProperty(a),delete n[a];for(a in t)i=t[a],i!==n[a]&&(r.setProperty(a,i),n[a]=i);return n}function Qe(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function $e(e,t={},n,r){let i={};return r||l(()=>i.children=ct(e,t.children,i.children)),l(()=>typeof t.ref==`function`&&et(t.ref,e)),l(()=>tt(e,t,n,!0,i,!0)),i}function et(e,t,n){return h(()=>e(t,n))}function J(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return ct(e,t,r,n);l(r=>ct(e,t(),r,n),r)}function tt(e,t,n,r,i={},a=!1){t||={};for(let r in i)if(!(r in t)){if(r===`children`)continue;i[r]=ot(e,r,null,i[r],n,a,t)}for(let o in t){if(o===`children`){r||ct(e,t.children);continue}let s=t[o];i[o]=ot(e,o,s,i[o],n,a,t)}}function nt(e){let t,n;return!rt()||!(t=R.registry.get(n=ft()))?e():(R.completed&&R.completed.add(t),R.registry.delete(n),t)}function rt(e){return!!R.context&&!R.done&&(!e||e.isConnected)}function it(e){return e.toLowerCase().replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function at(e,t,n){let r=t.trim().split(/\s+/);for(let t=0,i=r.length;t<i;t++)e.classList.toggle(r[t],n)}function ot(e,t,n,r,i,a,o){let s,c,l,u,d;if(t===`style`)return Ze(e,n,r);if(t===`classList`)return Xe(e,n,r);if(n===r)return r;if(t===`ref`)a||n(e);else if(t.slice(0,3)===`on:`){let i=t.slice(3);r&&e.removeEventListener(i,r,typeof r!=`function`&&r),n&&e.addEventListener(i,n,typeof n!=`function`&&n)}else if(t.slice(0,10)===`oncapture:`){let i=t.slice(10);r&&e.removeEventListener(i,r,!0),n&&e.addEventListener(i,n,!0)}else if(t.slice(0,2)===`on`){let i=t.slice(2).toLowerCase(),a=bt.has(i);if(!a&&r){let t=Array.isArray(r)?r[0]:r;e.removeEventListener(i,t)}(a||n)&&(Ye(e,i,n,a),a&&Ge([i]))}else if(t.slice(0,5)===`attr:`)q(e,t.slice(5),n);else if(t.slice(0,5)===`bool:`)qe(e,t.slice(5),n);else if((d=t.slice(0,5)===`prop:`)||(l=_t.has(t))||!i&&((u=He(t,e.tagName))||(c=gt.has(t)))||(s=e.nodeName.includes(`-`)||`is`in o)){if(d)t=t.slice(5),c=!0;else if(rt(e))return n;t===`class`||t===`className`?Je(e,n):s&&!c&&!l?e[it(t)]=n:e[u||t]=n}else{let r=i&&t.indexOf(`:`)>-1&&St[t.split(`:`)[0]];r?Ke(e,r,t,n):q(e,vt[t]||t,n)}return n}function st(e){if(R.registry&&R.events&&R.events.find(([t,n])=>n===e))return;let t=e.target,n=`$$${e.type}`,r=e.target,i=e.currentTarget,a=t=>Object.defineProperty(e,"target",{configurable:!0,value:t}),o=()=>{let r=t[n];if(r&&!t.disabled){let i=t[`${n}Data`];if(i===void 0?r.call(t,e):r.call(t,i,e),e.cancelBubble)return}return t.host&&typeof t.host!=`string`&&!t.host._$host&&t.contains(e.target)&&a(t.host),!0},s=()=>{for(;o()&&(t=t._$host||t.parentNode||t.host););};if(Object.defineProperty(e,"currentTarget",{configurable:!0,get(){return t||document}}),R.registry&&!R.done&&(R.done=_$HY.done=!0),e.composedPath){let n=e.composedPath();a(n[0]);for(let e=0;e<n.length-2&&(t=n[e],o());e++){if(t._$host){t=t._$host,s();break}if(t.parentNode===i)break}}else s();a(r)}function ct(e,t,n,r,i){let a=rt(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=dt(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=dt(e,n,r)}else if(o===`function`)return l(()=>{let i=t();for(;typeof i==`function`;)i=i();n=ct(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(lt(o,t,n,i))return l(()=>n=ct(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=dt(e,n,r),s)return n}else c?n.length===0?ut(e,o,r):Ue(e,n,o):(n&&dt(e),ut(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=dt(e,n,r,t);dt(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function lt(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(!(o==null||o===!0||o===!1))if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=lt(e,o,s)||i;else if(c===`function`)if(r){for(;typeof o==`function`;)o=o();i=lt(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0;else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}return i}function ut(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function dt(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}function ft(){return R.getNextContextId()}function pt(e,t=!1,n=void 0){return t?document.createElementNS(wt,e):document.createElement(e,{is:n})}function mt(e,t){let n=d(e);return d(()=>{let e=n();switch(typeof e){case`function`:return h(()=>e(t));case`string`:let n=xt.has(e),r=R.context?nt():pt(e,n,h(()=>t.is));return $e(r,t,n),r}})}function ht(e){let[,t]=ge(e,[`component`]);return mt(()=>e.component,t)}var gt,_t,vt,yt,bt,xt,St,Y,Ct,wt,X=t((()=>{G(),gt=new Set([`className`,`value`,`readOnly`,`noValidate`,`formNoValidate`,`isMap`,`noModule`,`playsInline`,`adAuctionHeaders`,`allowFullscreen`,`browsingTopics`,`defaultChecked`,`defaultMuted`,`defaultSelected`,`disablePictureInPicture`,`disableRemotePlayback`,`preservesPitch`,`shadowRootClonable`,`shadowRootCustomElementRegistry`,`shadowRootDelegatesFocus`,`shadowRootSerializable`,`sharedStorageWritable`,...`allowfullscreen.async.alpha.autofocus.autoplay.checked.controls.default.disabled.formnovalidate.hidden.indeterminate.inert.ismap.loop.multiple.muted.nomodule.novalidate.open.playsinline.readonly.required.reversed.seamless.selected.adauctionheaders.browsingtopics.credentialless.defaultchecked.defaultmuted.defaultselected.defer.disablepictureinpicture.disableremoteplayback.preservespitch.shadowrootclonable.shadowrootcustomelementregistry.shadowrootdelegatesfocus.shadowrootserializable.sharedstoragewritable`.split(`.`)]),_t=new Set([`innerHTML`,`textContent`,`innerText`,`children`]),vt=Object.assign(Object.create(null),{className:`class`,htmlFor:`for`}),yt=Object.assign(Object.create(null),{class:`className`,novalidate:{$:`noValidate`,FORM:1},formnovalidate:{$:`formNoValidate`,BUTTON:1,INPUT:1},ismap:{$:`isMap`,IMG:1},nomodule:{$:`noModule`,SCRIPT:1},playsinline:{$:`playsInline`,VIDEO:1},readonly:{$:`readOnly`,INPUT:1,TEXTAREA:1},adauctionheaders:{$:`adAuctionHeaders`,IFRAME:1},allowfullscreen:{$:`allowFullscreen`,IFRAME:1},browsingtopics:{$:`browsingTopics`,IMG:1},defaultchecked:{$:`defaultChecked`,INPUT:1},defaultmuted:{$:`defaultMuted`,AUDIO:1,VIDEO:1},defaultselected:{$:`defaultSelected`,OPTION:1},disablepictureinpicture:{$:`disablePictureInPicture`,VIDEO:1},disableremoteplayback:{$:`disableRemotePlayback`,AUDIO:1,VIDEO:1},preservespitch:{$:`preservesPitch`,AUDIO:1,VIDEO:1},shadowrootclonable:{$:`shadowRootClonable`,TEMPLATE:1},shadowrootdelegatesfocus:{$:`shadowRootDelegatesFocus`,TEMPLATE:1},shadowrootserializable:{$:`shadowRootSerializable`,TEMPLATE:1},sharedstoragewritable:{$:`sharedStorageWritable`,IFRAME:1,IMG:1}}),bt=new Set([`beforeinput`,`click`,`dblclick`,`contextmenu`,`focusin`,`focusout`,`input`,`keydown`,`keyup`,`mousedown`,`mousemove`,`mouseout`,`mouseover`,`mouseup`,`pointerdown`,`pointermove`,`pointerout`,`pointerover`,`pointerup`,`touchend`,`touchmove`,`touchstart`]),xt=new Set(`altGlyph.altGlyphDef.altGlyphItem.animate.animateColor.animateMotion.animateTransform.circle.clipPath.color-profile.cursor.defs.desc.ellipse.feBlend.feColorMatrix.feComponentTransfer.feComposite.feConvolveMatrix.feDiffuseLighting.feDisplacementMap.feDistantLight.feDropShadow.feFlood.feFuncA.feFuncB.feFuncG.feFuncR.feGaussianBlur.feImage.feMerge.feMergeNode.feMorphology.feOffset.fePointLight.feSpecularLighting.feSpotLight.feTile.feTurbulence.filter.font.font-face.font-face-format.font-face-name.font-face-src.font-face-uri.foreignObject.g.glyph.glyphRef.hkern.image.line.linearGradient.marker.mask.metadata.missing-glyph.mpath.path.pattern.polygon.polyline.radialGradient.rect.set.stop.svg.switch.symbol.text.textPath.tref.tspan.use.view.vkern`.split(`.`)),St={xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`},Y=e=>d(()=>e()),Ct=`_$DX_DELEGATE`,wt=`http://www.w3.org/2000/svg`}));X();function Tt(){let e=new Set;function t(t){return e.add(t),()=>e.delete(t)}let n=!1;function r(t,r){if(n)return!(n=!1);let i={to:t,options:r,defaultPrevented:!1,preventDefault:()=>i.defaultPrevented=!0};for(let a of e)a.listener({...i,from:a.location,retry:e=>{e&&(n=!0),a.navigate(t,{...r,resolve:!1})}});return!i.defaultPrevented}return{subscribe:t,confirm:r}}function Et(){(!window.history.state||window.history.state._depth==null)&&window.history.replaceState({...window.history.state,_depth:window.history.length-1},``),kt=window.history.state._depth}function Dt(e){return{...e,_depth:window.history.state&&window.history.state._depth}}function Ot(e,t){let n=!1;return()=>{let r=kt;Et();let i=r==null?null:kt-r;if(n){n=!1;return}i&&t(i)?(n=!0,window.history.go(-i)):e()}}var kt,At=t((()=>{Et()}));function jt(e,t=!1){let n=e.replace(Ht,`$1`);return n?t||/^[?#]/.test(n)?n:`/`+n:``}function Mt(e,t,n){if(Vt.test(t))return;let r=jt(e),i=n&&jt(n),a=``;return a=!i||t.startsWith(`/`)?r:i.toLowerCase().indexOf(r.toLowerCase())===0?i:r+i,(a||`/`)+jt(t,!a)}function Nt(e,t){if(e==null)throw Error(t);return e}function Pt(e,t){return jt(e).replace(/\/*(\*.*)?$/g,``)+jt(t)}function Ft(e){let t={};return e.searchParams.forEach((e,n)=>{n in t?Array.isArray(t[n])?t[n].push(e):t[n]=[t[n],e]:t[n]=e}),t}function It(e,t,n){let[r,i]=e.split(`/*`,2),a=r.split(`/`).filter(Boolean),o=a.length;return e=>{let r=e.split(`/`).filter(Boolean),s=r.length-o;if(s<0||s>0&&i===void 0&&!t)return null;let c={path:o?``:`/`,params:{}},l=e=>n===void 0?void 0:n[e];for(let e=0;e<o;e++){let t=a[e],n=t[0]===`:`,i=n?r[e]:r[e].toLowerCase(),o=n?t.slice(1):t.toLowerCase();if(n&&Lt(i,l(o)))c.params[o]=i;else if(n||!Lt(i,o))return null;c.path+=`/${i}`}if(i){let e=s?r.slice(-s).join(`/`):``;if(Lt(e,l(i)))c.params[i]=e;else return null}return c}}function Lt(e,t){let n=t=>t===e;return t===void 0?!0:typeof t==`string`?n(t):typeof t==`function`?t(e):Array.isArray(t)?t.some(n):t instanceof RegExp?t.test(e):!1}function Rt(e){let[t,n]=e.pattern.split(`/*`,2),r=t.split(`/`).filter(Boolean);return r.reduce((e,t)=>e+(t.startsWith(`:`)?2:3),r.length-(n===void 0?0:1))}function zt(e){let t=new Map,n=y();return new Proxy({},{get(r,i){return t.has(i)||b(n,()=>t.set(i,d(()=>e()[i]))),t.get(i)()},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}},ownKeys(){return Reflect.ownKeys(e())},has(t,n){return n in e()}})}function Bt(e){let t=/(\/?\:[^\/]+)\?/.exec(e);if(!t)return[e];let n=e.slice(0,t.index),r=e.slice(t.index+t[0].length),i=[n,n+=t[1]];for(;t=/^(\/\:[^\/]+)\?/.exec(r);)i.push(n+=t[1]),r=r.slice(t[0].length);return Bt(r).reduce((e,t)=>[...e,...i.map(e=>e+t)],[])}var Vt,Ht,Ut,Wt=t((()=>{G(),Vt=/^(?:[a-z0-9]+:)?\/\//i,Ht=/^\/+|(\/)\/+$/g,Ut=`http://sr`}));function Gt(e,t=``){let{component:n,preload:r,load:i,children:a,info:o}=e,s=!a||Array.isArray(a)&&!a.length,c={key:e,component:n,preload:r||i,info:o};return qt(e.path).reduce((n,r)=>{for(let i of Bt(r)){let a=Pt(t,i),o=s?a:a.split(`/*`,1)[0];o=o.split(`/`).map(e=>e.startsWith(`:`)||e.startsWith(`*`)?e:encodeURIComponent(e)).join(`/`),n.push({...c,originalPath:r,pattern:o,matcher:It(o,!s,e.matchFilters)})}return n},[])}function Kt(e,t=0){return{routes:e,score:Rt(e[e.length-1])*1e4-t,matcher(t){let n=[];for(let r=e.length-1;r>=0;r--){let i=e[r],a=i.matcher(t);if(!a)return null;n.unshift({...a,route:i})}return n}}}function qt(e){return Array.isArray(e)?e:[e]}function Jt(e,t=``,n=[],r=[]){let i=qt(e);for(let e=0,a=i.length;e<a;e++){let a=i[e];if(a&&typeof a==`object`){a.hasOwnProperty(`path`)||(a.path=``);let e=Gt(a,t);for(let t of e){n.push(t);let e=Array.isArray(a.children)&&a.children.length===0;if(a.children&&!e)Jt(a.children,t.pattern,n,r);else{let e=Kt([...n],r.length);r.push(e)}n.pop()}}}return n.length?r:r.sort((e,t)=>t.score-e.score)}function Yt(e,t){for(let n=0,r=e.length;n<r;n++){let r=e[n].matcher(t);if(r)return r}return[]}function Xt(e,t,n){let r=new URL(Ut),i=d(t=>{let n=e();try{return new URL(n,r)}catch{return console.error(`Invalid path ${n}`),t}},r,{equals:(e,t)=>e.href===t.href}),a=d(()=>i().pathname),o=d(()=>i().search,!0),s=d(()=>i().hash),c=()=>``,l=g(o,()=>Ft(i()));return{get pathname(){return a()},get search(){return o()},get hash(){return s()},get state(){return t()},get key(){return c()},query:n?n(l):zt(l)}}function Zt(){return fn}function Qt(e){pn=e}function $t(e,t,n,r={}){let{signal:[i,a],utils:o={}}=e,c=o.parsePath||(e=>e),u=o.renderPath||(e=>e),f=o.beforeLeave||Tt(),p=Mt(``,r.base||``);if(p===void 0)throw Error(`${p} is not a valid base path`);p&&!i().value&&a({value:p,replace:!0,scroll:!1});let[_,v]=s(!1),y,S=(e,t)=>{t.value===w()&&t.state===T()||(y===void 0&&v(!0),fn=e,y=t,x(()=>{y===t&&(ee(y.value),E(y.state),be(),k[1](e=>e.filter(e=>e.pending)))}).finally(()=>{y===t&&m(()=>{fn=void 0,e===`navigate`&&ie(y),v(!1),y=void 0})}))},[w,ee]=s(i().value),[T,E]=s(i().state),D=Xt(w,T,o.queryWrapper),O=[],k=s([]),A=d(()=>typeof r.transformUrl==`function`?Yt(t(),r.transformUrl(D.pathname)):Yt(t(),D.pathname)),j=()=>{let e=A(),t={};for(let n=0;n<e.length;n++)Object.assign(t,e[n].params);return t},te=o.paramsWrapper?o.paramsWrapper(j,t):zt(j),M={pattern:p,path:()=>p,outlet:()=>null,resolvePath(e){return Mt(p,e)}};return l(g(i,e=>S(`native`,e),{defer:!0})),{base:M,location:D,params:te,isRouting:_,renderPath:u,parsePath:c,navigatorFactory:re,matches:A,beforeLeave:f,preloadRoute:N,singleFlight:r.singleFlight===void 0?!0:r.singleFlight,submissions:k};function ne(e,t,n){h(()=>{if(typeof t==`number`){t&&(o.go?o.go(t):console.warn(`Router integration does not support relative routing`));return}let r=!t||t[0]===`?`,{replace:i,resolve:a,scroll:s,state:c}={replace:!1,resolve:!r,scroll:!0,...n},l=a?e.resolvePath(t):Mt(r&&D.pathname||``,t);if(l===void 0)throw Error(`Path '${t}' is not a routable path`);if(O.length>=tn)throw Error(`Too many redirects`);let u=w();(l!==u||c!==T())&&f.confirm(l,n)&&(O.push({value:u,replace:i,scroll:s,state:T()}),S(`navigate`,{value:l,state:c}))})}function re(e){return e=e||C(rn)||M,(t,n)=>ne(e,t,n)}function ie(e){let t=O[0];t&&(a({...e,replace:t.replace,scroll:t.scroll}),O.length=0)}function N(e,r){let i=Yt(t(),e.pathname),a=fn;fn=`preload`;for(let t in i){let{route:a,params:o}=i[t];a.component&&a.component.preload&&a.component.preload();let{preload:s}=a;pn=!0,r&&s&&b(n(),()=>s({params:o,location:{pathname:e.pathname,search:e.search,hash:e.hash,query:Ft(e),state:null,key:``},intent:`preload`})),pn=!1}fn=a}}function en(e,t,n,r){let{base:i,location:a,params:o}=e,{pattern:s,component:c,preload:l}=r().route,u=d(()=>r().path);c&&c.preload&&c.preload(),pn=!0;let f=l?l({params:o,location:a,intent:fn||`initial`}):void 0;return pn=!1,{parent:t,pattern:s,path:u,outlet:()=>c?P(c,{params:o,location:a,data:f,get children(){return n()}}):n(),resolvePath(e){return Mt(i.path(),e,u())}}}var tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn=t((()=>{G(),X(),At(),Wt(),tn=100,nn=S(),rn=S(),an=()=>Nt(C(nn),`<A> and 'use' router primitives can be only used inside a Route.`),on=()=>C(rn)||an().base,sn=e=>{let t=on();return d(()=>t.resolvePath(e()))},cn=e=>{let t=an();return d(()=>{let n=e();return n===void 0?n:t.renderPath(n)})},ln=()=>an().navigatorFactory(),un=()=>an().location,dn=()=>an().params}));function hn(e){let t=e.routerState.location,n=e.routerState.params,r=d(()=>e.preload&&h(()=>{Qt(!0),e.preload({params:n,location:t,intent:Zt()||`initial`}),Qt(!1)}));return P(L,{get when(){return e.root},keyed:!0,get fallback(){return e.children},children:i=>P(i,{params:n,location:t,get data(){return r()},get children(){return e.children}})})}function gn(e){let t=[],n,r=d(g(e.routerState.matches,(i,a,s)=>{let c=a&&i.length===a.length,l=[];for(let n=0,u=i.length;n<u;n++){let u=a&&a[n],d=i[n];s&&u&&d.route.key===u.route.key?l[n]=s[n]:(c=!1,t[n]&&t[n](),o(i=>{t[n]=i,l[n]=en(e.routerState,l[n-1]||e.routerState.base,vn(()=>r()[n+1]),()=>{let t=e.routerState.matches();return t[n]??t[0]})}))}return t.splice(i.length).forEach(e=>e()),s&&c?s:(n=l[0],l)}));return vn(()=>r()&&n)()}var _n,vn,yn,bn=t((()=>{X(),G(),mn(),_n=e=>t=>{let{base:n}=t,r=w(()=>t.children),i=d(()=>Jt(r(),t.base||``)),a,o=$t(e,i,()=>a,{base:n,singleFlight:t.singleFlight,transformUrl:t.transformUrl});return e.create&&e.create(o),P(nn.Provider,{value:o,get children(){return P(hn,{routerState:o,get root(){return t.root},get preload(){return t.rootPreload||t.rootLoad},get children(){return[Y(()=>(a=y())&&null),P(gn,{routerState:o,get branches(){return i()}})]}})}})},vn=e=>()=>P(L,{get when(){return e()},keyed:!0,children:e=>P(rn.Provider,{value:e,get children(){return e.outlet()}})}),yn=e=>{let t=w(()=>e.children);return F(e,{get children(){return t()}})}}));function xn([e,t],n,r){return[n?()=>n(e()):e,r?e=>t(r(e)):t]}function Sn(e){let t=!1,n=e=>typeof e==`string`?{value:e}:e,r=xn(s(n(e.get()),{equals:(e,t)=>e.value===t.value&&e.state===t.state}),void 0,n=>(!t&&e.set(n),R.registry&&!R.done&&(R.done=!0),n));return e.init&&v(e.init((i=e.get())=>{t=!0,r[1](n(i)),t=!1})),_n({signal:r,create:e.create,utils:e.utils})}function Cn(e,t,n){return e.addEventListener(t,n),()=>e.removeEventListener(t,n)}function wn(e,t){let n=e&&document.getElementById(e);n?n.scrollIntoView():t&&window.scrollTo(0,0)}var Tn=t((()=>{G(),bn()})),En,Dn=t((()=>{En=new Map}));function On(e=!0,t=!1,n=`/_server`,r){return i=>{let a=i.base.path(),o=i.navigatorFactory(i.base),s,c;function l(e){return e.namespaceURI===`http://www.w3.org/2000/svg`}function u(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;let n=e.composedPath().find(e=>e instanceof Node&&e.nodeName.toUpperCase()===`A`);if(!n||t&&!n.hasAttribute(`link`))return;let r=l(n),i=r?n.href.baseVal:n.href;if((r?n.target.baseVal:n.target)||!i&&!n.hasAttribute(`state`))return;let o=(n.getAttribute(`rel`)||``).split(/\s+/);if(n.hasAttribute(`download`)||o&&o.includes(`external`))return;let s=r?new URL(i,document.baseURI):new URL(i);if(!(s.origin!==window.location.origin||a&&s.pathname&&!s.pathname.toLowerCase().startsWith(a.toLowerCase())))return[n,s]}function d(e){let t=u(e);if(!t)return;let[n,r]=t,a=i.parsePath(r.pathname+r.search+r.hash),s=n.getAttribute(`state`);e.preventDefault(),o(a,{resolve:!1,replace:n.hasAttribute(`replace`),scroll:!n.hasAttribute(`noscroll`),state:s?JSON.parse(s):void 0})}function f(e){let t=u(e);if(!t)return;let[n,a]=t;r&&(a.pathname=r(a.pathname)),i.preloadRoute(a,n.getAttribute(`preload`)!==`false`)}function p(e){clearTimeout(s);let t=u(e);if(!t)return c=null;let[n,a]=t;c!==n&&(r&&(a.pathname=r(a.pathname)),s=setTimeout(()=>{i.preloadRoute(a,n.getAttribute(`preload`)!==`false`),c=n},20))}function m(e){if(e.defaultPrevented)return;let t=e.submitter&&e.submitter.hasAttribute(`formaction`)?e.submitter.getAttribute(`formaction`):e.target.getAttribute(`action`);if(!t)return;if(!t.startsWith(`https://action/`)){let e=new URL(t,Ut);if(t=i.parsePath(e.pathname+e.search),!t.startsWith(n))return}if(e.target.method.toUpperCase()!==`POST`)throw Error(`Only POST forms are supported for Actions`);let r=En.get(t);if(r){e.preventDefault();let t=new FormData(e.target,e.submitter);r.call({r:i,f:e.target},e.target.enctype===`multipart/form-data`?t:new URLSearchParams(t))}}Ge([`click`,`submit`]),document.addEventListener(`click`,d),e&&(document.addEventListener(`mousemove`,p,{passive:!0}),document.addEventListener(`focusin`,f,{passive:!0}),document.addEventListener(`touchstart`,f,{passive:!0})),document.addEventListener(`submit`,m),v(()=>{document.removeEventListener(`click`,d),e&&(document.removeEventListener(`mousemove`,p),document.removeEventListener(`focusin`,f),document.removeEventListener(`touchstart`,f)),document.removeEventListener(`submit`,m)})}}var kn=t((()=>{X(),G(),Dn(),Wt()}));function An(e){let t=e.replace(/^.*?#/,``);if(!t.startsWith(`/`)){let[,e=`/`]=window.location.hash.split(`#`,2);return`${e}#${t}`}return t}function jn(e){let t=()=>window.location.hash.slice(1),n=Tt();return Sn({get:t,set({value:e,replace:t,scroll:n,state:r}){t?window.history.replaceState(Dt(r),``,`#`+e):window.history.pushState(r,``,`#`+e);let i=e.indexOf(`#`);wn(i>=0?e.slice(i+1):``,n),Et()},init:e=>Cn(window,`hashchange`,Ot(e,e=>!n.confirm(e&&e<0?e:t()))),create:On(e.preload,e.explicitLinks,e.actionBase),utils:{go:e=>window.history.go(e),renderPath:e=>`#${e}`,parsePath:An,beforeLeave:n}})(e)}var Mn=t((()=>{kn(),Tn(),At()})),Nn=t((()=>{bn(),Tn(),X(),kn(),At(),Mn()}));function Pn(e){e=F({inactiveClass:`inactive`,activeClass:`active`},e);let[,t]=ge(e,[`href`,`state`,`class`,`activeClass`,`inactiveClass`,`end`]),n=sn(()=>e.href),r=cn(n),i=un(),a=d(()=>{let t=n();if(t===void 0)return[!1,!1];let r=jt(t.split(/[?#]/,1)[0]).toLowerCase(),a=decodeURI(jt(i.pathname).toLowerCase());return[e.end?r===a:a.startsWith(r+`/`)||a===r,r===a]});return(()=>{var n=Fn();return $e(n,F(t,{get href(){return r()||e.href},get state(){return JSON.stringify(e.state)},get classList(){return{...e.class&&{[e.class]:!0},[e.inactiveClass]:!a()[0],[e.activeClass]:a()[0],...t.classList}},link:``,get"aria-current"(){return a()[1]?`page`:void 0}}),!1,!1),n})()}var Fn,In=t((()=>{X(),G(),mn(),Wt(),Fn=K(`<a>`)})),Ln=t((()=>{G(),X(),Dn(),mn()})),Rn=t((()=>{Nn(),In(),At(),mn(),Wt(),Ln()})),zn,Bn=t((()=>{zn={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":2,"stroke-linecap":`round`,"stroke-linejoin":`round`}})),Vn,Hn,Un,Wn,Z,Q=t((()=>{X(),G(),Bn(),Vn=K(`<svg>`),Hn=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),Un=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),Wn=e=>{let[t,n]=ge(e,[`color`,`size`,`strokeWidth`,`children`,`class`,`name`,`iconNode`,`absoluteStrokeWidth`]);return(()=>{var e=Vn();return $e(e,F(zn,{get width(){return t.size??zn.width},get height(){return t.size??zn.height},get stroke(){return t.color??zn.stroke},get"stroke-width"(){return Y(()=>!!t.absoluteStrokeWidth)()?Number(t.strokeWidth??zn[`stroke-width`])*24/Number(t.size):Number(t.strokeWidth??zn[`stroke-width`])},get class(){return Un(`lucide`,`lucide-icon`,t.name==null?void 0:`lucide-${Hn(t?.name)}`,t.class==null?``:t.class)}},n),!0,!0),J(e,P(I,{get each(){return t.iconNode},children:([e,t])=>P(ht,F({component:e},t))})),e})()},Z=Wn})),Gn,Kn,qn,Jn=t((()=>{X(),Q(),Gn=[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]],Kn=e=>P(Z,F(e,{name:`Activity`,iconNode:Gn})),qn=Kn})),Yn,Xn,Zn,Qn=t((()=>{X(),Q(),Yn=[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]],Xn=e=>P(Z,F(e,{name:`ArrowLeft`,iconNode:Yn})),Zn=Xn})),$n,er,tr,nr=t((()=>{X(),Q(),$n=[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]],er=e=>P(Z,F(e,{name:`BookOpen`,iconNode:$n})),tr=er})),rr,ir,ar,or=t((()=>{X(),Q(),rr=[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]],ir=e=>P(Z,F(e,{name:`ChevronDown`,iconNode:rr})),ar=ir})),sr,cr,lr,ur=t((()=>{X(),Q(),sr=[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]],cr=e=>P(Z,F(e,{name:`ChevronRight`,iconNode:sr})),lr=cr})),dr,fr,pr,mr=t((()=>{X(),Q(),dr=[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]],fr=e=>P(Z,F(e,{name:`ChevronUp`,iconNode:dr})),pr=fr})),hr,gr,_r,vr=t((()=>{X(),Q(),hr=[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]],gr=e=>P(Z,F(e,{name:`CircleCheckBig`,iconNode:hr})),_r=gr})),yr,br,xr,Sr=t((()=>{X(),Q(),yr=[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]],br=e=>P(Z,F(e,{name:`CircleDashed`,iconNode:yr})),xr=br})),Cr,wr,Tr,Er=t((()=>{X(),Q(),Cr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]],wr=e=>P(Z,F(e,{name:`CircleX`,iconNode:Cr})),Tr=wr})),Dr,Or,kr,Ar=t((()=>{X(),Q(),Dr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]],Or=e=>P(Z,F(e,{name:`Clock`,iconNode:Dr})),kr=Or})),jr,Mr,Nr,Pr=t((()=>{X(),Q(),jr=[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]],Mr=e=>P(Z,F(e,{name:`CodeXml`,iconNode:jr})),Nr=Mr})),Fr,Ir,Lr,Rr=t((()=>{X(),Q(),Fr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M9 15h6`,key:`cctwl0`}],[`path`,{d:`M12 18v-6`,key:`17g6i2`}]],Ir=e=>P(Z,F(e,{name:`FilePlus`,iconNode:Fr})),Lr=Ir})),zr,Br,Vr,Hr=t((()=>{X(),Q(),zr=[[`path`,{d:`M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z`,key:`1rqfz7`}],[`path`,{d:`M14 2v4a2 2 0 0 0 2 2h4`,key:`tnqrlb`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]],Br=e=>P(Z,F(e,{name:`FileText`,iconNode:zr})),Vr=Br})),Ur,Wr,Gr,Kr=t((()=>{X(),Q(),Ur=[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]],Wr=e=>P(Z,F(e,{name:`FolderOpen`,iconNode:Ur})),Gr=Wr})),qr,Jr,Yr,Xr=t((()=>{X(),Q(),qr=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]],Jr=e=>P(Z,F(e,{name:`Globe`,iconNode:qr})),Yr=Jr})),Zr,Qr,$r,ei=t((()=>{X(),Q(),Zr=[[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}],[`path`,{d:`M10.41 10.41a2 2 0 1 1-2.83-2.83`,key:`1bzlo9`}],[`line`,{x1:`13.5`,x2:`6`,y1:`13.5`,y2:`21`,key:`1q0aeu`}],[`line`,{x1:`18`,x2:`21`,y1:`12`,y2:`15`,key:`5mozeu`}],[`path`,{d:`M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59`,key:`mmje98`}],[`path`,{d:`M21 15V5a2 2 0 0 0-2-2H9`,key:`43el77`}]],Qr=e=>P(Z,F(e,{name:`ImageOff`,iconNode:Zr})),$r=Qr})),ti,ni,ri,ii=t((()=>{X(),Q(),ti=[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]],ni=e=>P(Z,F(e,{name:`Image`,iconNode:ti})),ri=ni})),ai,oi,si,ci=t((()=>{X(),Q(),ai=[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]],oi=e=>P(Z,F(e,{name:`Languages`,iconNode:ai})),si=oi})),li,ui,di,fi=t((()=>{X(),Q(),li=[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]],ui=e=>P(Z,F(e,{name:`Layers`,iconNode:li})),di=ui})),pi,mi,hi,gi=t((()=>{X(),Q(),pi=[[`rect`,{width:`7`,height:`9`,x:`3`,y:`3`,rx:`1`,key:`10lvy0`}],[`rect`,{width:`7`,height:`5`,x:`14`,y:`3`,rx:`1`,key:`16une8`}],[`rect`,{width:`7`,height:`9`,x:`14`,y:`12`,rx:`1`,key:`1hutg5`}],[`rect`,{width:`7`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`ldoo1y`}]],mi=e=>P(Z,F(e,{name:`LayoutDashboard`,iconNode:pi})),hi=mi})),_i,vi,yi,bi=t((()=>{X(),Q(),_i=[[`path`,{d:`M12 20h9`,key:`t2du7b`}],[`path`,{d:`M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z`,key:`1ykcvy`}]],vi=e=>P(Z,F(e,{name:`PenLine`,iconNode:_i})),yi=vi})),xi,Si,Ci,wi=t((()=>{X(),Q(),xi=[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]],Si=e=>P(Z,F(e,{name:`Pen`,iconNode:xi})),Ci=Si})),Ti,Ei,Di,Oi=t((()=>{X(),Q(),Ti=[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]],Ei=e=>P(Z,F(e,{name:`Plus`,iconNode:Ti})),Di=Ei})),ki,Ai,ji,Mi=t((()=>{X(),Q(),ki=[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]],Ai=e=>P(Z,F(e,{name:`RefreshCw`,iconNode:ki})),ji=Ai})),Ni,Pi,Fi,Ii=t((()=>{X(),Q(),Ni=[[`path`,{d:`M3 7V5a2 2 0 0 1 2-2h2`,key:`aa7l1z`}],[`path`,{d:`M17 3h2a2 2 0 0 1 2 2v2`,key:`4qcy5o`}],[`path`,{d:`M21 17v2a2 2 0 0 1-2 2h-2`,key:`6vwrx8`}],[`path`,{d:`M7 21H5a2 2 0 0 1-2-2v-2`,key:`ioqczr`}],[`path`,{d:`M7 8h8`,key:`1jbsf9`}],[`path`,{d:`M7 12h10`,key:`b7w52i`}],[`path`,{d:`M7 16h6`,key:`1vyc9m`}]],Pi=e=>P(Z,F(e,{name:`ScanText`,iconNode:Ni})),Fi=Pi})),Li,Ri,zi,Bi=t((()=>{X(),Q(),Li=[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]],Ri=e=>P(Z,F(e,{name:`ShieldAlert`,iconNode:Li})),zi=Ri})),Vi,Hi,Ui,Wi=t((()=>{X(),Q(),Vi=[[`path`,{d:`M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z`,key:`4pj2yx`}],[`path`,{d:`M20 3v4`,key:`1olli1`}],[`path`,{d:`M22 5h-4`,key:`1gvqau`}],[`path`,{d:`M4 17v2`,key:`vumght`}],[`path`,{d:`M5 18H3`,key:`zchphs`}]],Hi=e=>P(Z,F(e,{name:`Sparkles`,iconNode:Vi})),Ui=Hi})),Gi,Ki,qi,Ji=t((()=>{X(),Q(),Gi=[[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6`,key:`4alrt4`}],[`path`,{d:`M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2`,key:`v07s0e`}],[`line`,{x1:`10`,x2:`10`,y1:`11`,y2:`17`,key:`1uufr5`}],[`line`,{x1:`14`,x2:`14`,y1:`11`,y2:`17`,key:`xtxkd`}]],Ki=e=>P(Z,F(e,{name:`Trash2`,iconNode:Gi})),qi=Ki})),Yi,Xi,Zi,Qi=t((()=>{X(),Q(),Yi=[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]],Xi=e=>P(Z,F(e,{name:`X`,iconNode:Yi})),Zi=Xi})),$i=t((()=>{Jn(),Qn(),nr(),or(),ur(),mr(),Sr(),Ar(),Rr(),Hr(),Kr(),Xr(),ei(),ii(),ci(),fi(),gi(),bi(),Oi(),Mi(),Ii(),Bi(),Wi(),Ji(),Qi()})),ea=t((()=>{vr()})),ta=t((()=>{Er()})),na=t((()=>{Pr()})),ra=t((()=>{wi()})),ia=t((()=>{ea(),ta(),na(),ra()})),aa=t((()=>{})),oa=t((()=>{})),sa=t((()=>{ia(),aa(),oa()})),ca=t((()=>{})),la=t((()=>{$i(),sa(),ca()}));X(),Rn(),la();var ua=K(`<div class="flex h-screen bg-slate-50 text-slate-800"><nav class="group flex w-14 flex-col gap-1 overflow-hidden bg-slate-900 px-2 py-4 transition-all duration-200 hover:w-48"><div class="mb-4 flex items-center gap-3 px-1"><span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-violet-600 text-xs font-bold text-white">W</span><span class="whitespace-nowrap text-sm font-semibold text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100">WebOCR</span></div></nav><main class="flex-1 overflow-y-auto">`),da=K(`<span class="flex h-8 w-8 shrink-0 items-center justify-center">`),fa=K(`<span class="whitespace-nowrap text-sm opacity-0 transition-opacity duration-200 group-hover:opacity-100">`),pa=[{href:`/`,label:`Dashboard`,Icon:hi},{href:`/jobs`,label:`Jobs`,Icon:ri},{href:`/library`,label:`Library`,Icon:tr}];function ma(e){return(()=>{var t=ua(),n=t.firstChild;n.firstChild;var r=n.nextSibling;return J(n,()=>pa.map(e=>P(Pn,{get href(){return e.href},get end(){return e.href===`/`},class:`flex items-center gap-3 rounded-lg px-1 py-2 text-slate-400 transition-colors hover:bg-slate-800 hover:text-white`,activeClass:`bg-slate-800 text-white!`,get children(){return[(()=>{var t=da();return J(t,P(e.Icon,{class:`h-5 w-5`})),t})(),(()=>{var t=fa();return J(t,()=>e.label),t})()]}})),null),J(r,()=>e.children),t})()}X(),G(),la();var ha=K(`<span class="inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700">`),ga=K(`<span class="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-500">`),_a=K(`<span class="inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-xs text-red-600">`),va=K(`<div class="min-h-screen bg-slate-50 px-4 py-10"><div class="mx-auto max-w-2xl space-y-8"><div class="flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div><h1 class="text-xl font-semibold text-slate-800">Web OCR Server</h1><p class="text-sm text-slate-500">ASP.NET Core · Manga-OCR · Opus-MT</p></div><div class=ml-auto></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">Server info</span></div></div><div class="rounded-2xl bg-white shadow-sm ring-1 ring-slate-200"><div class="border-b border-slate-100 px-5 py-3"><span class="text-sm font-medium text-slate-600">API Endpoints</span></div><ul class="divide-y divide-slate-50">`),ya=K(`<div class="flex items-center gap-2 px-5 py-4 text-sm text-red-600">`),ba=K(`<div class="px-5 py-4 text-sm text-slate-400">Loading…`),xa=K(`<dl class="divide-y divide-slate-50 text-sm"><div class="flex items-center gap-3 px-5 py-3"><dt class="w-36 shrink-0 text-slate-500">Version</dt><dd class="font-medium text-slate-800"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> OCR models</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-start gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> Translate</dt><dd class="break-all font-mono text-xs text-slate-600"></dd></div><div class="flex items-center gap-3 px-5 py-3"><dt class="flex w-36 shrink-0 items-center gap-1 text-slate-500"> DeepL</dt><dd>`),Sa=K(`<li class="flex items-center gap-4 px-5 py-3.5 text-sm"><span></span><code class="w-28 shrink-0 text-slate-700"></code><span></span><span class=text-slate-500>`);function Ca(e){return P(L,{get when(){return e.ok!==null},get fallback(){return(()=>{var t=ga();return J(t,P(xr,{class:`h-3 w-3 animate-spin`}),null),J(t,()=>e.label,null),t})()},get children(){return P(L,{get when(){return e.ok},get fallback(){return(()=>{var t=_a();return J(t,P(Tr,{class:`h-3 w-3`}),null),J(t,()=>e.label,null),t})()},get children(){var t=ha();return J(t,P(_r,{class:`h-3 w-3`}),null),J(t,()=>e.label,null),t}})}})}var wa=[{method:`GET`,path:`/health`,desc:`Server status, version, model paths`,Icon:qn,color:`text-sky-600`},{method:`POST`,path:`/ocr`,desc:`Base64 image → Japanese text`,Icon:Fi,color:`text-violet-600`},{method:`POST`,path:`/translate`,desc:`Japanese → English (local Opus-MT or DeepL)`,Icon:si,color:`text-amber-600`},{method:`POST`,path:`/analyze`,desc:`Tokenise text + dictionary lookup`,Icon:tr,color:`text-emerald-600`}],Ta={GET:`bg-sky-50 text-sky-700`,POST:`bg-violet-50 text-violet-700`};function Ea(){let[e,t]=s(null),[n,r]=s(null);_(()=>{fetch(`/health`).then(e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);return e.json()}).then(t).catch(e=>r(String(e)))});let i=()=>{if(n())return!1;let t=e();return t?t.status===`ok`:null},a=()=>{if(n())return`error`;let t=e();return t?t.status:`connecting`};return(()=>{var t=va(),r=t.firstChild.firstChild,o=r.firstChild,s=o.nextSibling.nextSibling,c=r.nextSibling;c.firstChild;var u=c.nextSibling.firstChild.nextSibling;return J(o,P(Nr,{class:`h-6 w-6 text-slate-700`})),J(s,P(Ca,{get ok(){return i()},get label(){return a()}})),J(c,P(L,{get when(){return!n()},get fallback(){return(()=>{var e=ya();return J(e,P(zi,{class:`h-4 w-4 shrink-0`}),null),J(e,n,null),e})()},get children(){return P(L,{get when(){return e()},get fallback(){return ba()},children:e=>(()=>{var t=xa(),n=t.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild,o=a.firstChild,s=a.nextSibling,c=i.nextSibling,l=c.firstChild,u=l.firstChild,d=l.nextSibling,f=c.nextSibling.firstChild,p=f.firstChild,m=f.nextSibling;return J(r,()=>e().version),J(a,P(Gr,{class:`h-3.5 w-3.5`}),o),J(s,()=>e().ocr_models_dir),J(l,P(Gr,{class:`h-3.5 w-3.5`}),u),J(d,()=>e().translate_models_dir),J(f,P(Yr,{class:`h-3.5 w-3.5`}),p),J(m,P(Ca,{get ok(){return e().deepl_available},get label(){return e().deepl_available?`configured`:`not configured`}})),t})()})}}),null),J(u,P(I,{each:wa,children:({method:e,path:t,desc:n,Icon:r,color:i})=>(()=>{var a=Sa(),o=a.firstChild,s=o.nextSibling,c=s.nextSibling,u=c.nextSibling;return J(o,e),J(s,t),Je(c,`shrink-0 ${i}`),J(c,P(r,{class:`h-4 w-4`})),J(u,n),l(()=>Je(o,`w-12 shrink-0 rounded px-1.5 py-0.5 text-center text-xs font-semibold ${Ta[e]??``}`)),a})()})),t})()}function Da(e){return e.replace(/_([a-z])/g,(e,t)=>t.toUpperCase())}function Oa(e){return e.replace(/([A-Z])/g,e=>`_${e.toLowerCase()}`)}function ka(e){if(Array.isArray(e))return e.map(ka);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Da(n)]=ka(r);return t}return e}function Aa(e){if(Array.isArray(e))return e.map(Aa);if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[Oa(n)]=Aa(r);return t}return e}async function $(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`,...t?.headers},...t});if(!n.ok){let e=await n.text().catch(()=>n.statusText);throw Error(`API ${n.status}: ${e}`)}if(n.status!==204)return ka(await n.json())}function ja(e={}){let t=new URLSearchParams;e.page!==void 0&&t.set(`page`,String(e.page)),e.pageSize!==void 0&&t.set(`page_size`,String(e.pageSize)),e.status&&t.set(`status`,e.status),e.chapterId!==void 0&&t.set(`chapter_id`,String(e.chapterId));let n=t.toString();return $(`/api/portal/jobs${n?`?${n}`:``}`)}function Ma(e){return $(`/api/portal/jobs/${e}`)}function Na(e,t){return $(`/api/portal/jobs/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Pa(e){return $(`/api/portal/jobs/${e}/bubbles`)}function Fa(e,t){return $(`/api/portal/jobs/${e}/bubbles`,{method:`POST`,body:JSON.stringify(Aa(t))})}function Ia(e,t,n){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`PUT`,body:JSON.stringify(Aa(n))})}function La(e,t){return $(`/api/portal/jobs/${e}/bubbles/${t}`,{method:`DELETE`})}function Ra(e){return $(`/api/portal/jobs/${e}/redetect`,{method:`POST`})}function za(e){return $(`/api/portal/jobs/${e}/retranslate`,{method:`POST`})}function Ba(e){return $(`/api/portal/jobs/${e}/rerender`,{method:`POST`})}function Va(){return $(`/api/portal/volumes`)}function Ha(e){return $(`/api/portal/volumes`,{method:`POST`,body:JSON.stringify(Aa(e))})}function Ua(e,t){return $(`/api/portal/volumes/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Wa(e){return $(`/api/portal/volumes/${e}`,{method:`DELETE`})}function Ga(e={}){let t=new URLSearchParams;e.volumeId!==void 0&&t.set(`volume_id`,String(e.volumeId));let n=t.toString();return $(`/api/portal/chapters${n?`?${n}`:``}`)}function Ka(e){return $(`/api/portal/chapters`,{method:`POST`,body:JSON.stringify(Aa(e))})}function qa(e,t){return $(`/api/portal/chapters/${e}`,{method:`PUT`,body:JSON.stringify(Aa(t))})}function Ja(e){return $(`/api/portal/chapters/${e}`,{method:`DELETE`})}function Ya(e){return $(`/api/portal/chapters/${e}/jobs`)}function Xa(e){return`/api/portal/jobs/${e}/original`}function Za(e){return`/api/portal/jobs/${e}/result`}var Qa=t((()=>{})),$a=n({JobsListPage:()=>no,StatusBadge:()=>eo});function eo(e){let t=()=>{switch(e.status){case`done`:return{cls:`bg-green-100 text-green-700`,Icon:_r,label:`Done`};case`processing`:return{cls:`bg-yellow-100 text-yellow-700`,Icon:kr,label:`Processing`};case`error`:return{cls:`bg-red-100 text-red-700`,Icon:Tr,label:`Error`};default:return{cls:`bg-slate-100 text-slate-600`,Icon:kr,label:String(e.status)}}};return(()=>{var e=ro();return J(e,()=>P(t()?.Icon??kr,{class:`h-3 w-3`}),null),J(e,()=>t()?.label??``,null),l(()=>Je(e,`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${t()?.cls??``}`)),e})()}function to(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=io(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling.firstChild,s=o.nextSibling.firstChild,c=s.firstChild,u=s.nextSibling;return Ye(n,`click`,e.onClick,!0),J(a,P(eo,{get status(){return e.job.status}})),J(o,()=>e.job.title),J(s,P(di,{class:`h-3 w-3`}),c),J(s,()=>e.job.bubbleCount,c),J(u,()=>new Date(e.job.createdAt).toLocaleDateString()),l(n=>{var r=t(),a=e.job.title;return r!==n.e&&q(i,`src`,n.e=r),a!==n.t&&q(i,`alt`,n.t=a),n},{e:void 0,t:void 0}),n})()}function no(){let e=ln(),[t,n]=s(``),[r,i]=s(``),[a]=p(t,e=>ja({pageSize:100,status:e||void 0})),o=()=>{let e=r().toLowerCase();return(a()?.items??[]).filter(t=>!e||t.title.toLowerCase().includes(e))};return(()=>{var s=so(),c=s.firstChild,u=c.firstChild,d=c.nextSibling.firstChild,f=d.nextSibling;return J(u,P(ri,{class:`h-5 w-5 text-violet-600`})),d.$$input=e=>i(e.currentTarget.value),f.addEventListener(`change`,e=>n(e.currentTarget.value)),J(f,()=>fo.map(e=>(()=>{var t=co();return J(t,()=>e.label),l(()=>t.value=e.value),t})())),J(s,P(L,{get when(){return a.loading},get children(){var e=ao();return J(e,()=>Array.from({length:10}).map(()=>lo())),e}}),null),J(s,P(L,{get when(){return a.error},get children(){var e=oo();return e.firstChild,J(e,()=>String(a.error),null),e}}),null),J(s,P(L,{get when(){return Y(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return o().length>0},get fallback(){return(()=>{var e=uo(),t=e.firstChild;return J(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var t=ao();return J(t,P(I,{get each(){return o()},children:t=>P(to,{job:t,onClick:()=>e(`/jobs/${t.id}`)})})),t}})}}),null),l(()=>d.value=r()),l(()=>f.value=t()),s})()}var ro,io,ao,oo,so,co,lo,uo,fo,po=t((()=>{X(),G(),Rn(),la(),Qa(),ro=K(`<span>`),io=K(`<button class="group flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-violet-500"><div class="relative aspect-3/4 w-full overflow-hidden bg-slate-100"><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><div class="absolute right-2 top-2"></div></div><div class="flex flex-col gap-1 p-3"><p class="truncate text-sm font-medium text-slate-800"></p><div class="flex items-center gap-3 text-xs text-slate-500"><span class="flex items-center gap-1"> bubbles</span><span class=ml-auto>`,!0,!1,!1),ao=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),oo=K(`<div class="rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load jobs: `),so=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Jobs</h1></div><div class="mb-6 flex flex-wrap gap-3"><input type=search placeholder="Search jobs…"class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-400"><select class="h-9 rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-400">`),co=K(`<option>`),lo=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),uo=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No jobs yet.</p><p class="max-w-xs text-center text-xs text-slate-400">Upload pages via the extension or API to see translation jobs here.`),fo=[{value:``,label:`All statuses`},{value:`done`,label:`Done`},{value:`processing`,label:`Processing`},{value:`error`,label:`Error`}],Ge([`click`,`input`])}));function mo(e,t,n,r){let{x:i,y:a,w:o,h:s}=t;switch(e){case`TL`:i+=n,a+=r,o-=n,s-=r;break;case`T`:a+=r,s-=r;break;case`TR`:a+=r,o+=n,s-=r;break;case`L`:i+=n,o-=n;break;case`R`:o+=n;break;case`BL`:i+=n,o-=n,s+=r;break;case`B`:s+=r;break;case`BR`:o+=n,s+=r;break}return o<5&&(o=5),s<5&&(s=5),{x:i,y:a,w:o,h:s}}function ho(e){let t,n,[r,i]=s({scale:1,offsetX:0,offsetY:0}),[a,o]=s({kind:`none`});function c(){if(!t||!e.imageWidth||!e.imageHeight)return;let n=t.clientWidth,r=t.clientHeight;if(n===0||r===0)return;let a=n/e.imageWidth,o=r/e.imageHeight,s=Math.min(a,o),c=e.imageWidth*s,l=e.imageHeight*s;i({scale:s,offsetX:(n-c)/2,offsetY:(r-l)/2})}function u(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return{x:e*n+i,y:t*n+a}}function d(e,t){let{scale:n,offsetX:i,offsetY:a}=r();return n===0?{x:0,y:0}:{x:(e-i)/n,y:(t-a)/n}}function f(e){let t=n.getBoundingClientRect();return d(e.clientX-t.left,e.clientY-t.top)}function p(e){let t=a();return t.kind===`moving`&&t.bubbleIndex===e.bubbleIndex?{x:e.bubbleX+(t.curImgX-t.startImgX),y:e.bubbleY+(t.curImgY-t.startImgY),w:e.bubbleW,h:e.bubbleH}:t.kind===`resizing`&&t.bubbleIndex===e.bubbleIndex?mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY):{x:e.bubbleX,y:e.bubbleY,w:e.bubbleW,h:e.bubbleH}}function m(){let e=a();return e.kind===`drawing`?{x:Math.min(e.startImgX,e.curImgX),y:Math.min(e.startImgY,e.curImgY),w:Math.abs(e.curImgX-e.startImgX),h:Math.abs(e.curImgY-e.startImgY)}:null}function h(e){let t=a();if(t.kind===`none`)return;e.preventDefault();let n=f(e);(t.kind===`moving`||t.kind===`resizing`||t.kind===`drawing`)&&o({...t,curImgX:n.x,curImgY:n.y})}function g(){let t=a();if(t.kind===`moving`){let n=t.curImgX-t.startImgX,r=t.curImgY-t.startImgY;(Math.abs(n)>1||Math.abs(r)>1)&&e.onMove(t.bubbleIndex,n,r)}else if(t.kind===`resizing`){let n=mo(t.handle,{x:t.origX,y:t.origY,w:t.origW,h:t.origH},t.curImgX-t.startImgX,t.curImgY-t.startImgY);e.onResize(t.bubbleIndex,n.x,n.y,n.w,n.h)}else if(t.kind===`drawing`){let n=Math.min(t.startImgX,t.curImgX),r=Math.min(t.startImgY,t.curImgY),i=Math.abs(t.curImgX-t.startImgX),a=Math.abs(t.curImgY-t.startImgY);i>5&&a>5?e.onDraw(n,r,i,a):e.onSelect(null)}o({kind:`none`}),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)}function y(e){e.preventDefault(),g()}function b(){window.addEventListener(`mousemove`,h),window.addEventListener(`mouseup`,y)}function x(t){if(t.preventDefault(),!e.drawMode){e.onSelect(null);return}let n=f(t);o({kind:`drawing`,startImgX:n.x,startImgY:n.y,curImgX:n.x,curImgY:n.y}),b()}function S(t,n){t.preventDefault(),t.stopPropagation(),e.onSelect(n.bubbleIndex);let r=f(t);o({kind:`moving`,bubbleIndex:n.bubbleIndex,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}function C(e,t,n){e.preventDefault(),e.stopPropagation();let r=f(e);o({kind:`resizing`,bubbleIndex:t.bubbleIndex,handle:n,origX:t.bubbleX,origY:t.bubbleY,origW:t.bubbleW,origH:t.bubbleH,startImgX:r.x,startImgY:r.y,curImgX:r.x,curImgY:r.y}),b()}return _(()=>{c();let e=new ResizeObserver(()=>c());e.observe(t),v(()=>{e.disconnect(),window.removeEventListener(`mousemove`,h),window.removeEventListener(`mouseup`,y)})}),(()=>{var r=go(),i=r.firstChild,o=i.nextSibling,s=t;typeof s==`function`?et(s,r):t=r,i.addEventListener(`load`,c),q(i,`draggable`,!1),o.$$mousedown=x;var d=n;return typeof d==`function`?et(d,o):n=o,J(o,P(I,{get each(){return e.bubbles},children:t=>{let n=()=>p(t),r=()=>{let e=n(),t=u(e.x,e.y),r=u(e.x+e.w,e.y+e.h);return{x:t.x,y:t.y,w:r.x-t.x,h:r.y-t.y}},i=()=>e.selectedIndex===t.bubbleIndex,a=()=>t.isExcluded?`#9ca3af`:i()?`#7c3aed`:t.isManuallyAdded?`#10b981`:`#3b82f6`,o=()=>t.isExcluded?`rgba(0,0,0,0.15)`:i()?`rgba(124,58,237,0.1)`:`rgba(59,130,246,0.05)`;return(()=>{var e=vo(),s=e.firstChild,c=s.nextSibling,d=c.nextSibling;return s.$$mousedown=e=>S(e,t),J(e,P(L,{get when(){return t.isExcluded},get children(){var e=_o();return l(t=>{var n=r().x,i=r().y,a=r().x+r().w,o=r().y+r().h;return n!==t.e&&q(e,`x1`,t.e=n),i!==t.t&&q(e,`y1`,t.t=i),a!==t.a&&q(e,`x2`,t.a=a),o!==t.o&&q(e,`y2`,t.o=o),t},{e:void 0,t:void 0,a:void 0,o:void 0}),e}}),c),J(c,()=>t.bubbleIndex),J(d,()=>t.bubbleIndex),J(e,P(L,{get when(){return i()},get children(){return P(I,{each:xo,children:e=>{let[r,i]=So[e],a=()=>{let e=n();return u(e.x+r*e.w,e.y+i*e.h)};return(()=>{var n=yo();return n.$$mousedown=n=>C(n,t,e),l(t=>{var r=a().x-4,i=a().y-4,o=Co[e];return r!==t.e&&q(n,`x`,t.e=r),i!==t.t&&q(n,`y`,t.t=i),o!==t.a&&Qe(n,`cursor`,t.a=o),t},{e:void 0,t:void 0,a:void 0}),n})()}})}}),null),l(e=>{var t=r().x,n=r().y,l=r().w,u=r().h,f=o(),p=a(),m=i()?3:2,h=r().x+4,g=r().y+13,_=r().x+3,v=r().y+12;return t!==e.e&&q(s,`x`,e.e=t),n!==e.t&&q(s,`y`,e.t=n),l!==e.a&&q(s,`width`,e.a=l),u!==e.o&&q(s,`height`,e.o=u),f!==e.i&&q(s,`fill`,e.i=f),p!==e.n&&q(s,`stroke`,e.n=p),m!==e.s&&q(s,`stroke-width`,e.s=m),h!==e.h&&q(c,`x`,e.h=h),g!==e.r&&q(c,`y`,e.r=g),_!==e.d&&q(d,`x`,e.d=_),v!==e.l&&q(d,`y`,e.l=v),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0,h:void 0,r:void 0,d:void 0,l:void 0}),e})()}}),null),J(o,P(L,{get when(){return m()},children:e=>{let t=()=>{let t=e(),n=u(t.x,t.y),r=u(t.x+t.w,t.y+t.h);return{x:n.x,y:n.y,w:r.x-n.x,h:r.y-n.y}};return(()=>{var e=bo();return l(n=>{var r=t().x,i=t().y,a=t().w,o=t().h;return r!==n.e&&q(e,`x`,n.e=r),i!==n.t&&q(e,`y`,n.t=i),a!==n.a&&q(e,`width`,n.a=a),o!==n.o&&q(e,`height`,n.o=o),n},{e:void 0,t:void 0,a:void 0,o:void 0}),e})()}}),null),l(t=>{var n=e.imageUrl,r=a().kind===`moving`?`grabbing`:a().kind===`drawing`||e.drawMode?`crosshair`:`default`;return n!==t.e&&q(i,`src`,t.e=n),r!==t.t&&Qe(o,`cursor`,t.t=r),t},{e:void 0,t:void 0}),r})()}var go,_o,vo,yo,bo,xo,So,Co,wo=t((()=>{X(),G(),go=K(`<div class="relative overflow-hidden bg-slate-900 w-full h-full select-none"><img alt="manga page"class="w-full h-full object-contain pointer-events-none"><svg class="absolute inset-0 w-full h-full">`),_o=K(`<svg><line stroke=#9ca3af stroke-width=1 style=pointer-events:none></svg>`,!1,!0,!1),vo=K(`<svg><g><rect style=cursor:grab></rect><text font-size=10 fill=black style=pointer-events:none;user-select:none></text><text font-size=10 fill=white style=pointer-events:none;user-select:none></svg>`,!1,!0,!1),yo=K(`<svg><rect width=8 height=8 fill=white stroke=#7c3aed stroke-width=1.5></svg>`,!1,!0,!1),bo=K(`<svg><rect fill=rgba(16,185,129,0.1) stroke=#10b981 stroke-width=2 stroke-dasharray=4,2 style=pointer-events:none></svg>`,!1,!0,!1),xo=[`TL`,`T`,`TR`,`L`,`R`,`BL`,`B`,`BR`],So={TL:[0,0],T:[.5,0],TR:[1,0],L:[0,.5],R:[1,.5],BL:[0,1],B:[.5,1],BR:[1,1]},Co={TL:`nw-resize`,T:`n-resize`,TR:`ne-resize`,L:`w-resize`,R:`e-resize`,BL:`sw-resize`,B:`s-resize`,BR:`se-resize`},Ge([`mousedown`])}));function To(e){let t;return u(()=>{let n=e.selectedIndex;n!==null&&(t?.querySelector(`[data-bubble-idx="${n}"]`))?.scrollIntoView({behavior:`smooth`,block:`nearest`})}),(()=>{var n=Eo(),r=n.firstChild,i=r.firstChild,a=i.firstChild.nextSibling;a.nextSibling;var o=i.nextSibling,s=r.nextSibling;J(i,()=>e.bubbles.length,a),Ye(o,`click`,e.onAddBubble,!0),J(o,P(Di,{class:`h-3 w-3`}),null),J(o,P(yi,{class:`h-3 w-3`}),null);var c=t;return typeof c==`function`?et(c,s):t=s,J(s,P(L,{get when(){return e.bubbles.length>0},get fallback(){return Do()},get children(){return P(I,{get each(){return e.bubbles},children:t=>{let n=()=>e.selectedIndex===t.bubbleIndex;return(()=>{var r=Ao(),i=r.firstChild,a=i.firstChild;a.firstChild;var o=i.nextSibling;return r.$$click=()=>e.onSelect(n()?null:t.bubbleIndex),J(a,()=>t.bubbleIndex,null),J(i,P(L,{get when(){return t.isManuallyAdded},get children(){return Oo()}}),null),J(i,P(L,{get when(){return t.isExcluded},get children(){return ko()}}),null),J(o,()=>t.sourceText.slice(0,20)||`(empty)`),l(e=>{var i=t.bubbleIndex,s=`w-full border-b border-slate-100 px-3 py-2 text-left transition-colors ${n()?`border-l-2 border-l-violet-500 bg-violet-50`:`hover:bg-slate-50`} ${t.isExcluded?`opacity-50`:``}`,c=`font-mono text-xs font-medium ${n()?`text-violet-700`:`text-slate-500`}`,l=`mt-0.5 truncate text-xs ${t.isExcluded?`line-through text-slate-400`:`text-slate-600`}`;return i!==e.e&&q(r,`data-bubble-idx`,e.e=i),s!==e.t&&Je(r,e.t=s),c!==e.a&&Je(a,e.a=c),l!==e.o&&Je(o,e.o=l),e},{e:void 0,t:void 0,a:void 0,o:void 0}),r})()}})}})),n})()}var Eo,Do,Oo,ko,Ao,jo=t((()=>{X(),G(),la(),Eo=K(`<div class="flex flex-col h-full"><div class="flex items-center gap-2 border-b border-slate-100 px-3 py-2 shrink-0"><span class="flex-1 text-xs font-semibold uppercase tracking-wide text-slate-500">Bubbles (<!>)</span><button class="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium text-slate-600 hover:bg-slate-100 active:bg-slate-200 transition-colors"title="Draw a new bubble on the canvas"></button></div><div class="flex-1 overflow-y-auto">`),Do=K(`<div class="px-3 py-6 text-center text-xs text-slate-400">No bubbles detected`),Oo=K(`<span class="rounded bg-emerald-100 px-1 py-0.5 text-[10px] font-medium text-emerald-700">M`),ko=K(`<span class="rounded bg-slate-100 px-1 py-0.5 text-[10px] font-medium text-slate-500">×`),Ao=K(`<button><div class="flex items-center gap-1.5"><span>#</span></div><p>`),Ge([`click`])}));function Mo(e){return(()=>{var t=Po(),n=t.firstChild,r=n.nextSibling;return J(n,()=>e.label),r.addEventListener(`change`,t=>e.onChange(parseFloat(t.currentTarget.value)||0)),r.$$input=t=>e.onInput(parseFloat(t.currentTarget.value)||0),l(()=>r.value=e.value),t})()}function No(e){let[t,n]=s(0),[r,i]=s(0),[a,o]=s(0),[c,d]=s(0),[f,p]=s(``),[m,h]=s(``),[_,v]=s(!1);return u(g(()=>e.bubble,()=>{let t=e.bubble;t&&(n(t.bubbleX),i(t.bubbleY),o(t.bubbleW),d(t.bubbleH),p(t.sourceText),h(t.translatedText),v(t.isExcluded))})),(()=>{var s=Fo();return s.firstChild,J(s,P(L,{get when(){return e.bubble},get fallback(){return Io()},children:s=>(()=>{var u=Ro(),g=u.firstChild,y=g.firstChild;y.firstChild;var b=y.nextSibling,x=g.nextSibling,S=x.firstChild.nextSibling,C=x.nextSibling,w=C.firstChild.nextSibling,ee=C.nextSibling,T=ee.firstChild.nextSibling,E=ee.nextSibling,D=E.firstChild,O=E.nextSibling.firstChild,k=O.firstChild;return J(y,()=>s().bubbleIndex,null),J(g,P(L,{get when(){return s().isManuallyAdded},get children(){return Lo()}}),b),J(b,(()=>{var e=Y(()=>!!s().isManuallyAdded);return()=>e()?`N/A conf`:`${Math.round(s().confidence*100)}% conf`})()),J(S,P(Mo,{label:`X`,get value(){return t()},onInput:n,onChange:t=>e.onUpdate({bubbleX:t})}),null),J(S,P(Mo,{label:`Y`,get value(){return r()},onInput:i,onChange:t=>e.onUpdate({bubbleY:t})}),null),J(S,P(Mo,{label:`W`,get value(){return a()},onInput:o,onChange:t=>e.onUpdate({bubbleW:t})}),null),J(S,P(Mo,{label:`H`,get value(){return c()},onInput:d,onChange:t=>e.onUpdate({bubbleH:t})}),null),w.addEventListener(`blur`,t=>e.onUpdate({sourceText:t.currentTarget.value})),w.$$input=e=>p(e.currentTarget.value),T.addEventListener(`blur`,t=>e.onUpdate({translatedText:t.currentTarget.value})),T.$$input=e=>h(e.currentTarget.value),D.addEventListener(`change`,t=>{let n=t.currentTarget.checked;v(n),e.onUpdate({isExcluded:n})}),Ye(O,`click`,e.onDelete,!0),J(O,P(qi,{class:`h-3.5 w-3.5`}),k),l(()=>w.value=f()),l(()=>T.value=m()),l(()=>D.checked=_()),u})()}),null),s})()}var Po,Fo,Io,Lo,Ro,zo=t((()=>{X(),G(),la(),Po=K(`<label class="flex flex-col gap-0.5"><span class="text-[10px] text-slate-400"></span><input type=number step=0.1 class="rounded border border-slate-200 px-2 py-1 text-xs focus:border-violet-400 focus:outline-none">`),Fo=K(`<div class="flex h-full flex-col"><div class="shrink-0 border-b border-slate-100 px-3 py-2"><span class="text-xs font-semibold uppercase tracking-wide text-slate-500">Editor`),Io=K(`<div class="flex flex-1 items-center justify-center text-xs text-slate-400">Select a bubble to edit`),Lo=K(`<span class="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700">Manual`),Ro=K(`<div class="flex flex-1 flex-col gap-4 overflow-y-auto p-3"><div class="flex items-center gap-2"><span class="text-sm font-medium text-slate-700">Bubble #</span><span class="ml-auto text-[10px] text-slate-400"></span></div><div><p class="mb-1.5 text-xs font-medium text-slate-500">Position &amp; Size (px)</p><div class="grid grid-cols-2 gap-1.5"></div></div><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Source</span><textarea rows=3 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><label class="flex flex-col gap-1"><span class="text-xs font-medium text-slate-500">Translation</span><textarea rows=4 class="resize-y rounded border border-slate-200 px-2 py-1.5 text-xs focus:border-violet-400 focus:outline-none"></textarea></label><div class="flex items-center gap-2"><input id=exclude-check type=checkbox class="h-3.5 w-3.5 rounded accent-violet-600"><label for=exclude-check class="cursor-pointer text-xs text-slate-600">Exclude from render</label></div><div class="mt-auto border-t border-slate-100 pt-3"><button class="flex w-full items-center justify-center gap-1.5 rounded-lg bg-red-50 px-3 py-2 text-xs font-medium text-red-600 transition-colors hover:bg-red-100 active:bg-red-200">Delete bubble`),Ge([`input`,`click`])})),Bo=n({StudioPage:()=>Vo});function Vo(){let e=dn(),t=ln(),[n]=p(()=>e.id,Ma),[r,{refetch:i}]=p(()=>e.id,Pa),[a,o]=s(null),[c,u]=s(`result`),[d,f]=s(!1),[m,h]=s(!1),[g,_]=s(!1),[v,y]=s(!1),[b,x]=s(null),S=()=>r()??[],C=()=>{let e=a();return e===null?null:S().find(t=>t.bubbleIndex===e)??null};function w(e){o(e===a()?null:e)}async function ee(t,n,r){let a=S().find(e=>e.bubbleIndex===t);a&&(await Ia(e.id,t,{bubbleX:a.bubbleX+n,bubbleY:a.bubbleY+r,bubbleW:a.bubbleW,bubbleH:a.bubbleH}),i())}async function T(t,n,r,a,o){await Ia(e.id,t,{bubbleX:n,bubbleY:r,bubbleW:a,bubbleH:o}),i()}async function E(t,n,r,a){x(null);try{let s=await Fa(e.id,{x:t,y:n,w:r,h:a});await i(),o(s.bubbleIndex)}catch(e){x(e instanceof Error?e.message:`Failed to add bubble`)}}async function D(t){let n=C();if(n){x(null);try{await Ia(e.id,n.bubbleIndex,t),i()}catch(e){x(e instanceof Error?e.message:`Failed to update bubble`)}}}async function O(){let t=C();if(t){x(null);try{await La(e.id,t.bubbleIndex),o(null),i()}catch(e){x(e instanceof Error?e.message:`Failed to delete bubble`)}}}async function k(){for(let t=0;t<120;t++)if(await new Promise(e=>setTimeout(e,1500)),(await Ma(e.id)).status!==`processing`)return}async function A(){f(!0),x(null);try{await Ra(e.id),await k(),await i()}catch(e){x(e instanceof Error?e.message:`Re-detect failed`)}finally{f(!1)}}async function j(){h(!0),x(null);try{await za(e.id),await k(),await i()}catch(e){x(e instanceof Error?e.message:`Re-translate failed`)}finally{h(!1)}}async function te(){_(!0),x(null);try{await Ba(e.id),await k(),await i()}catch(e){x(e instanceof Error?e.message:`Re-render failed`)}finally{_(!1)}}let M=()=>({bubbles:S(),selectedIndex:a(),drawMode:v(),onSelect:w,onMove:ee,onResize:T,onDraw:async(e,t,n,r)=>{y(!1),await E(e,t,n,r)}});return(()=>{var r=Wo(),i=r.firstChild,o=i.firstChild,s=o.nextSibling,f=s.nextSibling.nextSibling,p=f.firstChild,h=f.nextSibling,_=h.firstChild,v=h.nextSibling,ee=v.firstChild;return o.$$click=()=>t(`/jobs`),J(o,P(Zn,{class:`h-4 w-4`})),J(i,P(L,{get when(){return n()},get fallback(){return Go()},children:e=>[(()=>{var t=Ko();return J(t,()=>e().title),t})(),P(eo,{get status(){return e().status}})]}),s),J(s,()=>[`original`,`result`,`sidebyside`].map(e=>(()=>{var t=qo();return t.$$click=()=>u(e),J(t,e===`original`?`Original`:e===`result`?`Result`:`Side by side`),l(()=>Je(t,`px-2.5 py-1.5 font-medium transition-colors ${c()===e?`bg-violet-600 text-white`:`bg-white text-slate-600 hover:bg-slate-50`}`)),t})())),f.$$click=A,J(f,P(L,{get when(){return d()},get fallback(){return P(Fi,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),p),h.$$click=j,J(h,P(L,{get when(){return m()},get fallback(){return P(Ui,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),_),v.$$click=te,J(v,P(L,{get when(){return g()},get fallback(){return P(ji,{class:`h-3.5 w-3.5`})},get children(){return P(ji,{class:`h-3.5 w-3.5 animate-spin`})}}),ee),J(r,P(L,{get when(){return b()},children:e=>(()=>{var t=Jo(),n=t.firstChild,r=n.nextSibling;return J(n,e),r.$$click=()=>x(null),t})()}),null),J(r,P(L,{get when(){return n.loading},get children(){return Ho()}}),null),J(r,P(L,{get when(){return n.error},get children(){var e=Uo();return e.firstChild,J(e,()=>String(n.error),null),e}}),null),J(r,P(L,{get when(){return Y(()=>!n.loading&&!n.error)()&&n()},children:t=>(()=>{var n=Xo(),r=n.firstChild,i=r.nextSibling,o=i.nextSibling;return J(r,P(To,{get bubbles(){return S()},get selectedIndex(){return a()},onSelect:w,onAddBubble:()=>y(!0)})),J(i,P(ve,{get children(){return[P(ye,{get when(){return c()===`original`},get children(){return P(ho,F(M,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}}),P(ye,{get when(){return c()===`result`},get children(){return P(L,{get when(){return t().resultImagePath},get fallback(){return(()=>{var e=Zo(),t=e.firstChild;return J(e,P($r,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){return P(ho,F(M,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}})}}),P(ye,{get when(){return c()===`sidebyside`},get children(){var n=Yo(),r=n.firstChild,i=r.nextSibling;return J(r,P(ho,F(M,{get imageUrl(){return Xa(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))),J(i,P(L,{get when(){return t().resultImagePath},get fallback(){return(()=>{var e=Qo(),t=e.firstChild;return J(e,P($r,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){return P(ho,F(M,{get imageUrl(){return Za(e.id)},get imageWidth(){return t().originalWidth},get imageHeight(){return t().originalHeight}}))}})),n}})]}})),J(o,P(No,{get bubble(){return C()},onUpdate:D,onDelete:O})),n})()}),null),l(e=>{var t=d(),n=m(),r=g();return t!==e.e&&(f.disabled=e.e=t),n!==e.t&&(h.disabled=e.t=n),r!==e.a&&(v.disabled=e.a=r),e},{e:void 0,t:void 0,a:void 0}),r})()}var Ho,Uo,Wo,Go,Ko,qo,Jo,Yo,Xo,Zo,Qo,$o=t((()=>{X(),G(),Rn(),la(),Qa(),wo(),jo(),zo(),po(),Ho=K(`<div class="flex flex-1 items-center justify-center"><p class="text-sm text-slate-400">Loading job…`),Uo=K(`<div class="m-6 rounded-2xl bg-red-50 p-6 text-sm text-red-600 ring-1 ring-red-200">Failed to load job: `),Wo=K(`<div class="flex h-screen flex-col bg-slate-50"><header class="flex shrink-0 items-center gap-2 border-b border-slate-200 bg-white px-3 py-2 shadow-sm"><button class="flex items-center gap-1 rounded p-1 text-slate-500 hover:bg-slate-100 transition-colors"title="Back to jobs"aria-label="Back to jobs"></button><div class="ml-4 flex overflow-hidden rounded-lg border border-slate-200 text-xs"></div><div class=flex-1></div><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-detect bubbles"aria-label="Re-detect bubbles">Re-detect</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title=Re-translate aria-label=Re-translate>Re-translate</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 transition-colors hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"title="Re-render image"aria-label="Re-render image">Re-render`),Go=K(`<div class="h-4 w-40 animate-pulse rounded bg-slate-200">`),Ko=K(`<h1 class="max-w-xs truncate text-sm font-semibold text-slate-800">`),qo=K(`<button>`),Jo=K(`<div class="flex items-center gap-2 bg-red-50 px-4 py-2 text-sm text-red-700 ring-1 ring-inset ring-red-200"><span class=flex-1></span><button class="shrink-0 rounded p-0.5 hover:bg-red-100"aria-label="Dismiss error">✕`),Yo=K(`<div class="flex h-full w-full"><div class="flex-1 overflow-hidden border-r border-slate-700"></div><div class="flex-1 overflow-hidden">`),Xo=K(`<div class="flex flex-1 overflow-hidden"><aside class="flex w-52 shrink-0 flex-col border-r border-slate-200 bg-white"></aside><main class="relative flex flex-1 overflow-hidden"></main><aside class="flex w-64 shrink-0 flex-col border-l border-slate-200 bg-white">`),Zo=K(`<div class="flex flex-1 flex-col items-center justify-center gap-3 text-slate-400"><p class=text-sm>No result image yet</p><p class=text-xs>Run Re-render to generate the translated image.`),Qo=K(`<div class="flex h-full flex-col items-center justify-center gap-3 text-slate-400"><p class=text-sm>No result image yet</p><p class=text-xs>Run Re-render to generate the translated image.`),Ge([`click`])}));function es(e){return u(()=>{if(!e.open){document.body.style.overflow=``;return}document.body.style.overflow=`hidden`;let t=t=>{t.key===`Escape`&&e.onClose()};return document.addEventListener(`keydown`,t),()=>{document.body.style.overflow=``,document.removeEventListener(`keydown`,t)}}),P(L,{get when(){return e.open},get children(){var t=ts(),n=t.firstChild,r=n.firstChild.firstChild,i=r.nextSibling;return t.$$click=t=>{t.target===t.currentTarget&&e.onClose()},J(r,()=>e.title),Ye(i,`click`,e.onClose,!0),J(i,P(Zi,{class:`h-4 w-4`})),J(n,()=>e.children,null),t}})}var ts,ns=t((()=>{X(),G(),la(),ts=K(`<div role=dialog aria-modal=true aria-labelledby=modal-title class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"><div class="w-full max-w-md rounded-2xl bg-white p-6 shadow-xl"><div class="mb-4 flex items-center justify-between"><h2 id=modal-title class="text-base font-semibold text-slate-800"></h2><button class="rounded-lg p-1 text-slate-400 hover:bg-slate-100 hover:text-slate-600"aria-label=Close>`),Ge([`click`])}));function rs(e){return P(es,{get open(){return e.open},get title(){return e.title},get onClose(){return e.onCancel},get children(){return[(()=>{var t=is();return J(t,()=>e.message),t})(),(()=>{var t=as(),n=t.firstChild,r=n.nextSibling;return Ye(n,`click`,e.onCancel,!0),Ye(r,`click`,e.onConfirm,!0),J(r,(()=>{var t=Y(()=>!!e.loading);return()=>t()?`Deleting…`:e.confirmLabel??`Delete`})()),l(t=>{var i=e.loading,a=e.confirmClass??`rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:opacity-50`,o=e.loading;return i!==t.e&&(n.disabled=t.e=i),a!==t.t&&Je(r,t.t=a),o!==t.a&&(r.disabled=t.a=o),t},{e:void 0,t:void 0,a:void 0}),t})()]}})}var is,as,os=t((()=>{X(),ns(),is=K(`<p class="mb-6 text-sm text-slate-600">`),as=K(`<div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 disabled:opacity-50">Cancel</button><button>`),Ge([`click`])})),ss=n({LibraryPage:()=>cs});function cs(){let e=ln(),[t,{refetch:n}]=p(Va),[r,{refetch:i}]=p(()=>Ga()),a=()=>(r()??[]).filter(e=>!e.volumeId),[o,c]=s(null),[u,d]=s(``),[f,m]=s(``);function h(){d(``),m(``),c({mode:`create`})}function g(e){d(e.title),m(e.synopsis??``),c({mode:`edit`,vol:e})}let[_,v]=s(null),[y,b]=s(``),[x,S]=s(``),[C,w]=s(void 0);function ee(){b(``),S(``),w(void 0),v({mode:`create`})}function T(e){b(e.title),S(e.chapterNumber),w(e.volumeId),v({mode:`edit`,ch:e})}let[E,D]=s(null),[O,k]=s(null),[A,j]=s(!1),[te,M]=s(null);async function ne(){j(!0),M(null);try{let e=o();if(!e)return;e.mode===`create`?await Ha({title:u(),synopsis:f()||void 0}):await Ua(e.vol.id,{title:u(),synopsis:f()||void 0}),c(null),n()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function re(){M(null);try{let e=E();if(!e)return;await Wa(e.id),D(null),n()}catch(e){M(e instanceof Error?e.message:String(e)),D(null)}}async function ie(){j(!0),M(null);try{let e=_();if(!e)return;e.mode===`create`?await Ka({title:y(),chapterNumber:x(),volumeId:C()}):await qa(e.ch.id,{title:y(),chapterNumber:x(),volumeId:C()??null}),v(null),i()}catch(e){M(e instanceof Error?e.message:String(e))}finally{j(!1)}}async function N(){M(null);try{let e=O();if(!e)return;await Ja(e.id),k(null),i()}catch(e){M(e instanceof Error?e.message:String(e)),k(null)}}return(()=>{var n=gs(),i=n.firstChild,s=i.firstChild,p=s.nextSibling.nextSibling.firstChild,j=p.firstChild,ae=p.nextSibling,oe=ae.firstChild,se=i.nextSibling;se.firstChild;var ce=se.nextSibling;return ce.firstChild,J(n,P(L,{get when(){return te()},get children(){var e=ls(),t=e.firstChild,n=t.nextSibling;return J(t,te),n.$$click=()=>M(null),e}}),i),J(s,P(tr,{class:`h-5 w-5 text-violet-600`})),p.$$click=h,J(p,P(Di,{class:`h-3.5 w-3.5`}),j),ae.$$click=ee,J(ae,P(Di,{class:`h-3.5 w-3.5`}),oe),J(se,P(L,{get when(){return t.loading},get children(){var e=us();return J(e,()=>Array.from({length:4}).map(()=>_s())),e}}),null),J(se,P(L,{get when(){return t.error},get children(){return ds()}}),null),J(se,P(L,{get when(){return Y(()=>!t.loading)()&&!t.error},get children(){return P(L,{get when(){return(t()??[]).length>0},get fallback(){return(()=>{var e=vs(),t=e.firstChild;return J(e,P(Gr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var n=us();return J(n,P(I,{get each(){return t()},children:t=>(()=>{var n=ys(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling,s=o.firstChild,c=s.nextSibling.firstChild,l=c.nextSibling,u=l.firstChild;return i.$$click=e=>{e.stopPropagation(),g(t)},J(i,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),a.$$click=e=>{e.stopPropagation(),D(t)},J(a,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),o.$$click=()=>e(`/library/${t.id}`),J(s,P(tr,{class:`h-6 w-6 text-violet-500`})),J(c,()=>t.title),J(l,()=>t.chapterCount??0,u),J(o,P(lr,{class:`ml-auto h-4 w-4 shrink-0 text-slate-300 transition group-hover:translate-x-0.5 group-hover:text-slate-500`}),null),n})()})),n}})}}),null),J(ce,P(L,{get when(){return r.loading},get children(){var e=fs();return J(e,()=>Array.from({length:3}).map(()=>bs())),e}}),null),J(ce,P(L,{get when(){return!r.loading},get children(){return P(L,{get when(){return a().length>0},get fallback(){return xs()},get children(){var t=ps();return J(t,P(I,{get each(){return a()},children:t=>(()=>{var n=Ss(),r=n.firstChild,i=r.firstChild;i.firstChild;var a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=r.nextSibling.firstChild,l=c.nextSibling;return r.$$click=()=>e(`/library/chapters/${t.id}`),J(i,()=>t.chapterNumber,null),J(a,()=>t.title),J(o,()=>t.pageCount??0,s),J(r,P(lr,{class:`h-4 w-4 text-slate-300`}),null),c.$$click=()=>T(t),J(c,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),l.$$click=()=>k(t),J(l,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),n})()})),t}})}}),null),J(n,P(es,{get open(){return o()!==null},get title(){return o()?.mode===`create`?`New Volume`:`Edit Volume`},onClose:()=>c(null),get children(){var e=ms(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>d(e.currentTarget.value),i.$$input=e=>m(e.currentTarget.value),a.$$click=()=>c(null),o.$$click=ne,J(o,()=>A()?`Saving…`:`Save`),l(()=>o.disabled=A()||!u().trim()),l(()=>n.value=u()),l(()=>i.value=f()),e}}),null),J(n,P(es,{get open(){return _()!==null},get title(){return _()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>v(null),get children(){var e=hs(),n=e.firstChild,r=n.firstChild.nextSibling,i=n.nextSibling,a=i.firstChild.nextSibling,o=i.nextSibling,s=o.firstChild.nextSibling;s.firstChild;var c=o.nextSibling.firstChild,u=c.nextSibling;return r.$$input=e=>b(e.currentTarget.value),a.$$input=e=>S(e.currentTarget.value),s.addEventListener(`change`,e=>{let t=e.currentTarget.value;w(t?Number(t):void 0)}),J(s,P(I,{get each(){return t()??[]},children:e=>(()=>{var t=Cs();return J(t,()=>e.title),l(()=>t.value=e.id),t})()}),null),c.$$click=()=>v(null),u.$$click=ie,J(u,()=>A()?`Saving…`:`Save`),l(()=>u.disabled=A()||!y().trim()||!x().trim()),l(()=>r.value=y()),l(()=>a.value=x()),l(()=>s.value=C()??``),e}}),null),J(n,P(rs,{get open(){return E()!==null},title:`Delete Volume`,get message(){return`Delete "${E()?.title}"? Chapters inside will be ungrouped but not deleted.`},onConfirm:re,onCancel:()=>D(null)}),null),J(n,P(rs,{get open(){return O()!==null},title:`Delete Chapter`,get message(){return`Delete "${O()?.title}"? This cannot be undone.`},onConfirm:N,onCancel:()=>k(null)}),null),n})()}var ls,us,ds,fs,ps,ms,hs,gs,_s,vs,ys,bs,xs,Ss,Cs,ws=t((()=>{X(),G(),Rn(),la(),Qa(),ns(),os(),ls=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),us=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">`),ds=K(`<p class="text-sm text-red-500">Failed to load volumes.`),fs=K(`<div class=space-y-2>`),ps=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),ms=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Volume title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3 placeholder="Brief description…"></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),hs=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Volume (optional)</label><select class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"><option value>No volume / Standalone</option></select></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),gs=K(`<div class="min-h-screen px-6 py-8"><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><h1 class="text-xl font-semibold text-slate-800">Library</h1><div class="ml-auto flex gap-2"><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> New Volume</button><button class="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 hover:bg-slate-50"> New Chapter</button></div></div><section class=mb-10><h2 class="mb-3 text-sm font-semibold text-slate-600">Volumes</h2></section><section><h2 class="mb-3 text-sm font-semibold text-slate-600">Standalone Chapters`),_s=K(`<div class="h-32 animate-pulse rounded-2xl bg-slate-200">`),vs=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-16 text-slate-400"><p class=text-sm>No volumes yet.`),ys=K(`<div class="group relative flex flex-col gap-2 rounded-2xl bg-white p-4 text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-slate-50"title="Edit volume"></button><button class="rounded-lg bg-white p-1.5 shadow-sm ring-1 ring-slate-200 hover:bg-red-50"title="Delete volume"></button></div><button class="flex flex-col gap-2 text-left"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-violet-50"></div><div class="min-w-0 pr-10"><p class="truncate text-sm font-semibold text-slate-800"></p><p class="text-xs text-slate-500"> chapters`),bs=K(`<div class="h-12 animate-pulse rounded-xl bg-slate-200">`),xs=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-12 text-slate-400"><p class=text-sm>No standalone chapters.`),Ss=K(`<li class="group flex items-center"><button class="flex flex-1 items-center gap-4 px-5 py-3.5 text-left transition hover:bg-slate-50"><span class="w-14 shrink-0 text-right text-xs font-mono text-slate-400">#</span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-3 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),Cs=K(`<option>`),Ge([`click`,`input`])})),Ts=n({VolumePage:()=>Es});function Es(){let e=dn(),t=ln(),n=()=>Number(e.volumeId),[r,{refetch:i}]=p(Va),a=()=>r()?.find(e=>e.id===n()),[o,{refetch:c}]=p(n,e=>Ga({volumeId:e})),[u,d]=s(!1),[f,m]=s(``),[h,g]=s(``),[_,v]=s(!1),[y,b]=s(null);function x(){let e=a();e&&(m(e.title),g(e.synopsis??``),d(!0))}async function S(){v(!0),b(null);try{await Ua(n(),{title:f(),synopsis:h()||void 0}),d(!1),i()}catch(e){b(e instanceof Error?e.message:String(e))}finally{v(!1)}}let[C,w]=s(!1);async function ee(){b(null);try{await Wa(n()),w(!1),t(`/library`)}catch(e){b(e instanceof Error?e.message:String(e)),w(!1)}}let[T,E]=s(null),[D,O]=s(``),[k,A]=s(``),[j,te]=s(!1);function M(){O(``),A(``),E({mode:`create`})}function ne(e){O(e.title),A(e.chapterNumber),E({mode:`edit`,ch:e})}async function re(){te(!0),b(null);try{let e=T();if(!e)return;e.mode===`create`?await Ka({title:D(),chapterNumber:k(),volumeId:n()}):await qa(e.ch.id,{title:D(),chapterNumber:k()}),E(null),c()}catch(e){b(e instanceof Error?e.message:String(e))}finally{te(!1)}}let[ie,N]=s(null);async function ae(){b(null);try{let e=ie();if(!e)return;await Ja(e.id),N(null),c()}catch(e){b(e instanceof Error?e.message:String(e)),N(null)}}async function oe(e,t){b(null);try{let n=o()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];if(!i)return;await Promise.all([qa(e.id,{sortOrder:i.sortOrder}),qa(i.id,{sortOrder:e.sortOrder})]),c()}catch(e){b(e instanceof Error?e.message:String(e))}}return(()=>{var e=Ns(),n=e.firstChild,r=n.firstChild,i=n.nextSibling.firstChild,s=i.nextSibling,c=s.nextSibling.firstChild,p=c.nextSibling,v=p.nextSibling,te=v.firstChild;return J(e,P(L,{get when(){return y()},get children(){var e=Ds(),t=e.firstChild,n=t.nextSibling;return J(t,y),n.$$click=()=>b(null),e}}),n),n.$$click=()=>t(`/library`),J(n,P(Zn,{class:`h-4 w-4`}),r),J(i,P(tr,{class:`h-5 w-5 text-violet-600`})),J(s,P(L,{get when(){return a()},get fallback(){return Ps()},children:e=>[(()=>{var t=Fs();return J(t,()=>e().title),t})(),P(L,{get when(){return e().synopsis},get children(){var t=Is();return J(t,()=>e().synopsis),t}})]})),c.$$click=x,J(c,P(Ci,{class:`h-4 w-4`})),p.$$click=()=>w(!0),J(p,P(qi,{class:`h-4 w-4`})),v.$$click=M,J(v,P(Di,{class:`h-3.5 w-3.5`}),te),J(e,P(L,{get when(){return o.loading},get children(){var e=Os();return J(e,()=>Array.from({length:4}).map(()=>Ls())),e}}),null),J(e,P(L,{get when(){return o.error},get children(){return ks()}}),null),J(e,P(L,{get when(){return Y(()=>!o.loading)()&&!o.error},get children(){return P(L,{get when(){return(o()??[]).length>0},get fallback(){return(()=>{var e=Rs(),t=e.firstChild;return J(e,P(Vr,{class:`h-8 w-8 opacity-40`}),t),e})()},get children(){var e=As();return J(e,P(I,{get each(){return o()},children:(e,n)=>{let r=()=>o()??[],i=()=>n()===0,a=()=>n()===r().length-1;return(()=>{var n=zs(),r=n.firstChild,o=r.firstChild,s=o.nextSibling,c=r.nextSibling,u=c.firstChild,d=u.nextSibling,f=d.nextSibling,p=f.firstChild,m=c.nextSibling.firstChild,h=m.nextSibling;return o.$$click=()=>oe(e,`up`),J(o,P(pr,{class:`h-3.5 w-3.5`})),s.$$click=()=>oe(e,`down`),J(s,P(ar,{class:`h-3.5 w-3.5`})),c.$$click=()=>t(`/library/chapters/${e.id}`),J(u,()=>e.chapterNumber),J(d,()=>e.title),J(f,()=>e.pageCount??0,p),J(c,P(lr,{class:`h-4 w-4 text-slate-300`}),null),m.$$click=()=>ne(e),J(m,P(Ci,{class:`h-3.5 w-3.5 text-slate-500`})),h.$$click=()=>N(e),J(h,P(qi,{class:`h-3.5 w-3.5 text-red-400`})),l(e=>{var t=i(),n=a();return t!==e.e&&(o.disabled=e.e=t),n!==e.t&&(s.disabled=e.t=n),e},{e:void 0,t:void 0}),n})()}})),e}})}}),null),J(e,P(es,{get open(){return u()},title:`Edit Volume`,onClose:()=>d(!1),get children(){var e=js(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>m(e.currentTarget.value),i.$$input=e=>g(e.currentTarget.value),a.$$click=()=>d(!1),o.$$click=S,J(o,()=>_()?`Saving…`:`Save`),l(()=>o.disabled=_()||!f().trim()),l(()=>n.value=f()),l(()=>i.value=h()),e}}),null),J(e,P(es,{get open(){return T()!==null},get title(){return T()?.mode===`create`?`New Chapter`:`Edit Chapter`},onClose:()=>E(null),get children(){var e=Ms(),t=e.firstChild,n=t.firstChild.nextSibling,r=t.nextSibling,i=r.firstChild.nextSibling,a=r.nextSibling.firstChild,o=a.nextSibling;return n.$$input=e=>O(e.currentTarget.value),i.$$input=e=>A(e.currentTarget.value),a.$$click=()=>E(null),o.$$click=re,J(o,()=>j()?`Saving…`:`Save`),l(()=>o.disabled=j()||!D().trim()||!k().trim()),l(()=>n.value=D()),l(()=>i.value=k()),e}}),null),J(e,P(rs,{get open(){return C()},title:`Delete Volume`,get message(){return`Delete "${a()?.title}"? This will not delete the chapters — they will just be ungrouped.`},onConfirm:ee,onCancel:()=>w(!1)}),null),J(e,P(rs,{get open(){return ie()!==null},title:`Delete Chapter`,get message(){return`Delete "${ie()?.title}"? This cannot be undone.`},onConfirm:ae,onCancel:()=>N(null)}),null),e})()}var Ds,Os,ks,As,js,Ms,Ns,Ps,Fs,Is,Ls,Rs,zs,Bs=t((()=>{X(),G(),Rn(),la(),Qa(),ns(),os(),Ds=K(`<div class="mb-4 flex items-center justify-between rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700 ring-1 ring-red-200"><span></span><button class="ml-4 text-red-400 hover:text-red-600">✕`),Os=K(`<div class=space-y-2>`),ks=K(`<p class="text-sm text-red-500">Failed to load chapters.`),As=K(`<ul class="divide-y divide-slate-100 rounded-2xl bg-white shadow-sm ring-1 ring-slate-200">`),js=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Synopsis (optional)</label><textarea class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"rows=3></textarea></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Ms=K(`<div class="flex flex-col gap-4"><div><label class="block text-xs font-medium text-slate-600 mb-1">Title</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="Chapter title"></div><div><label class="block text-xs font-medium text-slate-600 mb-1">Chapter Number</label><input class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"placeholder="e.g. 1 or 1.5"></div><div class="flex justify-end gap-2"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Ns=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"> Library</button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><div class="flex items-center gap-2"><button class="rounded-lg p-1.5 text-slate-400 hover:bg-slate-100 hover:text-slate-600"title="Edit volume"></button><button class="rounded-lg p-1.5 text-slate-400 hover:bg-red-50 hover:text-red-500"title="Delete volume"></button><button class="flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add Chapter`),Ps=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),Fs=K(`<h1 class="text-xl font-semibold text-slate-800">`),Is=K(`<p class="text-sm text-slate-500">`),Ls=K(`<div class="h-14 animate-pulse rounded-xl bg-slate-200">`),Rs=K(`<div class="flex flex-col items-center gap-2 rounded-2xl border border-dashed border-slate-300 py-20 text-slate-400"><p class=text-sm>No chapters yet. Add the first one.`),zs=K(`<li class="group flex items-center"><div class="flex flex-col items-center px-2"><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button><button class="rounded p-0.5 text-slate-300 hover:bg-slate-100 hover:text-slate-500 disabled:cursor-not-allowed disabled:opacity-30"></button></div><button class="flex flex-1 items-center gap-4 py-4 pr-4 text-left transition hover:bg-slate-50"><span class="w-16 shrink-0 rounded-lg bg-slate-100 px-2 py-1 text-center text-xs font-mono text-slate-600"></span><span class="flex-1 text-sm font-medium text-slate-800"></span><span class="text-xs text-slate-400"> pages</span></button><div class="flex shrink-0 gap-1 px-2 opacity-0 transition-opacity group-hover:opacity-100"><button class="rounded-lg p-1.5 hover:bg-slate-100"title="Edit chapter"></button><button class="rounded-lg p-1.5 hover:bg-red-50"title="Delete chapter">`),Ge([`click`,`input`])})),Vs=n({ChapterPage:()=>Ws});function Hs(e){switch(e.status){case`done`:return P(_r,{class:`h-4 w-4 text-green-500`});case`processing`:return P(kr,{class:`h-4 w-4 text-yellow-500`});case`error`:return P(Tr,{class:`h-4 w-4 text-red-500`});default:return P(kr,{class:`h-4 w-4 text-slate-400`})}}function Us(e){let t=()=>e.job.resultImagePath?Za(e.job.id):Xa(e.job.id);return(()=>{var n=Gs(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling,s=o.firstChild,c=s.nextSibling,u=o.nextSibling,d=r.nextSibling.firstChild;return r.$$keydown=t=>t.key===`Enter`&&e.onClick(),Ye(r,`click`,e.onClick,!0),J(a,P(Hs,{get status(){return e.job.status}})),s.$$click=t=>{t.stopPropagation(),e.onMove(`up`)},J(s,P(pr,{class:`h-3.5 w-3.5 text-slate-600`})),c.$$click=t=>{t.stopPropagation(),e.onMove(`down`)},J(c,P(ar,{class:`h-3.5 w-3.5 text-slate-600`})),u.$$click=t=>{t.stopPropagation(),e.onUnassign()},J(u,P(Zi,{class:`h-3.5 w-3.5`})),J(d,()=>e.job.title),l(n=>{var a=`Open ${e.job.title} in studio`,o=t(),l=e.job.title,u=e.isFirst,d=e.isLast;return a!==n.e&&q(r,`aria-label`,n.e=a),o!==n.t&&q(i,`src`,n.t=o),l!==n.a&&q(i,`alt`,n.a=l),u!==n.o&&(s.disabled=n.o=u),d!==n.i&&(c.disabled=n.i=d),n},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0}),n})()}function Ws(){let e=dn(),t=ln(),n=()=>Number(e.chapterId),[r]=p(()=>Ga()),i=()=>r()?.find(e=>e.id===n()),[a,{refetch:o}]=p(n,Ya),[c,u]=s(!1),[d,f]=s([]),[m,h]=s(new Set),[g,_]=s(!1),[v,y]=s(!1);async function b(){_(!0),h(new Set),u(!0);try{let e=[],t=1;for(;;){let n=await ja({page:t,pageSize:200});if(e.push(...n.items.filter(e=>!e.chapterId)),n.items.length<200)break;t++}f(e)}finally{_(!1)}}function x(e){h(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}async function S(){y(!0);try{let e=[...m()],t=a()?.length??0;await Promise.all(e.map((e,r)=>Na(e,{chapterId:n(),pageOrder:t+r}))),u(!1),h(new Set),o()}finally{y(!1)}}async function C(e,t){let n=a()??[],r=n.findIndex(t=>t.id===e.id),i=t===`up`?n[r-1]:n[r+1];i&&(await Promise.all([Na(e.id,{pageOrder:i.pageOrder}),Na(i.id,{pageOrder:e.pageOrder})]),o())}async function w(e){await Na(e,{chapterId:null}),o()}return(()=>{var e=Qs(),n=e.firstChild,r=n.nextSibling.firstChild,o=r.nextSibling,s=o.nextSibling,f=s.firstChild;return n.$$click=()=>{let e=i();e?.volumeId?t(`/library/${e.volumeId}`):t(`/library`)},J(n,P(Zn,{class:`h-4 w-4`}),null),J(n,P(L,{get when(){return i()?.volumeId},fallback:`Library`,children:`Volume`}),null),J(r,P(ri,{class:`h-5 w-5 text-violet-600`})),J(o,P(L,{get when(){return i()},get fallback(){return $s()},children:e=>(()=>{var t=ec(),n=t.firstChild.nextSibling;return n.nextSibling,J(t,()=>e().chapterNumber,n),J(t,()=>e().title,null),t})()})),s.$$click=b,J(s,P(Lr,{class:`h-3.5 w-3.5`}),f),J(e,P(L,{get when(){return a.loading},get children(){var e=Ks();return J(e,()=>Array.from({length:8}).map(()=>tc())),e}}),null),J(e,P(L,{get when(){return a.error},get children(){return qs()}}),null),J(e,P(L,{get when(){return Y(()=>!a.loading)()&&!a.error},get children(){return P(L,{get when(){return(a()??[]).length>0},get fallback(){return(()=>{var e=nc(),t=e.firstChild;return J(e,P(ri,{class:`h-10 w-10 opacity-40`}),t),e})()},get children(){var e=Ks();return J(e,P(I,{get each(){return a()},children:(e,n)=>{let r=()=>a()??[];return P(Us,{job:e,get isFirst(){return n()===0},get isLast(){return n()===r().length-1},onMove:t=>C(e,t),onUnassign:()=>w(e.id),onClick:()=>t(`/jobs/${e.id}`)})}})),e}})}}),null),J(e,P(es,{get open(){return c()},title:`Add Pages to Chapter`,onClose:()=>u(!1),get children(){var e=Zs(),t=e.firstChild.nextSibling,n=t.firstChild,r=n.nextSibling;return J(e,P(L,{get when(){return g()},get children(){var e=Js();return J(e,()=>Array.from({length:4}).map(()=>rc())),e}}),t),J(e,P(L,{get when(){return Y(()=>!g())()&&d().length===0},get children(){return Ys()}}),t),J(e,P(L,{get when(){return Y(()=>!g())()&&d().length>0},get children(){var e=Xs();return J(e,P(I,{get each(){return d()},children:e=>{let t=()=>m().has(e.id);return(()=>{var n=ic(),r=n.firstChild,i=r.firstChild,a=i.nextSibling,o=a.nextSibling.firstChild,s=o.nextSibling;return i.addEventListener(`change`,()=>x(e.id)),J(o,()=>e.title),J(s,()=>new Date(e.createdAt).toLocaleDateString()),J(r,P(Hs,{get status(){return e.status}}),null),l(t=>{var n=Xa(e.id),r=e.title;return n!==t.e&&q(a,`src`,t.e=n),r!==t.t&&q(a,`alt`,t.t=r),t},{e:void 0,t:void 0}),l(()=>i.checked=t()),n})()}})),e}}),t),n.$$click=()=>u(!1),r.$$click=S,J(r,(()=>{var e=Y(()=>!!v());return()=>e()?`Assigning…`:`Assign ${m().size>0?m().size:``} selected`})()),l(()=>r.disabled=v()||m().size===0),e}}),null),e})()}var Gs,Ks,qs,Js,Ys,Xs,Zs,Qs,$s,ec,tc,nc,rc,ic,ac=t((()=>{X(),G(),Rn(),la(),Qa(),ns(),Gs=K(`<div class="group relative flex flex-col overflow-hidden rounded-2xl bg-white text-left shadow-sm ring-1 ring-slate-200 transition hover:shadow-md hover:ring-slate-300"><div class="relative aspect-3/4 w-full cursor-pointer overflow-hidden bg-slate-100"role=button tabindex=0><img class="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"loading=lazy><span class="absolute left-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow"></span><div class="absolute right-2 top-2 flex flex-col gap-1 opacity-0 transition-opacity group-hover:opacity-100"><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move up"></button><button class="flex h-6 w-6 items-center justify-center rounded-full bg-white/90 shadow hover:bg-white disabled:cursor-not-allowed disabled:opacity-30"title="Move down"></button></div><button class="absolute bottom-2 right-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500/90 text-white shadow opacity-0 transition-opacity group-hover:opacity-100 hover:bg-red-600"title="Remove from chapter"></button></div><div class=p-3><p class="truncate text-xs font-medium text-slate-700">`,!0,!1,!1),Ks=K(`<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">`),qs=K(`<p class="text-sm text-red-500">Failed to load pages.`),Js=K(`<div class=space-y-2>`),Ys=K(`<p class="py-6 text-center text-sm text-slate-400">No unassigned pages found.`),Xs=K(`<ul class="max-h-80 overflow-y-auto divide-y divide-slate-100 rounded-lg border border-slate-200">`),Zs=K(`<div class="flex flex-col gap-3"><p class="text-xs text-slate-500">Select unassigned jobs to add to this chapter.</p><div class="flex justify-end gap-2 pt-1"><button class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Cancel</button><button class="rounded-lg bg-violet-600 px-4 py-2 text-sm font-medium text-white hover:bg-violet-700 disabled:opacity-50">`),Qs=K(`<div class="min-h-screen px-6 py-8"><button class="mb-5 flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800"></button><div class="mb-6 flex items-center gap-3"><div class="rounded-xl bg-white p-2 shadow-sm ring-1 ring-slate-200"></div><div class="flex-1 min-w-0"></div><button class="ml-auto flex items-center gap-1.5 rounded-lg bg-violet-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-violet-700"> Add pages`),$s=K(`<div class="h-6 w-48 animate-pulse rounded bg-slate-200">`),ec=K(`<h1 class="text-xl font-semibold text-slate-800">Ch. <!> — `),tc=K(`<div class="aspect-3/4 animate-pulse rounded-2xl bg-slate-200">`),nc=K(`<div class="flex flex-col items-center gap-3 py-24 text-slate-400"><p class=text-sm>No pages in this chapter yet.`),rc=K(`<div class="h-14 animate-pulse rounded-lg bg-slate-200">`),ic=K(`<li><label class="flex cursor-pointer items-center gap-3 px-3 py-2.5 hover:bg-slate-50"><input type=checkbox class="h-4 w-4 accent-violet-600"><img class="h-10 w-8 rounded object-cover bg-slate-100"loading=lazy><div class="min-w-0 flex-1"><p class="truncate text-sm font-medium text-slate-800"></p><p class="text-xs text-slate-400">`,!0,!1,!1),Ge([`click`,`keydown`])}));X(),G(),Rn();var oc=_e(()=>Promise.resolve().then(()=>(po(),$a)).then(e=>({default:e.JobsListPage}))),sc=_e(()=>Promise.resolve().then(()=>($o(),Bo)).then(e=>({default:e.StudioPage}))),cc=_e(()=>Promise.resolve().then(()=>(ws(),ss)).then(e=>({default:e.LibraryPage}))),lc=_e(()=>Promise.resolve().then(()=>(Bs(),Ts)).then(e=>({default:e.VolumePage}))),uc=_e(()=>Promise.resolve().then(()=>(ac(),Vs)).then(e=>({default:e.ChapterPage})));function dc(){return P(jn,{get children(){return P(yn,{path:`/`,component:e=>P(ma,{get children(){return e.children}}),get children(){return[P(yn,{path:`/`,component:Ea}),P(yn,{path:`/jobs`,component:oc}),P(yn,{path:`/jobs/:id`,component:sc}),P(yn,{path:`/library`,component:cc}),P(yn,{path:`/library/:volumeId`,component:lc}),P(yn,{path:`/library/chapters/:chapterId`,component:uc})]}})}})}var fc=new Map;window.AppBridge={mount(e,t={}){if(fc.has(e))return;let n=We(()=>P(dc,{}),e);fc.set(e,n)},unmount(e){fc.get(e)?.(),fc.delete(e)}}})();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle ChapterPage action failures visibly.

ChapterPage’s load, assign, reorder, and unassign handlers allow rejected API promises to escape without updating the existing error state. A failed request therefore produces an unhandled rejection and leaves the user with no explanation or recovery path; catch each operation and surface the error before resetting loading state.

🧰 Tools
🪛 Biome (2.5.3)

[error] 1-1: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🪛 OpenGrep (1.25.0)

[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 1-1: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.js` at line 1, Update ChapterPage’s load, assign,
reorder, and unassign action handlers to catch rejected API promises and write
the failure to the component’s existing error state. Ensure each handler
surfaces the error before its loading-state cleanup runs, preserving the
existing reset behavior through finally or equivalent.

@deckyfx

deckyfx commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/src/ServiceExtensions.cs`:
- Around line 104-105: Update the portal route mapping invoked by
MapPortalRoutes to require authorization for all /api/portal endpoints,
including state-changing routes, and apply a dedicated restrictive CORS policy
instead of the global default. Ensure the endpoint group uses
RequireAuthorization and the isolated portal CORS configuration prevents
arbitrary browser origins while preserving the existing route mappings.

In `@server/wwwroot/js/app.css`:
- Line 2: Prevent generated Tailwind CSS from being checked by Stylelint, or
update the generation pipeline so the output is clean and free of duplicated
declarations, deprecated appearance values, and keyword-casing violations. Do
not hand-edit the generated app.css artifact; adjust the Stylelint configuration
or the Tailwind build process that produces it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3a7f8c50-d343-40c1-821b-5a77e8a91cab

📥 Commits

Reviewing files that changed from the base of the PR and between 7261fcf and 3723755.

📒 Files selected for processing (53)
  • .gitignore
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
🚧 Files skipped from review as they are similar to previous changes (44)
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • extension/src/popup.ts
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • .gitignore
  • server/src/Jobs/TranslationJobStore.cs
  • extension/static/content.css
  • extension/static/manifest.json
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/ClientApp/src/components/BubbleList.tsx
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/package.json
  • server/ClientApp/src/components/Modal.tsx
  • server/server-csharp.csproj
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • docs/manga-page-translation.md
  • server/src/Services/BubbleDetectionService.cs
  • server/Program.cs
  • server/src/Config.cs
  • extension/src/types.ts
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • extension/static/popup.css
  • server/src/Data/AppDbContext.cs
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/src/ModelSettingsStore.cs
  • docs/portal-plan.md
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/src/Services/TypesettingService.cs
  • extension/src/content.ts
  • server/src/Routes/HealthRoutes.cs
  • extension/src/background.ts
  • server/src/Routes/TranslatePage.cs
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/src/BootExtensions.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Routes/PortalRoutes.cs
  • server/ClientApp/src/pages/StudioPage.tsx

Comment thread server/src/ServiceExtensions.cs
Comment thread server/wwwroot/js/app.css Outdated
@@ -0,0 +1,3 @@
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-600:oklch(66.6% .179 58.318);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-700:oklch(55.4% .135 66.442);--color-green-100:oklch(96.2% .044 156.743);--color-green-500:oklch(72.3% .219 149.579);--color-green-700:oklch(52.7% .154 150.069);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-600:oklch(58.8% .158 241.966);--color-sky-700:oklch(50% .134 242.749);--color-violet-50:oklch(96.9% .016 293.756);--color-violet-400:oklch(70.2% .183 293.541);--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-violet-700:oklch(49.1% .27 292.581);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.top-2{top:calc(var(--spacing) * 2)}.right-2{right:calc(var(--spacing) * 2)}.bottom-2{bottom:calc(var(--spacing) * 2)}.left-2{left:calc(var(--spacing) * 2)}.z-50{z-index:50}.m-6{margin:calc(var(--spacing) * 6)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-auto{margin-top:auto}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.aspect-3\/4{aspect-ratio:3/4}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-32{height:calc(var(--spacing) * 32)}.h-full{height:100%}.h-screen{height:100vh}.max-h-80{max-height:calc(var(--spacing) * 80)}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-36{width:calc(var(--spacing) * 36)}.w-40{width:calc(var(--spacing) * 40)}.w-48{width:calc(var(--spacing) * 48)}.w-52{width:calc(var(--spacing) * 52)}.w-64{width:calc(var(--spacing) * 64)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-md{max-width:var(--container-md)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize-y{resize:vertical}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-slate-50>:not(:last-child)){border-color:var(--color-slate-50)}:where(.divide-slate-100>:not(:last-child)){border-color:var(--color-slate-100)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-slate-100{border-color:var(--color-slate-100)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-300{border-color:var(--color-slate-300)}.border-slate-700{border-color:var(--color-slate-700)}.border-l-violet-500{border-left-color:var(--color-violet-500)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-green-100{background-color:var(--color-green-100)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-500\/90{background-color:#fb2c36e6}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/90{background-color:color-mix(in oklab, var(--color-red-500) 90%, transparent)}}.bg-red-600{background-color:var(--color-red-600)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-200{background-color:var(--color-slate-200)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-violet-50{background-color:var(--color-violet-50)}.bg-violet-600{background-color:var(--color-violet-600)}.bg-white{background-color:var(--color-white)}.bg-white\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.bg-white\/90{background-color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.bg-yellow-100{background-color:var(--color-yellow-100)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-20{padding-block:calc(var(--spacing) * 20)}.py-24{padding-block:calc(var(--spacing) * 24)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-10{padding-right:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-amber-600{color:var(--color-amber-600)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-green-500{color:var(--color-green-500)}.text-green-700{color:var(--color-green-700)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-sky-600{color:var(--color-sky-600)}.text-sky-700{color:var(--color-sky-700)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-800{color:var(--color-slate-800)}.text-violet-500{color:var(--color-violet-500)}.text-violet-600{color:var(--color-violet-600)}.text-violet-700{color:var(--color-violet-700)}.text-white{color:var(--color-white)}.text-white\!{color:var(--color-white)!important}.text-yellow-500{color:var(--color-yellow-500)}.text-yellow-700{color:var(--color-yellow-700)}.uppercase{text-transform:uppercase}.line-through{text-decoration-line:line-through}.accent-violet-600{accent-color:var(--color-violet-600)}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.ring-slate-200{--tw-ring-color:var(--color-slate-200)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-none{-webkit-user-select:none;user-select:none}.ring-inset{--tw-ring-inset:inset}@media (hover:hover){.group-hover\:translate-x-0\.5:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\:scale-105:is(:where(.group):hover *){--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}.group-hover\:text-slate-500:is(:where(.group):hover *){color:var(--color-slate-500)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-slate-400::placeholder{color:var(--color-slate-400)}@media (hover:hover){.hover\:w-48:hover{width:calc(var(--spacing) * 48)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-100:hover{background-color:var(--color-red-100)}.hover\:bg-red-600:hover{background-color:var(--color-red-600)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)}.hover\:bg-slate-800:hover{background-color:var(--color-slate-800)}.hover\:bg-violet-700:hover{background-color:var(--color-violet-700)}.hover\:bg-white:hover{background-color:var(--color-white)}.hover\:text-red-500:hover{color:var(--color-red-500)}.hover\:text-red-600:hover{color:var(--color-red-600)}.hover\:text-slate-500:hover{color:var(--color-slate-500)}.hover\:text-slate-600:hover{color:var(--color-slate-600)}.hover\:text-slate-800:hover{color:var(--color-slate-800)}.hover\:text-white:hover{color:var(--color-white)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:ring-slate-300:hover{--tw-ring-color:var(--color-slate-300)}}.focus\:border-violet-400:focus{border-color:var(--color-violet-400)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-violet-400:focus{--tw-ring-color:var(--color-violet-400)}.focus\:ring-violet-500:focus{--tw-ring-color:var(--color-violet-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-violet-500:focus-visible{outline-color:var(--color-violet-500)}.active\:bg-red-200:active{background-color:var(--color-red-200)}.active\:bg-slate-200:active{background-color:var(--color-slate-200)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=64rem){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (width>=80rem){.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}}body{font-family:Inter,system-ui,sans-serif}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep generated Tailwind output out of Stylelint, or regenerate it cleanly.

Line 2 contains repeated -webkit-text-decoration declarations, and Stylelint also reports deprecated appearance: button values and keyword-casing errors. Do not hand-edit this artifact; fix the build output or exclude generated CSS from source linting.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 2-2: Duplicate property "-webkit-text-decoration" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 2-2: Duplicate property "-webkit-text-decoration" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 2-2: Duplicate property "-webkit-text-decoration" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 2-2: Expected "button" to be "auto" (declaration-property-value-keyword-no-deprecated)

(declaration-property-value-keyword-no-deprecated)


[error] 2-2: Expected "button" to be "auto" (declaration-property-value-keyword-no-deprecated)

(declaration-property-value-keyword-no-deprecated)


[error] 2-2: Expected "SFMono-Regular" to be "sfmono-regular" (value-keyword-case)

(value-keyword-case)


[error] 2-2: Expected "Menlo" to be "menlo" (value-keyword-case)

(value-keyword-case)


[error] 2-2: Expected "Monaco" to be "monaco" (value-keyword-case)

(value-keyword-case)


[error] 2-2: Expected "Consolas" to be "consolas" (value-keyword-case)

(value-keyword-case)


[error] 2-2: Expected "currentColor" to be "currentcolor" (value-keyword-case)

(value-keyword-case)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/wwwroot/js/app.css` at line 2, Prevent generated Tailwind CSS from
being checked by Stylelint, or update the generation pipeline so the output is
clean and free of duplicated declarations, deprecated appearance values, and
keyword-casing violations. Do not hand-edit the generated app.css artifact;
adjust the Stylelint configuration or the Tailwind build process that produces
it.

Source: Linters/SAST tools

@deckyfx

deckyfx commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
extension/src/content.ts (1)

602-609: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

?? guard still allows an empty-string error to slip through.

if (!result) throw ... fixes the "undefined result" half of the previously flagged issue, but result.error ?? !result.base64 is unchanged: since ?? only falls through on null/undefined, a falsy-but-defined empty-string error bypasses the throw, leaving base64 potentially undefined and later submitted to the server as part of the JSON body.

🐛 Proposed fix
-      if (!result) throw new Error("Extension service worker not responding");
-      if (result.error ?? !result.base64) throw new Error(result.error ?? "Failed to fetch image");
-      base64 = result.base64;
+      if (!result?.base64) throw new Error(result?.error || "Failed to fetch image");
+      base64 = result.base64;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/src/content.ts` around lines 602 - 609, Update the guard in the
image-fetch response handling around result.error and result.base64 to reject
any defined-but-empty error value and any missing or empty base64 value.
Preserve the existing error messages, including the fallback fetch failure
message, while ensuring base64 is assigned only after both response fields are
valid.
🧹 Nitpick comments (1)
extension/src/content.ts (1)

617-623: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a timeout on the job-submission fetch.

If the server hangs during POST /api/translate-page, the "Uploading…" overlay never resolves and the only way out is Escape. An AbortSignal.timeout(...) would surface a clear error instead of an indefinite spinner.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extension/src/content.ts` around lines 617 - 623, Add a timeout AbortSignal
to the job-submission fetch in the translate-page flow, using the surrounding
submission logic in content.ts. Ensure a hung POST rejects with a clear error so
the existing failure handling dismisses the “Uploading…” overlay, while
preserving the current request payload and response validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extension/src/content.ts`:
- Around line 536-552: Update exitImageMode() so cleanup always closes and
clears activeEventSource, even when imagePickerActive is already false after
image selection and uploadImageForTranslation() has started streaming. Replace
or narrow the early-return guard to only skip picker-specific cleanup, while
preserving removal of listeners, hovered-image styles, and the hint when
applicable.

In `@server/.env.example`:
- Around line 23-35: Update the example configuration values for
INPAINT_MODEL_ENABLED and BUBBLE_MODEL_ENABLED to false, matching the disabled
defaults in ModelSettingsStore while leaving the repository and file settings
unchanged.

In `@server/wwwroot/js/app.js`:
- Line 1: The bundled StudioPage move and resize handlers must handle failed
bubble-update requests before regenerating app.js. In StudioPage.tsx, locate the
move and resize callbacks and wrap their awaited update operations in try/catch,
matching the existing add/update/delete error-handling behavior; preserve
successful state updates and surface failures to the user. Then rebuild the
bundle so app.js contains the corrected handlers.

---

Duplicate comments:
In `@extension/src/content.ts`:
- Around line 602-609: Update the guard in the image-fetch response handling
around result.error and result.base64 to reject any defined-but-empty error
value and any missing or empty base64 value. Preserve the existing error
messages, including the fallback fetch failure message, while ensuring base64 is
assigned only after both response fields are valid.

---

Nitpick comments:
In `@extension/src/content.ts`:
- Around line 617-623: Add a timeout AbortSignal to the job-submission fetch in
the translate-page flow, using the surrounding submission logic in content.ts.
Ensure a hung POST rejects with a clear error so the existing failure handling
dismisses the “Uploading…” overlay, while preserving the current request payload
and response validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9f630ad-5473-413a-b87f-b1e6ef094197

📥 Commits

Reviewing files that changed from the base of the PR and between 7261fcf and 1739119.

📒 Files selected for processing (54)
  • .gitignore
  • docs/manga-page-translation.md
  • docs/portal-plan.md
  • extension/build.ts
  • extension/package.json
  • extension/src/background.ts
  • extension/src/content.ts
  • extension/src/popup.ts
  • extension/src/types.ts
  • extension/static/content.css
  • extension/static/manifest.json
  • extension/static/popup.css
  • extension/static/popup.html
  • server/.env.example
  • server/.stylelintignore
  • server/ClientApp/src/api.ts
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/ClientApp/src/components/BubbleList.tsx
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • server/ClientApp/src/components/Layout.tsx
  • server/ClientApp/src/components/Modal.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/ClientApp/src/pages/LibraryPage.tsx
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/solid-app.tsx
  • server/ClientApp/src/types.ts
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/Program.cs
  • server/package.json
  • server/server-csharp.csproj
  • server/src/BootExtensions.cs
  • server/src/Config.cs
  • server/src/Data/AppDbContext.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/src/ModelSettingsStore.cs
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/Routes/PortalRoutes.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/BubbleDetectionService.cs
  • server/src/Services/PageTranslationService.cs
  • server/src/Services/TypesettingService.cs
  • server/wwwroot/js/app.css
  • server/wwwroot/js/app.js
🚧 Files skipped from review as they are similar to previous changes (49)
  • extension/static/popup.html
  • server/Migrations/20260726032802_AddPageTranslationLog.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.cs
  • server/ClientApp/src/components/ConfirmDialog.tsx
  • extension/package.json
  • server/Migrations/20260726032802_AddPageTranslationLog.Designer.cs
  • extension/src/popup.ts
  • server/Migrations/20260726035542_AddPortalSchema.Designer.cs
  • server/Migrations/20260726035542_AddPortalSchema.cs
  • server/ClientApp/src/components/BubbleList.tsx
  • .gitignore
  • server/server-csharp.csproj
  • extension/build.ts
  • extension/static/popup.css
  • extension/src/types.ts
  • server/ClientApp/src/types.ts
  • server/src/Routes/AnalyzeRoutes.cs
  • server/src/Jobs/TranslationJobStore.cs
  • server/Migrations/20260726220327_AddPageTranslationLogForeignKey.Designer.cs
  • docs/portal-plan.md
  • server/ClientApp/src/components/Modal.tsx
  • extension/static/content.css
  • server/ClientApp/src/solid-app.tsx
  • extension/static/manifest.json
  • server/ClientApp/src/pages/VolumePage.tsx
  • server/ClientApp/src/pages/ChapterPage.tsx
  • server/ClientApp/src/components/Layout.tsx
  • docs/manga-page-translation.md
  • server/src/Services/BubbleDetectionService.cs
  • server/ClientApp/src/components/BubbleEditor.tsx
  • server/src/ModelSettingsStore.cs
  • server/ClientApp/src/pages/JobsListPage.tsx
  • server/Migrations/AppDbContextModelSnapshot.cs
  • server/ClientApp/src/components/BubbleCanvas.tsx
  • server/src/Config.cs
  • server/package.json
  • server/src/Data/AppDbContext.cs
  • server/src/Routes/TranslatePage.cs
  • server/src/Routes/HealthRoutes.cs
  • server/src/ServiceExtensions.cs
  • server/src/Services/PageTranslationService.cs
  • server/ClientApp/src/api.ts
  • server/Program.cs
  • server/src/BootExtensions.cs
  • server/src/Services/TypesettingService.cs
  • server/ClientApp/src/pages/LibraryPage.tsx
  • extension/src/background.ts
  • server/ClientApp/src/pages/StudioPage.tsx
  • server/src/Routes/PortalRoutes.cs

Comment thread extension/src/content.ts
Comment thread server/.env.example
Comment thread server/wwwroot/js/app.js Outdated
…e canvas

- Extension: add Re-scan button; fix SSE leak, image fetch hardening, zero-dim guard
- Extension CSS: add :focus-visible outline for Re-scan button
- Server (SolidJS): add portal pages (Jobs, Library, Volume, Chapter, Studio)
  - BubbleCanvas: ResizeObserver replaces window.resize; draw/move/resize modes
  - BubbleEditor: track full bubble object so form resets after server updates
  - ConfirmDialog: loading prop; disable buttons while deleting
  - Modal: Escape key handler; ARIA dialog attributes
  - Layout: Tailwind v4 activeClass postfix syntax fix
  - api.ts: snakelizeKeys() for request bodies; camelizeKeys() for responses
  - JobsListPage: export StatusBadge; add default case; null-safe config access
  - StudioPage: import StatusBadge from JobsListPage; remove duplicate
  - LibraryPage/VolumePage: mutationError signal + error banner
  - ChapterPage: parallel assignJobs; paginated unassigned job fetch
- Server (C#): fix all CodeRabbit review findings
  - BootState: volatile backing fields for cross-thread visibility
  - ModelSettingsStore: handle empty-string GetDirectoryName; MergeEntry empty-guard
  - BootExtensions: derive OCR/Translate model paths from configured FileList
  - HealthRoutes: use ms.Ocr.Enabled / ms.Translate.Enabled (not hardcoded true);
    optionalsMissing now includes OCR and Translate readiness
  - AnalyzeRoutes: gate on DictionaryReady instead of IsReady
  - TranslatePage: require both OcrReady and TranslateReady; SSE Content-Type
    charset; await MarkJobFailedAsync
  - PortalRoutes: job existence check before inserting bubble; status updates
    (processing→done/error) on redetect/rerender fire-and-forget tasks
  - PageTranslationService: await CreateJobRowAsync/FinalizeJobRowAsync/LogBubble;
    safe jobId[..8] truncation; ExecuteDeleteAsync for bulk delete;
    reuse decoded image dimensions instead of second SKBitmap.Decode
  - BubbleDetectionService: atomic session swap via Interlocked.Exchange;
    volatile session field; span-based pixel reads; RT-DETR inputs bound by name;
    Math.Clamp in ToPixelBox
  - TypesettingService: Save/ClipRect/Restore to prevent text overflow
  - Program.cs: guard dashboard URL/LAN IPs behind socket-mode check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@deckyfx

deckyfx commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume
@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

@deckyfx: Automated reviews have been resumed, and I’ve triggered a review for this PR.

✅ Action performed

Reviews resumed.


Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@deckyfx

deckyfx commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant