diff --git a/PlotLine.Tests/Program.cs b/PlotLine.Tests/Program.cs
index a9a3496..af27598 100644
--- a/PlotLine.Tests/Program.cs
+++ b/PlotLine.Tests/Program.cs
@@ -80,7 +80,12 @@ var tests = new (string Name, Action Test)[]
("Writing Intent route uses canonical story context and planning data", WritingIntentRouteUsesCanonicalStoryContextAndPlanningData),
("Writing Intent client uses shared writing follow helper", WritingIntentClientUsesSharedWritingFollowHelper),
("Writing mode pages are isolated from global Word navigation", WritingModePagesAreIsolatedFromGlobalWordNavigation),
- ("Writing pair shares canonical follow infrastructure", WritingPairSharesCanonicalFollowInfrastructure)
+ ("Writing pair shares canonical follow infrastructure", WritingPairSharesCanonicalFollowInfrastructure),
+ ("Word manuscript cleanup classifies PlotDirector markers by tag only", WordManuscriptCleanupClassifiesPlotDirectorMarkersByTagOnly),
+ ("Word manuscript cleanup preserves content controls content", WordManuscriptCleanupPreservesContentControlContent),
+ ("Word manuscript cleanup UI separates unlink from clean unlink", WordManuscriptCleanupUiSeparatesUnlinkFromCleanUnlink),
+ ("Word manuscript unlink keeps Story Intelligence data untouched", WordManuscriptUnlinkKeepsStoryIntelligenceDataUntouched),
+ ("Word manuscript cleanup remains relinkable and idempotent", WordManuscriptCleanupRemainsRelinkableAndIdempotent)
};
foreach (var test in tests)
@@ -264,6 +269,94 @@ static void WritingPairSharesCanonicalFollowInfrastructure()
Assert(helper.Contains("document.addEventListener(window.PlotDirectorStoryPosition?.eventName", StringComparison.Ordinal), "Both pages should react to the same canonical browser event.");
}
+static void WordManuscriptCleanupClassifiesPlotDirectorMarkersByTagOnly()
+{
+ var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
+ var script = File.ReadAllText(Path.Combine(root, "wwwroot/js/word-companion-host.js"));
+ var classifierStart = script.IndexOf("const classifyPlotDirectorContentControl", StringComparison.Ordinal);
+ var classifierEnd = script.IndexOf("window.PlotDirectorWordMarkers", classifierStart, StringComparison.Ordinal);
+
+ Assert(classifierStart >= 0 && classifierEnd > classifierStart, "Word host should expose a stable PlotDirector marker classifier.");
+ var classifier = script[classifierStart..classifierEnd];
+ Assert(classifier.Contains("const tag = String(control?.tag || \"\").trim().toUpperCase()", StringComparison.Ordinal), "Marker cleanup should classify content controls from the tag field.");
+ Assert(script.Contains("chapter: \"PD-CHAPTER-\"", StringComparison.Ordinal), "Chapter marker prefix is missing.");
+ Assert(script.Contains("scene: \"PD-SCENE-\"", StringComparison.Ordinal), "Scene marker prefix is missing.");
+ Assert(classifier.Contains("tag.startsWith(plotDirectorMarkerPrefixes.chapter)", StringComparison.Ordinal), "Classifier should use the chapter tag prefix.");
+ Assert(classifier.Contains("tag.startsWith(plotDirectorMarkerPrefixes.scene)", StringComparison.Ordinal), "Classifier should use the scene tag prefix.");
+ Assert(!classifier.Contains("title", StringComparison.OrdinalIgnoreCase), "Marker cleanup must not delete arbitrary controls by display title.");
+}
+
+static void WordManuscriptCleanupPreservesContentControlContent()
+{
+ var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
+ var script = File.ReadAllText(Path.Combine(root, "wwwroot/js/word-companion-host.js"));
+
+ Assert(script.Contains("const removePlotDirectorContentControlsPreservingContent", StringComparison.Ordinal), "Clean unlink should have a dedicated marker removal path.");
+ Assert(script.Contains("context.document.contentControls", StringComparison.Ordinal), "Clean unlink should inspect document content controls.");
+ Assert(script.Contains("control.delete(true);", StringComparison.Ordinal), "PlotDirector marker cleanup must call Word.ContentControl.delete(true) to preserve visible content.");
+ Assert(!script.Contains("control.delete(false)", StringComparison.Ordinal), "PlotDirector marker cleanup must not delete marker content.");
+ Assert(!script.Contains("control.delete();", StringComparison.Ordinal), "PlotDirector marker cleanup must pass keepContent explicitly.");
+ Assert(script.Contains("await inspectPlotDirectorMarkers();", StringComparison.Ordinal), "Clean unlink should verify marker counts after removal.");
+ Assert(script.Contains("latestMarkerState.totalCount > 0", StringComparison.Ordinal), "Clean unlink should stop when PlotDirector markers remain.");
+ Assert(script.Contains("cleanup verification failed", StringComparison.Ordinal), "Clean unlink should fail closed when marker verification cannot complete.");
+}
+
+static void WordManuscriptCleanupUiSeparatesUnlinkFromCleanUnlink()
+{
+ var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
+ var view = File.ReadAllText(Path.Combine(root, "Views/WordCompanionHost/Index.cshtml"));
+ var script = File.ReadAllText(Path.Combine(root, "wwwroot/js/word-companion-host.js"));
+
+ Assert(view.Contains("data-marker-binding-status", StringComparison.Ordinal), "Maintenance UI should report document binding status.");
+ Assert(view.Contains("data-marker-chapter-count", StringComparison.Ordinal), "Maintenance UI should report chapter marker counts.");
+ Assert(view.Contains("data-marker-scene-count", StringComparison.Ordinal), "Maintenance UI should report scene marker counts.");
+ Assert(view.Contains("Unlink from PlotDirector", StringComparison.Ordinal), "Existing unlink behavior should remain visible as a separate action.");
+ Assert(view.Contains("Hidden PlotDirector anchors will be left in place", StringComparison.Ordinal), "Existing unlink dialog should state markers are retained.");
+ Assert(view.Contains("Clean and unlink document", StringComparison.Ordinal), "Full cleanup should be a separate explicit action.");
+ Assert(view.Contains("data-clean-unlink-word-document", StringComparison.Ordinal), "Clean unlink button is missing.");
+ Assert(view.Contains("data-clean-unlink-word-document-dialog", StringComparison.Ordinal), "Clean unlink confirmation dialog is missing.");
+ Assert(view.Contains("Visible manuscript text, headings, formatting, comments, and tracked changes should remain", StringComparison.Ordinal), "Clean unlink dialog should describe content preservation.");
+ Assert(script.Contains("requestUnlinkWordDocumentConfirmation", StringComparison.Ordinal), "Existing unlink confirmation path should remain.");
+ Assert(script.Contains("requestCleanUnlinkWordDocumentConfirmation", StringComparison.Ordinal), "Clean unlink should use its own confirmation path.");
+}
+
+static void WordManuscriptUnlinkKeepsStoryIntelligenceDataUntouched()
+{
+ var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
+ var unlinkSql = File.ReadAllText(Path.Combine(root, "Sql/108_Phase16Q_ManuscriptUnlink.sql"));
+ var sceneResultSql = File.ReadAllText(Path.Combine(root, "Sql/115_Phase20I_StoryIntelligenceResultPersistence.sql"));
+ var importCommitSql = File.ReadAllText(Path.Combine(root, "Sql/121_Phase20V_StoryIntelligenceImportCommit.sql"));
+
+ Assert(unlinkSql.Contains("CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_UnlinkBook", StringComparison.Ordinal), "Server unlink procedure is missing.");
+ Assert(unlinkSql.Contains("IsLinkedToManuscript = 0", StringComparison.Ordinal), "Server unlink should clear manuscript link flags.");
+ Assert(unlinkSql.Contains("ManuscriptDocumentID = NULL", StringComparison.Ordinal), "Server unlink should clear manuscript document references.");
+ Assert(unlinkSql.Contains("IsActive = 0", StringComparison.Ordinal), "Server unlink should deactivate only the manuscript document binding row.");
+ Assert(!unlinkSql.Contains("StoryIntelligence", StringComparison.Ordinal), "Server unlink must not modify Story Intelligence tables.");
+ Assert(!unlinkSql.Contains("DELETE FROM dbo.Chapters", StringComparison.OrdinalIgnoreCase), "Server unlink must not delete chapters.");
+ Assert(!unlinkSql.Contains("DELETE FROM dbo.Scenes", StringComparison.OrdinalIgnoreCase), "Server unlink must not delete scenes.");
+ Assert(sceneResultSql.Contains("StartParagraph", StringComparison.Ordinal) && sceneResultSql.Contains("EndParagraph", StringComparison.Ordinal), "Story Intelligence scene result positions should remain database-backed.");
+ Assert(importCommitSql.Contains("SourceStartParagraph", StringComparison.Ordinal) && importCommitSql.Contains("SourceEndParagraph", StringComparison.Ordinal), "Story Intelligence source positions should remain database-backed.");
+}
+
+static void WordManuscriptCleanupRemainsRelinkableAndIdempotent()
+{
+ var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
+ var script = File.ReadAllText(Path.Combine(root, "wwwroot/js/word-companion-host.js"));
+ var service = File.ReadAllText(Path.Combine(root, "Services/WordCompanionService.cs"));
+ var repository = File.ReadAllText(Path.Combine(root, "Data/Repositories.cs"));
+ var saveSql = File.ReadAllText(Path.Combine(root, "Sql/094_Phase16B_ManuscriptBindingLinkedStructures.sql"));
+ var unlinkSql = File.ReadAllText(Path.Combine(root, "Sql/108_Phase16Q_ManuscriptUnlink.sql"));
+
+ Assert(script.Contains("const binding = currentDocumentBinding();", StringComparison.Ordinal), "Clean unlink should tolerate missing local binding metadata.");
+ Assert(script.Contains("if (binding?.documentGuid && Number.isInteger(binding.bookId) && binding.bookId > 0)", StringComparison.Ordinal), "Server unlink should be skipped safely when no binding exists.");
+ Assert(script.Contains("await removeDocumentBinding();", StringComparison.Ordinal), "Clean unlink should remove local binding settings after marker verification.");
+ Assert(service.Contains("documentGuid = Guid.NewGuid();", StringComparison.Ordinal), "Relinking should mint a new document GUID when needed.");
+ Assert(service.Contains("manuscriptDocuments.SaveAsync(request.BookId, documentGuid, RequireUserId())", StringComparison.Ordinal), "Relinking should still flow through the manuscript document repository.");
+ Assert(repository.Contains("\"dbo.ManuscriptDocument_Save\"", StringComparison.Ordinal), "Relinking should still use the manuscript document save procedure.");
+ Assert(saveSql.Contains("ManuscriptDocument_Save", StringComparison.Ordinal) && saveSql.Contains("IsActive", StringComparison.Ordinal), "Server save procedure should support a new active document binding.");
+ Assert(unlinkSql.Contains("@DocumentGuid IS NULL", StringComparison.Ordinal) && unlinkSql.Contains("00000000-0000-0000-0000-000000000000", StringComparison.Ordinal), "Server unlink should tolerate repeated or metadata-free unlink requests.");
+}
+
static void StripsMarkdownFence()
{
var result = StoryIntelligenceJsonRepair.Repair("""
diff --git a/PlotLine/Views/WordCompanionHost/Index.cshtml b/PlotLine/Views/WordCompanionHost/Index.cshtml
index 1efbef1..5933097 100644
--- a/PlotLine/Views/WordCompanionHost/Index.cshtml
+++ b/PlotLine/Views/WordCompanionHost/Index.cshtml
@@ -270,10 +270,28 @@
Manuscript Maintenance
Use these tools when manuscript headings, scene boundaries, or document links need attention.
+
+
Document bindingUnknown
+
Chapter markers-
+
Scene markers-
+
+
+
+ Unlink from PlotDirector
+
Disconnect this document while leaving hidden PlotDirector anchors in place for possible reuse.
+
+
+
+
+
+ Clean and unlink document
+
Remove PlotDirector hidden anchors and binding metadata from this Word document while preserving manuscript text.
+
+
+
-
@@ -539,15 +557,38 @@
Unlink Word Document?
-
This will remove PlotDirector binding metadata from this Word document.
-
If PlotDirector is reachable, it will also unlink this Book in PlotDirector.
+
This will remove PlotDirector binding metadata from this Word document and unlink this Book in PlotDirector.
+
Hidden PlotDirector anchors will be left in place for possible reuse.
Your manuscript text will not be changed.
+
+
Chapter markers kept-
+
Scene markers kept-
+
+
+
}
@if (Model.IsAuthenticated)
diff --git a/PlotLine/wwwroot/css/word-companion.css b/PlotLine/wwwroot/css/word-companion.css
index c7c9388..6570eb6 100644
--- a/PlotLine/wwwroot/css/word-companion.css
+++ b/PlotLine/wwwroot/css/word-companion.css
@@ -601,6 +601,67 @@ body {
background: #fef2f2;
}
+.word-companion-marker-status {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 6px;
+}
+
+.word-companion-marker-status div {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ border: 1px solid rgba(111, 75, 45, 0.16);
+ border-radius: 6px;
+ padding: 6px 8px;
+ background: #fffdf8;
+}
+
+.word-companion-marker-status span {
+ color: var(--companion-muted);
+ font-size: 0.76rem;
+ font-weight: 800;
+ text-transform: uppercase;
+}
+
+.word-companion-dialog-marker-status {
+ margin: 2px 0;
+}
+
+.word-companion-maintenance-group {
+ display: grid;
+ gap: 8px;
+ border: 1px solid rgba(111, 75, 45, 0.16);
+ border-radius: 8px;
+ padding: 9px;
+ background: #fffdf8;
+}
+
+.word-companion-maintenance-group-strong {
+ border-color: #fecaca;
+ background: #fff8f6;
+}
+
+.word-companion-maintenance-group p {
+ margin: 3px 0 0;
+ color: var(--companion-muted);
+ font-size: 0.84rem;
+}
+
+.word-companion-maintenance-group button {
+ width: 100%;
+ min-height: 31px;
+ border: 1px solid var(--companion-line);
+ border-radius: 6px;
+ padding: 6px 8px;
+ background: #fffdf8;
+ color: var(--companion-accent-dark);
+ font: inherit;
+ font-size: 0.8rem;
+ font-weight: 800;
+}
+
.word-companion-message:empty {
display: none;
}
diff --git a/PlotLine/wwwroot/css/word-companion.min.css b/PlotLine/wwwroot/css/word-companion.min.css
index 8d5e2f7..0c639ab 100644
--- a/PlotLine/wwwroot/css/word-companion.min.css
+++ b/PlotLine/wwwroot/css/word-companion.min.css
@@ -1 +1 @@
-:root{--companion-ink:#2d241d;--companion-muted:#7b7168;--companion-paper:#f8f1e6;--companion-panel:#fffaf2;--companion-line:#e1d3bf;--companion-accent:#6f4b2d;--companion-accent-dark:#4a321f;--companion-gold:#b68a46;--companion-soft:#f3eadc;--companion-soft-strong:#ead9c1}*{box-sizing:border-box}[hidden]{display:none!important}body{margin:0;min-width:280px;color:var(--companion-ink);background:var(--companion-paper);font-family:"Segoe UI",system-ui,-apple-system,BlinkMacSystemFont,sans-serif}.word-companion-login-body{min-width:280px}.word-companion-login-shell{display:grid;align-content:start;gap:12px;width:100%;max-width:420px;padding:14px 12px}.word-companion-login-header{display:grid;gap:2px;border-bottom:1px solid var(--companion-line);padding-bottom:9px}.word-companion-login-header h1{margin:0;color:var(--companion-accent-dark);font-size:1.22rem;line-height:1.1}.word-companion-login-header p{margin:0;color:var(--companion-muted);font-size:.82rem;font-weight:800;text-transform:uppercase}.word-companion-login-alert,.word-companion-login-card{border:1px solid var(--companion-line);border-radius:10px;background:var(--companion-panel);box-shadow:0 2px 8px rgba(74,50,31,.08)}.word-companion-login-card{padding:14px}.word-companion-login-alert{padding:10px;color:var(--companion-accent-dark);font-size:.86rem}.word-companion-login-form{display:grid;gap:10px}.word-companion-login-form div{display:grid;gap:4px}.word-companion-login-form label{color:var(--companion-muted);font-size:.74rem;font-weight:800;text-transform:uppercase}.word-companion-login-form input:not([type]),.word-companion-login-form input[type=email],.word-companion-login-form input[type=password]{width:100%;min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:7px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-login-form span{color:#8f3528;font-size:.76rem}.word-companion-login-check{display:flex!important;align-items:center;gap:7px;color:var(--companion-ink)!important;font-size:.84rem!important;font-weight:600!important;text-transform:none!important}.word-companion-login-check input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-login-form button{min-height:36px;border:1px solid var(--companion-accent);border-radius:8px;background:linear-gradient(180deg,#7b5432 0,var(--companion-accent-dark) 100%);color:#fff9ef;font:inherit;font-size:.9rem;font-weight:800}.word-companion-login-links{display:grid;gap:6px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-login-links a{color:var(--companion-accent-dark);font-size:.84rem;font-weight:700;text-decoration:none}.word-companion-login-validation:empty{display:none}.word-companion-shell{display:grid;align-content:start;gap:9px;width:100%;max-width:420px;padding:10px 11px}.word-companion-header{display:flex;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid var(--companion-line);padding-bottom:7px}.word-companion-eyebrow{margin:0;color:var(--companion-accent-dark);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.word-companion-header h1{margin:0;font-size:1.12rem;line-height:1.1;color:var(--companion-accent-dark)}.word-companion-footer,.word-companion-message,.word-companion-status,.word-companion-user{margin:0;color:var(--companion-muted);font-size:.82rem}.word-companion-status{color:var(--companion-accent-dark);font-weight:700}.word-companion-sign-in{display:inline-flex;align-items:center;justify-content:center;width:fit-content;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 10px;background:var(--companion-accent);color:#fff;font-size:.88rem;font-weight:700;text-decoration:none}.word-companion-signed-out{display:grid;gap:12px;border:1px solid var(--companion-line);border-radius:10px;padding:16px;background:var(--companion-panel);box-shadow:0 2px 8px rgba(74,50,31,.08)}.word-companion-signed-out p{margin:0;color:var(--companion-ink);font-size:.94rem;line-height:1.35}.word-companion-signed-out ul{display:grid;gap:5px;margin:0;padding-left:18px;color:var(--companion-muted);font-size:.88rem}.word-companion-sign-in-primary{width:100%;min-height:36px;border-radius:8px;font-size:.9rem}.word-companion-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:3px;border:1px solid var(--companion-line);border-radius:9px;padding:3px;background:#fff7eb;box-shadow:inset 0 1px 0 rgba(255,255,255,.75)}.word-companion-tabs button{min-width:0;height:28px;min-height:28px;border:1px solid transparent;border-radius:7px;background:0 0;color:var(--companion-muted);font:inherit;font-size:.68rem;font-weight:700;line-height:1;padding:0 4px;white-space:nowrap}.word-companion-tabs button.is-active{border-color:rgba(111,75,45,.3);background:var(--companion-soft-strong);color:var(--companion-accent-dark);font-weight:900;box-shadow:none}.word-companion-tab-panel{display:grid;align-content:start;gap:8px}.word-companion-section{display:grid;gap:7px;border:1px solid var(--companion-line);border-radius:8px;padding:9px;background:var(--companion-panel);box-shadow:0 1px 2px rgba(74,50,31,.05)}.word-companion-section label,.word-companion-section span,.word-companion-summary span{color:var(--companion-muted);font-size:.76rem;font-weight:800;text-transform:uppercase}.word-companion-section label{display:block}.word-companion-section input[type=text],.word-companion-section select{width:100%;min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-connection{grid-template-columns:1fr;gap:9px}.word-companion-linked-card{gap:4px;padding:8px 9px}.word-companion-linked-card div{display:grid;gap:2px}.word-companion-linked-card strong{color:var(--companion-accent-dark);font-size:.94rem;line-height:1.2}.word-companion-linked-card p{margin:0;color:#2f6b45;font-size:.8rem;font-weight:800}.word-companion-first-run{gap:10px}.word-companion-inline-create{display:grid;gap:5px}.word-companion-inline-create>div{display:grid;grid-template-columns:1fr auto;gap:6px}.word-companion-inline-create button{min-height:34px;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 9px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.8rem;font-weight:800}.word-companion-inline-create button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-import-summary{display:grid;gap:7px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-import-summary dl{display:grid;grid-template-columns:1fr auto;gap:5px 10px;margin:0}.word-companion-import-summary dt{color:var(--companion-muted);font-size:.76rem;font-weight:800;text-transform:uppercase}.word-companion-import-summary dd{margin:0;color:var(--companion-ink);font-weight:800;text-align:right}.word-companion-character-discovery{display:grid;gap:8px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-character-candidates{display:grid;align-content:start;gap:7px;grid-auto-rows:max-content;max-height:min(260px,42vh);overflow-y:auto;overflow-x:hidden;padding-right:2px}.word-companion-section .word-companion-character-candidate{display:flex;align-items:flex-start;gap:9px;min-height:42px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:7px 8px;background:#fffdf8}.word-companion-character-candidate input{flex:0 0 auto;width:16px;height:16px;margin:2px 0 0;accent-color:var(--companion-accent)}.word-companion-section .word-companion-character-candidate-text{display:grid;gap:2px;min-width:0;color:var(--companion-ink);font-size:inherit;font-weight:inherit;overflow-wrap:anywhere;text-transform:none}.word-companion-section .word-companion-character-candidate strong{color:var(--companion-ink);font-size:.92rem;line-height:1.2;text-transform:none}.word-companion-section .word-companion-character-candidate em{color:var(--companion-muted);font-size:.76rem;font-style:normal;font-weight:700;line-height:1.25;text-transform:none}.word-companion-connection .word-companion-message{grid-column:auto}.word-companion-section select:disabled{background:var(--companion-soft);color:var(--companion-muted)}.word-companion-section-header{display:flex;align-items:center;justify-content:space-between;gap:7px}.word-companion-header-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:5px}.word-companion-section-header button{min-height:28px;border:1px solid var(--companion-accent);border-radius:6px;padding:4px 7px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.74rem;font-weight:700}.word-companion-actions button:disabled,.word-companion-section-header button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}.word-companion-actions button{min-height:31px;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-accent-dark);font:inherit;font-size:.8rem;font-weight:800}.word-companion-actions .word-companion-primary-action{background:linear-gradient(180deg,#7b5432 0,var(--companion-accent-dark) 100%);color:#fff9ef}.word-companion-link-groups .word-companion-section-header button,.word-companion-structure-preview .word-companion-section-header button{min-height:27px;padding:4px 7px;font-size:.72rem}.word-companion-actions button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-current-scene>button{min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fff;color:var(--companion-accent-dark);font:inherit;font-size:.84rem;font-weight:800}.word-companion-current-scene>button:disabled{background:var(--companion-soft);color:var(--companion-muted)}.word-companion-current-scene>.word-companion-danger-action{border-color:#fecaca;color:#b91c1c}.word-companion-current-scene>.word-companion-danger-action:hover:not(:disabled){border-color:#ef4444;background:#fef2f2}.word-companion-maintenance .word-companion-danger-action{border-color:#fecaca;color:#b91c1c}.word-companion-maintenance .word-companion-danger-action:hover:not(:disabled){border-color:#ef4444;background:#fef2f2}.word-companion-message:empty{display:none}.word-companion-section strong{min-width:0;font-size:.96rem;overflow-wrap:anywhere}.word-companion-metrics,.word-companion-scene-card,.word-companion-structure-grid{display:grid;gap:8px}.word-companion-scene-card{border:1px solid rgba(111,75,45,.2);border-radius:8px;padding:10px;background:var(--companion-soft)}.word-companion-scene-summary{gap:8px}.word-companion-title-row strong{color:var(--companion-accent-dark);font-size:1rem;line-height:1.25}.word-companion-badges{display:flex;flex-wrap:wrap;gap:6px}.word-companion-badge{display:inline-flex;align-items:center;gap:4px;width:fit-content;min-height:24px;border:1px solid rgba(111,75,45,.24);border-radius:999px;padding:3px 8px;background:#fffaf2;color:var(--companion-accent-dark)!important;font-size:.74rem!important;font-weight:800!important;text-transform:none!important}.word-companion-badge strong{color:var(--companion-accent-dark);font-size:inherit}.word-companion-link-context{margin:-2px 0 2px;border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px 8px;background:var(--companion-soft);color:var(--companion-accent-dark);font-size:.82rem;font-weight:700}.word-companion-diagnostics-grid div,.word-companion-metrics div,.word-companion-scene-card div,.word-companion-structure-grid div,.word-companion-sync-meta div{display:grid;gap:2px}.word-companion-metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.word-companion-metrics div{border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px;background:#fffdf8}.word-companion-metrics strong{color:var(--companion-accent-dark);font-size:.91rem}.word-companion-sync-meta{display:grid;gap:8px;grid-template-columns:1fr 1fr}.word-companion-diagnostics-grid{display:grid;gap:8px;grid-template-columns:1fr 1fr}.word-companion-diagnostics-grid strong{font-size:.88rem}.word-companion-link-groups,.word-companion-resolve-diagnostics,.word-companion-scene-details{display:grid;gap:7px}.word-companion-link-groups div,.word-companion-resolve-diagnostics div,.word-companion-scene-details div{display:grid;gap:3px}.word-companion-review-group{display:grid;gap:7px;border:1px solid rgba(111,75,45,.16);border-radius:7px;padding:8px;background:#fffdf8}.word-companion-review-group summary{cursor:pointer;color:var(--companion-accent-dark);font-size:.9rem;font-weight:800}.word-companion-review-group:not([open])>:not(summary){display:none!important}.word-companion-review-group label{margin-top:6px}.word-companion-resolve-diagnostics{padding-top:4px;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 7px}.word-companion-resolve-diagnostics div{min-width:0;border-bottom:1px solid rgba(225,211,191,.6);padding-bottom:4px}.word-companion-resolve-diagnostics strong{color:var(--companion-ink);font-size:.8rem;line-height:1.25}.word-companion-resolve-diagnostics span{font-size:.68rem;letter-spacing:.01em}.word-companion-progress-sync{display:grid;gap:8px;border-top:1px solid var(--companion-line);padding-top:8px}.word-companion-progress-grid{display:grid;gap:8px}.word-companion-progress-grid div{display:grid;gap:3px}.word-companion-progress-grid strong{font-size:.88rem}.word-companion-brief{display:grid;gap:5px}.word-companion-brief p{margin:0;border:1px solid var(--companion-line);border-radius:6px;padding:9px;background:var(--companion-soft);color:var(--companion-ink);font-size:.9rem;line-height:1.35;white-space:pre-wrap}.word-companion-check-list{display:grid;gap:.75rem}.word-companion-check-item{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.75rem;min-height:42px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:.75rem;background:#fffdf8;color:var(--companion-ink);font-size:.9rem}.word-companion-check-item input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-check-item span{color:var(--companion-ink);font-size:.9rem;font-weight:600;text-transform:none}.word-companion-check-item:has(input:disabled){background:var(--companion-soft);color:var(--companion-muted)}.word-companion-create-link{border-color:rgba(182,138,70,.45);background:#fff8ec}.word-companion-advanced{border:0;border-top:1px solid var(--companion-line);border-radius:0;padding:7px 0 0;background:0 0;box-shadow:none}.word-companion-maintenance-actions{grid-template-columns:1fr}.word-companion-structure-preview{border-color:rgba(182,138,70,.35)}.word-companion-preview-group,.word-companion-preview-groups,.word-companion-preview-item{display:grid;gap:6px}.word-companion-preview-group{border-top:1px solid var(--companion-line);padding-top:7px}.word-companion-preview-group:first-child{border-top:0;padding-top:0}.word-companion-preview-item{border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px;background:#fffdf8}.word-companion-preview-item span,.word-companion-preview-matches li{color:var(--companion-ink);font-size:.86rem;font-weight:500;text-transform:none}.word-companion-preview-matches{display:grid;gap:3px}.word-companion-preview-matches ul{display:grid;gap:3px;margin:0;padding-left:18px}.word-companion-apply-summary ul{display:grid;gap:4px;margin:0;padding-left:18px}.word-companion-apply-summary li{color:var(--companion-ink);font-size:.9rem}.word-companion-dialog{width:min(360px,calc(100vw - 24px));border:1px solid var(--companion-line);border-radius:8px;padding:12px;background:var(--companion-panel);color:var(--companion-ink);font-family:"Segoe UI",system-ui,-apple-system,BlinkMacSystemFont,sans-serif}.word-companion-dialog::backdrop{background:rgba(30,37,43,.28)}.word-companion-dialog form{display:grid;gap:8px}.word-companion-dialog strong{min-width:0;overflow-wrap:anywhere}.word-companion-dialog-copy{margin:0;color:var(--companion-muted);font-size:.9rem}.word-companion-dialog-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.word-companion-dialog input[type=search]{width:100%;min-height:36px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-dialog button{min-height:32px;border:1px solid var(--companion-accent);border-radius:6px;padding:5px 9px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.82rem;font-weight:700}.word-companion-dialog button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-scene-options{display:grid;gap:5px;max-height:220px;overflow-y:auto}.word-companion-scene-option{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:7px;min-height:32px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:5px 7px;background:#fffdf8;color:var(--companion-ink);font-size:.9rem}.word-companion-scene-option input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-empty-list{margin:0;color:var(--companion-muted);font-size:.88rem}.word-companion-outline{display:grid;gap:7px;padding-top:4px}.word-companion-outline p{margin:0;color:var(--companion-muted);font-size:.9rem}.word-companion-outline-chapter{display:grid;gap:4px}.word-companion-outline-chapter ul{display:grid;gap:3px;margin:0;padding-left:18px}.word-companion-outline-chapter li{color:var(--companion-ink);font-size:.9rem}.word-companion-summary{display:grid;gap:8px;border:1px solid rgba(111,75,45,.18);border-radius:8px;padding:12px;background:var(--companion-soft)}.word-companion-summary div{display:grid;gap:2px}.word-companion-summary strong{min-width:0;font-size:.92rem;overflow-wrap:anywhere}.word-companion-collapsible{gap:8px;background:#fff8ec}.word-companion-collapsible:not([open])>:not(summary){display:none!important}.word-companion-collapsible summary{cursor:pointer;color:var(--companion-ink);font-size:.92rem;font-weight:800;list-style-position:outside}.word-companion-collapsible[open] summary{padding-bottom:6px;border-bottom:1px solid var(--companion-line)}.word-companion-collapsible .word-companion-section-header{padding-top:4px}.word-companion-footer{border-top:1px solid var(--companion-line);padding-top:7px;font-size:.76rem}@media (min-width:390px){.word-companion-connection{grid-template-columns:1fr 1fr}}@media (max-width:340px){.word-companion-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.word-companion-metrics,.word-companion-resolve-diagnostics{grid-template-columns:1fr}.word-companion-actions{grid-template-columns:1fr}}
\ No newline at end of file
+:root{--companion-ink:#2d241d;--companion-muted:#7b7168;--companion-paper:#f8f1e6;--companion-panel:#fffaf2;--companion-line:#e1d3bf;--companion-accent:#6f4b2d;--companion-accent-dark:#4a321f;--companion-gold:#b68a46;--companion-soft:#f3eadc;--companion-soft-strong:#ead9c1}*{box-sizing:border-box}[hidden]{display:none!important}body{margin:0;min-width:280px;color:var(--companion-ink);background:var(--companion-paper);font-family:"Segoe UI",system-ui,-apple-system,BlinkMacSystemFont,sans-serif}.word-companion-login-body{min-width:280px}.word-companion-login-shell{display:grid;align-content:start;gap:12px;width:100%;max-width:420px;padding:14px 12px}.word-companion-login-header{display:grid;gap:2px;border-bottom:1px solid var(--companion-line);padding-bottom:9px}.word-companion-login-header h1{margin:0;color:var(--companion-accent-dark);font-size:1.22rem;line-height:1.1}.word-companion-login-header p{margin:0;color:var(--companion-muted);font-size:.82rem;font-weight:800;text-transform:uppercase}.word-companion-login-alert,.word-companion-login-card{border:1px solid var(--companion-line);border-radius:10px;background:var(--companion-panel);box-shadow:0 2px 8px rgba(74,50,31,.08)}.word-companion-login-card{padding:14px}.word-companion-login-alert{padding:10px;color:var(--companion-accent-dark);font-size:.86rem}.word-companion-login-form{display:grid;gap:10px}.word-companion-login-form div{display:grid;gap:4px}.word-companion-login-form label{color:var(--companion-muted);font-size:.74rem;font-weight:800;text-transform:uppercase}.word-companion-login-form input:not([type]),.word-companion-login-form input[type=email],.word-companion-login-form input[type=password]{width:100%;min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:7px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-login-form span{color:#8f3528;font-size:.76rem}.word-companion-login-check{display:flex!important;align-items:center;gap:7px;color:var(--companion-ink)!important;font-size:.84rem!important;font-weight:600!important;text-transform:none!important}.word-companion-login-check input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-login-form button{min-height:36px;border:1px solid var(--companion-accent);border-radius:8px;background:linear-gradient(180deg,#7b5432 0,var(--companion-accent-dark) 100%);color:#fff9ef;font:inherit;font-size:.9rem;font-weight:800}.word-companion-login-links{display:grid;gap:6px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-login-links a{color:var(--companion-accent-dark);font-size:.84rem;font-weight:700;text-decoration:none}.word-companion-login-validation:empty{display:none}.word-companion-shell{display:grid;align-content:start;gap:9px;width:100%;max-width:420px;padding:10px 11px}.word-companion-header{display:flex;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid var(--companion-line);padding-bottom:7px}.word-companion-eyebrow{margin:0;color:var(--companion-accent-dark);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.word-companion-header h1{margin:0;font-size:1.12rem;line-height:1.1;color:var(--companion-accent-dark)}.word-companion-footer,.word-companion-message,.word-companion-status,.word-companion-user{margin:0;color:var(--companion-muted);font-size:.82rem}.word-companion-status{color:var(--companion-accent-dark);font-weight:700}.word-companion-sign-in{display:inline-flex;align-items:center;justify-content:center;width:fit-content;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 10px;background:var(--companion-accent);color:#fff;font-size:.88rem;font-weight:700;text-decoration:none}.word-companion-signed-out{display:grid;gap:12px;border:1px solid var(--companion-line);border-radius:10px;padding:16px;background:var(--companion-panel);box-shadow:0 2px 8px rgba(74,50,31,.08)}.word-companion-signed-out p{margin:0;color:var(--companion-ink);font-size:.94rem;line-height:1.35}.word-companion-signed-out ul{display:grid;gap:5px;margin:0;padding-left:18px;color:var(--companion-muted);font-size:.88rem}.word-companion-sign-in-primary{width:100%;min-height:36px;border-radius:8px;font-size:.9rem}.word-companion-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:3px;border:1px solid var(--companion-line);border-radius:9px;padding:3px;background:#fff7eb;box-shadow:inset 0 1px 0 rgba(255,255,255,.75)}.word-companion-tabs button{min-width:0;height:28px;min-height:28px;border:1px solid transparent;border-radius:7px;background:0 0;color:var(--companion-muted);font:inherit;font-size:.68rem;font-weight:700;line-height:1;padding:0 4px;white-space:nowrap}.word-companion-tabs button.is-active{border-color:rgba(111,75,45,.3);background:var(--companion-soft-strong);color:var(--companion-accent-dark);font-weight:900;box-shadow:none}.word-companion-tab-panel{display:grid;align-content:start;gap:8px}.word-companion-section{display:grid;gap:7px;border:1px solid var(--companion-line);border-radius:8px;padding:9px;background:var(--companion-panel);box-shadow:0 1px 2px rgba(74,50,31,.05)}.word-companion-section label,.word-companion-section span,.word-companion-summary span{color:var(--companion-muted);font-size:.76rem;font-weight:800;text-transform:uppercase}.word-companion-section label{display:block}.word-companion-section input[type=text],.word-companion-section select{width:100%;min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-connection{grid-template-columns:1fr;gap:9px}.word-companion-linked-card{gap:4px;padding:8px 9px}.word-companion-linked-card div{display:grid;gap:2px}.word-companion-linked-card strong{color:var(--companion-accent-dark);font-size:.94rem;line-height:1.2}.word-companion-linked-card p{margin:0;color:#2f6b45;font-size:.8rem;font-weight:800}.word-companion-first-run{gap:10px}.word-companion-inline-create{display:grid;gap:5px}.word-companion-inline-create>div{display:grid;grid-template-columns:1fr auto;gap:6px}.word-companion-inline-create button{min-height:34px;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 9px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.8rem;font-weight:800}.word-companion-inline-create button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-import-summary{display:grid;gap:7px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-import-summary dl{display:grid;grid-template-columns:1fr auto;gap:5px 10px;margin:0}.word-companion-import-summary dt{color:var(--companion-muted);font-size:.76rem;font-weight:800;text-transform:uppercase}.word-companion-import-summary dd{margin:0;color:var(--companion-ink);font-weight:800;text-align:right}.word-companion-character-discovery{display:grid;gap:8px;border-top:1px solid var(--companion-line);padding-top:9px}.word-companion-character-candidates{display:grid;align-content:start;gap:7px;grid-auto-rows:max-content;max-height:min(260px,42vh);overflow-y:auto;overflow-x:hidden;padding-right:2px}.word-companion-section .word-companion-character-candidate{display:flex;align-items:flex-start;gap:9px;min-height:42px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:7px 8px;background:#fffdf8}.word-companion-character-candidate input{flex:0 0 auto;width:16px;height:16px;margin:2px 0 0;accent-color:var(--companion-accent)}.word-companion-section .word-companion-character-candidate-text{display:grid;gap:2px;min-width:0;color:var(--companion-ink);font-size:inherit;font-weight:inherit;overflow-wrap:anywhere;text-transform:none}.word-companion-section .word-companion-character-candidate strong{color:var(--companion-ink);font-size:.92rem;line-height:1.2;text-transform:none}.word-companion-section .word-companion-character-candidate em{color:var(--companion-muted);font-size:.76rem;font-style:normal;font-weight:700;line-height:1.25;text-transform:none}.word-companion-connection .word-companion-message{grid-column:auto}.word-companion-section select:disabled{background:var(--companion-soft);color:var(--companion-muted)}.word-companion-section-header{display:flex;align-items:center;justify-content:space-between;gap:7px}.word-companion-header-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:5px}.word-companion-section-header button{min-height:28px;border:1px solid var(--companion-accent);border-radius:6px;padding:4px 7px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.74rem;font-weight:700}.word-companion-actions button:disabled,.word-companion-section-header button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}.word-companion-actions button{min-height:31px;border:1px solid var(--companion-accent);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-accent-dark);font:inherit;font-size:.8rem;font-weight:800}.word-companion-actions .word-companion-primary-action{background:linear-gradient(180deg,#7b5432 0,var(--companion-accent-dark) 100%);color:#fff9ef}.word-companion-link-groups .word-companion-section-header button,.word-companion-structure-preview .word-companion-section-header button{min-height:27px;padding:4px 7px;font-size:.72rem}.word-companion-actions button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-current-scene>button{min-height:34px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fff;color:var(--companion-accent-dark);font:inherit;font-size:.84rem;font-weight:800}.word-companion-current-scene>button:disabled{background:var(--companion-soft);color:var(--companion-muted)}.word-companion-current-scene>.word-companion-danger-action{border-color:#fecaca;color:#b91c1c}.word-companion-current-scene>.word-companion-danger-action:hover:not(:disabled){border-color:#ef4444;background:#fef2f2}.word-companion-maintenance .word-companion-danger-action{border-color:#fecaca;color:#b91c1c}.word-companion-maintenance .word-companion-danger-action:hover:not(:disabled){border-color:#ef4444;background:#fef2f2}.word-companion-marker-status{display:grid;grid-template-columns:1fr;gap:6px}.word-companion-marker-status div{display:flex;align-items:center;justify-content:space-between;gap:8px;border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:6px 8px;background:#fffdf8}.word-companion-marker-status span{color:var(--companion-muted);font-size:.76rem;font-weight:800;text-transform:uppercase}.word-companion-dialog-marker-status{margin:2px 0}.word-companion-maintenance-group{display:grid;gap:8px;border:1px solid rgba(111,75,45,.16);border-radius:8px;padding:9px;background:#fffdf8}.word-companion-maintenance-group-strong{border-color:#fecaca;background:#fff8f6}.word-companion-maintenance-group p{margin:3px 0 0;color:var(--companion-muted);font-size:.84rem}.word-companion-maintenance-group button{width:100%;min-height:31px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-accent-dark);font:inherit;font-size:.8rem;font-weight:800}.word-companion-message:empty{display:none}.word-companion-section strong{min-width:0;font-size:.96rem;overflow-wrap:anywhere}.word-companion-metrics,.word-companion-scene-card,.word-companion-structure-grid{display:grid;gap:8px}.word-companion-scene-card{border:1px solid rgba(111,75,45,.2);border-radius:8px;padding:10px;background:var(--companion-soft)}.word-companion-scene-summary{gap:8px}.word-companion-title-row strong{color:var(--companion-accent-dark);font-size:1rem;line-height:1.25}.word-companion-badges{display:flex;flex-wrap:wrap;gap:6px}.word-companion-badge{display:inline-flex;align-items:center;gap:4px;width:fit-content;min-height:24px;border:1px solid rgba(111,75,45,.24);border-radius:999px;padding:3px 8px;background:#fffaf2;color:var(--companion-accent-dark)!important;font-size:.74rem!important;font-weight:800!important;text-transform:none!important}.word-companion-badge strong{color:var(--companion-accent-dark);font-size:inherit}.word-companion-link-context{margin:-2px 0 2px;border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px 8px;background:var(--companion-soft);color:var(--companion-accent-dark);font-size:.82rem;font-weight:700}.word-companion-diagnostics-grid div,.word-companion-metrics div,.word-companion-scene-card div,.word-companion-structure-grid div,.word-companion-sync-meta div{display:grid;gap:2px}.word-companion-metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.word-companion-metrics div{border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px;background:#fffdf8}.word-companion-metrics strong{color:var(--companion-accent-dark);font-size:.91rem}.word-companion-sync-meta{display:grid;gap:8px;grid-template-columns:1fr 1fr}.word-companion-diagnostics-grid{display:grid;gap:8px;grid-template-columns:1fr 1fr}.word-companion-diagnostics-grid strong{font-size:.88rem}.word-companion-link-groups,.word-companion-resolve-diagnostics,.word-companion-scene-details{display:grid;gap:7px}.word-companion-link-groups div,.word-companion-resolve-diagnostics div,.word-companion-scene-details div{display:grid;gap:3px}.word-companion-review-group{display:grid;gap:7px;border:1px solid rgba(111,75,45,.16);border-radius:7px;padding:8px;background:#fffdf8}.word-companion-review-group summary{cursor:pointer;color:var(--companion-accent-dark);font-size:.9rem;font-weight:800}.word-companion-review-group:not([open])>:not(summary){display:none!important}.word-companion-review-group label{margin-top:6px}.word-companion-resolve-diagnostics{padding-top:4px;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 7px}.word-companion-resolve-diagnostics div{min-width:0;border-bottom:1px solid rgba(225,211,191,.6);padding-bottom:4px}.word-companion-resolve-diagnostics strong{color:var(--companion-ink);font-size:.8rem;line-height:1.25}.word-companion-resolve-diagnostics span{font-size:.68rem;letter-spacing:.01em}.word-companion-progress-sync{display:grid;gap:8px;border-top:1px solid var(--companion-line);padding-top:8px}.word-companion-progress-grid{display:grid;gap:8px}.word-companion-progress-grid div{display:grid;gap:3px}.word-companion-progress-grid strong{font-size:.88rem}.word-companion-brief{display:grid;gap:5px}.word-companion-brief p{margin:0;border:1px solid var(--companion-line);border-radius:6px;padding:9px;background:var(--companion-soft);color:var(--companion-ink);font-size:.9rem;line-height:1.35;white-space:pre-wrap}.word-companion-check-list{display:grid;gap:.75rem}.word-companion-check-item{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.75rem;min-height:42px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:.75rem;background:#fffdf8;color:var(--companion-ink);font-size:.9rem}.word-companion-check-item input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-check-item span{color:var(--companion-ink);font-size:.9rem;font-weight:600;text-transform:none}.word-companion-check-item:has(input:disabled){background:var(--companion-soft);color:var(--companion-muted)}.word-companion-create-link{border-color:rgba(182,138,70,.45);background:#fff8ec}.word-companion-advanced{border:0;border-top:1px solid var(--companion-line);border-radius:0;padding:7px 0 0;background:0 0;box-shadow:none}.word-companion-maintenance-actions{grid-template-columns:1fr}.word-companion-structure-preview{border-color:rgba(182,138,70,.35)}.word-companion-preview-group,.word-companion-preview-groups,.word-companion-preview-item{display:grid;gap:6px}.word-companion-preview-group{border-top:1px solid var(--companion-line);padding-top:7px}.word-companion-preview-group:first-child{border-top:0;padding-top:0}.word-companion-preview-item{border:1px solid rgba(111,75,45,.16);border-radius:6px;padding:7px;background:#fffdf8}.word-companion-preview-item span,.word-companion-preview-matches li{color:var(--companion-ink);font-size:.86rem;font-weight:500;text-transform:none}.word-companion-preview-matches{display:grid;gap:3px}.word-companion-preview-matches ul{display:grid;gap:3px;margin:0;padding-left:18px}.word-companion-apply-summary ul{display:grid;gap:4px;margin:0;padding-left:18px}.word-companion-apply-summary li{color:var(--companion-ink);font-size:.9rem}.word-companion-dialog{width:min(360px,calc(100vw - 24px));border:1px solid var(--companion-line);border-radius:8px;padding:12px;background:var(--companion-panel);color:var(--companion-ink);font-family:"Segoe UI",system-ui,-apple-system,BlinkMacSystemFont,sans-serif}.word-companion-dialog::backdrop{background:rgba(30,37,43,.28)}.word-companion-dialog form{display:grid;gap:8px}.word-companion-dialog strong{min-width:0;overflow-wrap:anywhere}.word-companion-dialog-copy{margin:0;color:var(--companion-muted);font-size:.9rem}.word-companion-dialog-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.word-companion-dialog input[type=search]{width:100%;min-height:36px;border:1px solid var(--companion-line);border-radius:6px;padding:6px 8px;background:#fffdf8;color:var(--companion-ink);font:inherit}.word-companion-dialog button{min-height:32px;border:1px solid var(--companion-accent);border-radius:6px;padding:5px 9px;background:var(--companion-accent);color:#fff9ef;font:inherit;font-size:.82rem;font-weight:700}.word-companion-dialog button:disabled{border-color:var(--companion-line);background:var(--companion-soft);color:var(--companion-muted)}.word-companion-scene-options{display:grid;gap:5px;max-height:220px;overflow-y:auto}.word-companion-scene-option{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:7px;min-height:32px;border:1px solid rgba(111,75,45,.18);border-radius:6px;padding:5px 7px;background:#fffdf8;color:var(--companion-ink);font-size:.9rem}.word-companion-scene-option input{width:16px;height:16px;margin:0;accent-color:var(--companion-accent)}.word-companion-empty-list{margin:0;color:var(--companion-muted);font-size:.88rem}.word-companion-outline{display:grid;gap:7px;padding-top:4px}.word-companion-outline p{margin:0;color:var(--companion-muted);font-size:.9rem}.word-companion-outline-chapter{display:grid;gap:4px}.word-companion-outline-chapter ul{display:grid;gap:3px;margin:0;padding-left:18px}.word-companion-outline-chapter li{color:var(--companion-ink);font-size:.9rem}.word-companion-summary{display:grid;gap:8px;border:1px solid rgba(111,75,45,.18);border-radius:8px;padding:12px;background:var(--companion-soft)}.word-companion-summary div{display:grid;gap:2px}.word-companion-summary strong{min-width:0;font-size:.92rem;overflow-wrap:anywhere}.word-companion-collapsible{gap:8px;background:#fff8ec}.word-companion-collapsible:not([open])>:not(summary){display:none!important}.word-companion-collapsible summary{cursor:pointer;color:var(--companion-ink);font-size:.92rem;font-weight:800;list-style-position:outside}.word-companion-collapsible[open] summary{padding-bottom:6px;border-bottom:1px solid var(--companion-line)}.word-companion-collapsible .word-companion-section-header{padding-top:4px}.word-companion-footer{border-top:1px solid var(--companion-line);padding-top:7px;font-size:.76rem}@media (min-width:390px){.word-companion-connection{grid-template-columns:1fr 1fr}}@media (max-width:340px){.word-companion-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.word-companion-metrics,.word-companion-resolve-diagnostics{grid-template-columns:1fr}.word-companion-actions{grid-template-columns:1fr}}
\ No newline at end of file
diff --git a/PlotLine/wwwroot/js/word-companion-host.js b/PlotLine/wwwroot/js/word-companion-host.js
index 18bc896..bbace1c 100644
--- a/PlotLine/wwwroot/js/word-companion-host.js
+++ b/PlotLine/wwwroot/js/word-companion-host.js
@@ -44,6 +44,9 @@
const unlinkWordDocumentDialog = document.querySelector("[data-unlink-word-document-dialog]");
const unlinkWordDocumentConfirm = document.querySelector("[data-unlink-word-document-confirm]");
const unlinkWordDocumentCancel = document.querySelector("[data-unlink-word-document-cancel]");
+ const cleanUnlinkWordDocumentDialog = document.querySelector("[data-clean-unlink-word-document-dialog]");
+ const cleanUnlinkWordDocumentConfirm = document.querySelector("[data-clean-unlink-word-document-confirm]");
+ const cleanUnlinkWordDocumentCancel = document.querySelector("[data-clean-unlink-word-document-cancel]");
const officeStatus = document.querySelector("[data-office-status]");
const connectionStatus = document.querySelector("[data-connection-status]");
const summaryConnection = document.querySelector("[data-summary-connection]");
@@ -75,6 +78,14 @@
const anchorSceneId = document.querySelector("[data-anchor-scene-id]");
const attachPlotDirectorIdsButton = document.querySelector("[data-attach-plotdirector-ids]");
const unlinkWordDocumentButton = document.querySelector("[data-unlink-word-document]");
+ const cleanUnlinkWordDocumentButton = document.querySelector("[data-clean-unlink-word-document]");
+ const markerBindingStatus = document.querySelector("[data-marker-binding-status]");
+ const markerChapterCount = document.querySelector("[data-marker-chapter-count]");
+ const markerSceneCount = document.querySelector("[data-marker-scene-count]");
+ const unlinkDialogChapterCount = document.querySelector("[data-unlink-dialog-chapter-count]");
+ const unlinkDialogSceneCount = document.querySelector("[data-unlink-dialog-scene-count]");
+ const cleanDialogChapterCount = document.querySelector("[data-clean-dialog-chapter-count]");
+ const cleanDialogSceneCount = document.querySelector("[data-clean-dialog-scene-count]");
const plotDirectorSceneDetails = document.querySelector("[data-plotdirector-scene-details]");
const plotDirectorSceneTitle = document.querySelector("[data-plotdirector-scene-title]");
const plotDirectorRevisionStatus = document.querySelector("[data-plotdirector-revision-status]");
@@ -253,6 +264,34 @@
locations: [],
primaryLocationId: null
};
+ let latestMarkerState = {
+ chapterCount: 0,
+ sceneCount: 0,
+ totalCount: 0,
+ available: false,
+ message: "Not inspected"
+ };
+
+ const plotDirectorMarkerPrefixes = {
+ chapter: "PD-CHAPTER-",
+ scene: "PD-SCENE-"
+ };
+
+ const classifyPlotDirectorContentControl = (control) => {
+ const tag = String(control?.tag || "").trim().toUpperCase();
+ if (tag.startsWith(plotDirectorMarkerPrefixes.chapter)) {
+ return "chapter";
+ }
+ if (tag.startsWith(plotDirectorMarkerPrefixes.scene)) {
+ return "scene";
+ }
+
+ return "";
+ };
+
+ window.PlotDirectorWordMarkers = {
+ classify: classifyPlotDirectorContentControl
+ };
const runtimeDebug = (message) => {
const now = Date.now();
@@ -458,6 +497,112 @@
setHidden(unlinkWordDocumentButton, !firstRunDocumentBinding);
};
+ const updateMarkerStatusDisplay = (state = latestMarkerState) => {
+ const binding = currentDocumentBinding();
+ setText(markerBindingStatus, binding ? "Linked" : "Not linked");
+ setText(markerChapterCount, state.available ? String(state.chapterCount) : "-");
+ setText(markerSceneCount, state.available ? String(state.sceneCount) : "-");
+ setText(unlinkDialogChapterCount, state.available ? String(state.chapterCount) : "-");
+ setText(unlinkDialogSceneCount, state.available ? String(state.sceneCount) : "-");
+ setText(cleanDialogChapterCount, state.available ? String(state.chapterCount) : "-");
+ setText(cleanDialogSceneCount, state.available ? String(state.sceneCount) : "-");
+ if (cleanUnlinkWordDocumentButton) {
+ cleanUnlinkWordDocumentButton.disabled = !wordHostAvailable || !officeReady;
+ }
+ };
+
+ const inspectPlotDirectorMarkers = async () => {
+ if (!officeReady || !wordHostAvailable || !window.Word || typeof window.Word.run !== "function") {
+ latestMarkerState = {
+ chapterCount: 0,
+ sceneCount: 0,
+ totalCount: 0,
+ available: false,
+ message: "Word document access is unavailable."
+ };
+ updateMarkerStatusDisplay();
+ return latestMarkerState;
+ }
+
+ try {
+ latestMarkerState = await window.Word.run(async (context) => {
+ const controls = context.document.contentControls;
+ controls.load("items/tag,title");
+ await context.sync();
+
+ let chapterCount = 0;
+ let sceneCount = 0;
+ for (const control of controls.items || []) {
+ const markerType = classifyPlotDirectorContentControl(control);
+ if (markerType === "chapter") {
+ chapterCount += 1;
+ } else if (markerType === "scene") {
+ sceneCount += 1;
+ }
+ }
+
+ return {
+ chapterCount,
+ sceneCount,
+ totalCount: chapterCount + sceneCount,
+ available: true,
+ message: "Marker inspection complete."
+ };
+ });
+ updateMarkerStatusDisplay(latestMarkerState);
+ return latestMarkerState;
+ } catch (error) {
+ console.error("Unable to inspect PlotDirector markers.", error);
+ latestMarkerState = {
+ chapterCount: 0,
+ sceneCount: 0,
+ totalCount: 0,
+ available: false,
+ message: `Unable to inspect markers: ${errorText(error)}`
+ };
+ updateMarkerStatusDisplay();
+ throw error;
+ }
+ };
+
+ const removePlotDirectorContentControlsPreservingContent = async () => {
+ if (!officeReady || !wordHostAvailable || !window.Word || typeof window.Word.run !== "function") {
+ throw new Error("Word document access is unavailable.");
+ }
+
+ return await window.Word.run(async (context) => {
+ const controls = context.document.contentControls;
+ controls.load("items/tag,title");
+ await context.sync();
+
+ let chapterCount = 0;
+ let sceneCount = 0;
+ for (const control of controls.items || []) {
+ const markerType = classifyPlotDirectorContentControl(control);
+ if (!markerType) {
+ continue;
+ }
+
+ if (markerType === "chapter") {
+ chapterCount += 1;
+ } else if (markerType === "scene") {
+ sceneCount += 1;
+ }
+
+ control.delete(true);
+ }
+
+ await context.sync();
+ return {
+ chapterCount,
+ sceneCount,
+ totalCount: chapterCount + sceneCount,
+ available: true,
+ message: "PlotDirector markers removed."
+ };
+ });
+ };
+
const setSyncStatus = (message) => {
setText(syncStatus, message);
};
@@ -1165,6 +1310,7 @@
setText(linkedProjectTitle, runtimeProjectTitle());
setText(linkedBookTitle, runtimeBookTitle());
}
+ updateMarkerStatusDisplay();
};
const selectedProject = () => {
@@ -1557,6 +1703,18 @@
});
});
+ const saveWordDocumentIfAvailable = () => new Promise((resolve) => {
+ const document = window.Office?.context?.document;
+ if (!document || typeof document.saveAsync !== "function") {
+ resolve(false);
+ return;
+ }
+
+ document.saveAsync((result) => {
+ resolve(result.status === window.Office.AsyncResultStatus.Succeeded);
+ });
+ });
+
const ensureDocumentGuid = () => {
if (firstRunDocumentBinding?.documentGuid) {
return firstRunDocumentBinding.documentGuid;
@@ -2202,6 +2360,7 @@
await context.sync();
});
+ await inspectPlotDirectorMarkers().catch(() => null);
};
const friendlyScanError = (error) => {
@@ -2924,6 +3083,7 @@
refreshDocumentButton.disabled = false;
refreshDocumentButton.textContent = "Refresh Document Structure";
}
+ await inspectPlotDirectorMarkers().catch(() => null);
}
};
@@ -3138,6 +3298,7 @@
await context.sync();
});
+ await inspectPlotDirectorMarkers().catch(() => null);
};
const resultSummaryText = (summary) =>
@@ -3409,7 +3570,7 @@
const requestUnlinkWordDocumentConfirmation = () => new Promise((resolve) => {
if (!unlinkWordDocumentDialog || typeof unlinkWordDocumentDialog.showModal !== "function") {
- resolve(window.confirm("This will remove PlotDirector binding metadata from this Word document.\n\nIf PlotDirector is reachable, it will also unlink this Book in PlotDirector.\n\nYour manuscript text will not be changed.\n\nContinue?"));
+ resolve(window.confirm(`This will remove PlotDirector binding metadata from this Word document and unlink this Book in PlotDirector.\n\nHidden PlotDirector anchors will be left in place for possible reuse.\n\nCurrent marker count:\n${latestMarkerState.chapterCount} chapter markers\n${latestMarkerState.sceneCount} scene markers\n\nYour manuscript text will not be changed.\n\nContinue?`));
return;
}
@@ -3433,6 +3594,33 @@
unlinkWordDocumentDialog.showModal();
});
+ const requestCleanUnlinkWordDocumentConfirmation = () => new Promise((resolve) => {
+ const message = `This will remove PlotDirector hidden anchors from this Word document while preserving manuscript text.\n\nThis will remove:\n${latestMarkerState.chapterCount} PlotDirector chapter markers\n${latestMarkerState.sceneCount} PlotDirector scene markers\nthe document's PlotDirector binding\n\nThe document can be linked again later if desired.\n\nContinue?`;
+ if (!cleanUnlinkWordDocumentDialog || typeof cleanUnlinkWordDocumentDialog.showModal !== "function") {
+ resolve(window.confirm(message));
+ return;
+ }
+
+ const cleanup = (confirmed) => {
+ cleanUnlinkWordDocumentConfirm?.removeEventListener("click", confirmHandler);
+ cleanUnlinkWordDocumentCancel?.removeEventListener("click", cancelHandler);
+ cleanUnlinkWordDocumentDialog?.removeEventListener("cancel", cancelEventHandler);
+ cleanUnlinkWordDocumentDialog?.close();
+ resolve(confirmed);
+ };
+ const confirmHandler = () => cleanup(true);
+ const cancelHandler = () => cleanup(false);
+ const cancelEventHandler = (event) => {
+ event.preventDefault();
+ cleanup(false);
+ };
+
+ cleanUnlinkWordDocumentConfirm?.addEventListener("click", confirmHandler);
+ cleanUnlinkWordDocumentCancel?.addEventListener("click", cancelHandler);
+ cleanUnlinkWordDocumentDialog?.addEventListener("cancel", cancelEventHandler);
+ cleanUnlinkWordDocumentDialog.showModal();
+ });
+
const importFirstRunManuscript = async () => {
const project = selectedFirstRunProject();
const book = selectedFirstRunBook();
@@ -3740,6 +3928,12 @@
return;
}
+ try {
+ await inspectPlotDirectorMarkers();
+ } catch {
+ setDocumentMessage("Marker counts are unavailable. You can still unlink without removing hidden anchors.");
+ }
+
const confirmed = await requestUnlinkWordDocumentConfirmation();
if (!confirmed) {
setDocumentMessage("Unlink cancelled.");
@@ -3758,6 +3952,7 @@
bookId: binding.bookId
});
await removeDocumentBinding();
+ await inspectPlotDirectorMarkers().catch(() => null);
await returnToUnboundOnboarding("Manuscript unlinked.");
} catch (error) {
console.error("Unable to unlink manuscript binding.", error);
@@ -3766,6 +3961,7 @@
if (removeLocalOnly) {
try {
await removeDocumentBinding();
+ await inspectPlotDirectorMarkers().catch(() => null);
await returnToUnboundOnboarding("Word metadata removed. Unlink the Book manually in PlotDirector if it still shows as linked.");
} catch (metadataError) {
console.error("Unable to remove Word document metadata.", metadataError);
@@ -3777,12 +3973,100 @@
} finally {
if (unlinkWordDocumentButton) {
unlinkWordDocumentButton.disabled = false;
- unlinkWordDocumentButton.textContent = "Unlink this Word document";
+ unlinkWordDocumentButton.textContent = "Unlink from PlotDirector";
}
updateUnlinkWordDocumentButton();
}
};
+ const cleanAndUnlinkWordDocument = async () => {
+ console.debug("Word Companion clean and unlink clicked");
+ const binding = currentDocumentBinding();
+
+ if (!officeReady || !wordHostAvailable || !window.Word || typeof window.Word.run !== "function") {
+ setDocumentMessage("Word document access is unavailable.");
+ return;
+ }
+
+ setDocumentMessage("Inspecting PlotDirector markers...");
+ try {
+ await inspectPlotDirectorMarkers();
+ } catch (error) {
+ setDocumentMessage(`Unable to inspect markers: ${errorText(error)}`);
+ return;
+ }
+
+ const confirmed = await requestCleanUnlinkWordDocumentConfirmation();
+ if (!confirmed) {
+ setDocumentMessage("Clean and unlink cancelled.");
+ return;
+ }
+
+ if (cleanUnlinkWordDocumentButton) {
+ cleanUnlinkWordDocumentButton.disabled = true;
+ cleanUnlinkWordDocumentButton.textContent = "Cleaning...";
+ }
+ if (unlinkWordDocumentButton) {
+ unlinkWordDocumentButton.disabled = true;
+ }
+
+ try {
+ setDocumentMessage("Removing PlotDirector hidden anchors...");
+ await removePlotDirectorContentControlsPreservingContent();
+ await saveWordDocumentIfAvailable();
+ try {
+ await inspectPlotDirectorMarkers();
+ } catch (verificationError) {
+ console.error("Unable to verify PlotDirector marker cleanup.", verificationError);
+ setDocumentMessage(`PlotDirector markers were removed, but cleanup verification failed: ${errorText(verificationError)}`);
+ return;
+ }
+
+ if (latestMarkerState.available && latestMarkerState.totalCount > 0) {
+ setDocumentMessage(`Cleanup stopped: ${latestMarkerState.totalCount} PlotDirector marker${latestMarkerState.totalCount === 1 ? "" : "s"} remain.`);
+ return;
+ }
+
+ setDocumentMessage("Removing PlotDirector binding metadata...");
+ try {
+ await removeDocumentBinding();
+ } catch (metadataError) {
+ console.error("Unable to remove Word document metadata after marker cleanup.", metadataError);
+ setDocumentMessage(`PlotDirector markers were removed, but Word binding metadata remains: ${errorText(metadataError)}`);
+ return;
+ }
+
+ let serverMessage = "";
+ if (binding?.documentGuid && Number.isInteger(binding.bookId) && binding.bookId > 0) {
+ try {
+ await postJson("/api/word-companion/manuscript/unlink", {
+ documentGuid: binding.documentGuid,
+ bookId: binding.bookId
+ });
+ } catch (serverError) {
+ console.error("Word document cleaned, but PlotDirector server unlink failed.", serverError);
+ serverMessage = " Word document is clean, but unlink the Book manually in PlotDirector if it still shows as linked.";
+ }
+ }
+
+ await inspectPlotDirectorMarkers().catch(() => null);
+ await returnToUnboundOnboarding(`Word document cleaned and unlinked.${serverMessage}`);
+ } catch (error) {
+ console.error("Unable to clean PlotDirector markers.", error);
+ setDocumentMessage(`Cleanup failed before unlinking: ${errorText(error)}`);
+ } finally {
+ if (cleanUnlinkWordDocumentButton) {
+ cleanUnlinkWordDocumentButton.disabled = false;
+ cleanUnlinkWordDocumentButton.textContent = "Clean and unlink";
+ }
+ if (unlinkWordDocumentButton) {
+ unlinkWordDocumentButton.disabled = false;
+ }
+ updateUnlinkWordDocumentButton();
+ updateMarkerStatusDisplay();
+ }
+ };
+
const patchJson = (url, body) => fetchJson(url, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
@@ -3953,6 +4237,7 @@
ensureAnchorControl(sceneParagraph, "PlotDirector Scene", `PD-SCENE-${resolvedSceneId}`, "PD-SCENE");
await context.sync();
});
+ await inspectPlotDirectorMarkers().catch(() => null);
detectedChapterAnchorId = resolvedChapterId;
detectedSceneAnchorId = resolvedSceneId;
@@ -4005,6 +4290,7 @@
ensureAnchorControl(chapterParagraph, "PlotDirector Chapter", `PD-CHAPTER-${resolvedChapterId}`, "PD-CHAPTER");
await context.sync();
});
+ await inspectPlotDirectorMarkers().catch(() => null);
detectedChapterAnchorId = resolvedChapterId;
storedAnchorInvalid = false;
@@ -5701,6 +5987,7 @@
saveSceneLinksButton?.addEventListener("click", saveSceneLinks);
attachPlotDirectorIdsButton?.addEventListener("click", attachPlotDirectorIds);
unlinkWordDocumentButton?.addEventListener("click", unlinkThisWordDocument);
+ cleanUnlinkWordDocumentButton?.addEventListener("click", cleanAndUnlinkWordDocument);
createPlotDirectorChapterButton?.addEventListener("click", createPlotDirectorChapter);
linkExistingChapterButton?.addEventListener("click", openLinkExistingChapterDialog);
linkChapterSearch?.addEventListener("input", renderLinkChapterOptions);
@@ -5760,6 +6047,7 @@
setDocumentMessage("Word document access is unavailable.");
setSceneTrackingState("Manual");
} else {
+ await inspectPlotDirectorMarkers().catch(() => null);
setupSelectionTracking();
}
})
diff --git a/PlotLine/wwwroot/js/word-companion-host.min.js b/PlotLine/wwwroot/js/word-companion-host.min.js
index d0b4fea..c6cd941 100644
--- a/PlotLine/wwwroot/js/word-companion-host.min.js
+++ b/PlotLine/wwwroot/js/word-companion-host.min.js
@@ -1,25 +1 @@
-(()=>{const s={projectId:"plotdirector.word.projectId",bookId:"plotdirector.word.bookId",activeTab:"plotdirector.word.activeTab"},bi={documentGuid:"plotdirector.word.documentGuid",bookId:"plotdirector.word.boundBookId",projectId:"plotdirector.word.boundProjectId",bindingVersion:"plotdirector.word.bindingVersion"},pl=new Set(["scene","review","maintenance","diagnostics"]),th=document.querySelector(".word-companion-shell"),wp=document.querySelector(".word-companion-tabs"),ih=[...document.querySelectorAll("[data-tab-button]")],wl=[...document.querySelectorAll("[data-tab-panel]")],bp=document.querySelector("[data-linked-manuscript-card]"),kp=document.querySelector("[data-linked-project-title]"),dp=document.querySelector("[data-linked-book-title]"),gp=document.querySelector("[data-first-run-wizard]"),et=document.querySelector("[data-first-run-project-select]"),g=document.querySelector("[data-first-run-book-select]"),te=document.querySelector("[data-first-run-new-book-title]"),oo=document.querySelector("[data-first-run-create-book]"),sr=document.querySelector("[data-first-run-scan]"),nw=document.querySelector("[data-first-run-cancel]"),tw=document.querySelector("[data-first-run-status]"),hr=document.querySelector("[data-first-run-summary]"),ku=document.querySelector("[data-first-run-character-section]"),du=document.querySelector("[data-first-run-character-status]"),ki=document.querySelector("[data-first-run-character-candidates]"),gu=document.querySelector("[data-first-run-character-actions]"),so=document.querySelector("[data-first-run-create-characters]"),bl=document.querySelector("[data-first-run-skip-characters]"),kl=document.querySelector("[data-first-run-continue]"),rh=document.querySelector("[data-first-run-import-actions]"),uh=document.querySelector("[data-first-run-import]"),iw=document.querySelector("[data-first-run-import-cancel]"),nf=document.querySelector("[data-first-run-replace-dialog]"),dl=document.querySelector("[data-first-run-replace-confirm]"),gl=document.querySelector("[data-first-run-replace-cancel]"),tf=document.querySelector("[data-unlink-word-document-dialog]"),na=document.querySelector("[data-unlink-word-document-confirm]"),ta=document.querySelector("[data-unlink-word-document-cancel]"),ia=document.querySelector("[data-office-status]"),ra=document.querySelector("[data-connection-status]"),ua=document.querySelector("[data-summary-connection]"),fa=document.querySelector("[data-summary-project]"),ea=document.querySelector("[data-summary-book]"),p=document.querySelector("[data-project-select]"),ot=document.querySelector("[data-book-select]"),rw=document.querySelector("[data-runtime-book-selectors]"),oa=document.querySelector("[data-project-message]"),sa=document.querySelector("[data-book-message]"),ho=document.querySelector("[data-refresh-current-scene]"),tu=document.querySelector("[data-refresh-document]"),ha=document.querySelector("[data-current-chapter]"),ca=document.querySelector("[data-current-scene]"),la=document.querySelector("[data-current-word-count]"),aa=document.querySelector("[data-scene-tracking-status]"),va=document.querySelector("[data-document-message]"),ya=document.querySelector("[data-sync-note]"),ie=document.querySelector("[data-document-outline]"),cr=document.querySelector("[data-analyse-manuscript-structure]"),fh=document.querySelector("[data-apply-structure-sync]"),uw=document.querySelector("[data-structure-preview-status]"),rf=document.querySelector("[data-structure-preview-results]"),iu=document.querySelector("[data-refresh-plotdirector-scene]"),pa=document.querySelector("[data-plotdirector-scene-status]"),fw=document.querySelector("[data-anchor-status]"),ew=document.querySelector("[data-anchor-book-id]"),ow=document.querySelector("[data-anchor-chapter-id]"),sw=document.querySelector("[data-anchor-scene-id]"),ai=document.querySelector("[data-attach-plotdirector-ids]"),lr=document.querySelector("[data-unlink-word-document]"),wa=document.querySelector("[data-plotdirector-scene-details]"),ba=document.querySelector("[data-plotdirector-scene-title]"),ka=document.querySelector("[data-plotdirector-revision-status]"),da=document.querySelector("[data-plotdirector-estimated-words]"),eh=document.querySelector("[data-plotdirector-actual-words]"),ga=document.querySelector("[data-plotdirector-blocked-status]"),oh=document.querySelector("[data-plotdirector-blocked-reason-row]"),sh=document.querySelector("[data-plotdirector-blocked-reason]"),nv=document.querySelector("[data-runtime-last-sync]"),ar=document.querySelector("[data-sync-scene-progress]"),hw=document.querySelector("[data-sync-word-count]"),hh=document.querySelector("[data-sync-plotdirector-count]"),tv=document.querySelector("[data-sync-last-synced]"),cw=document.querySelector("[data-sync-status]"),iv=document.querySelector("[data-writing-brief-block]"),rv=document.querySelector("[data-writing-brief]"),uv=document.querySelector("[data-plotdirector-link-groups]"),lw=document.querySelector("[data-character-review-summary]"),aw=document.querySelector("[data-asset-review-summary]"),vw=document.querySelector("[data-location-review-summary]"),re=document.querySelector("[data-character-chips]"),ue=document.querySelector("[data-asset-chips]"),btt=document.querySelector("[data-location-chips]"),vr=document.querySelector("[data-primary-location-select]"),di=document.querySelector("[data-save-scene-links]"),yw=document.querySelector("[data-scene-links-status]"),fv=document.querySelector("[data-links-editing-scene]"),ev=document.querySelector("[data-chapter-create-link]"),pw=document.querySelector("[data-chapter-create-link-chapter]"),yt=document.querySelector("[data-create-plotdirector-chapter]"),pt=document.querySelector("[data-link-existing-chapter]"),ww=document.querySelector("[data-chapter-create-link-status]"),ov=document.querySelector("[data-scene-create-link]"),bw=document.querySelector("[data-create-link-chapter]"),kw=document.querySelector("[data-create-link-scene]"),wt=document.querySelector("[data-create-plotdirector-scene]"),bt=document.querySelector("[data-link-existing-scene]"),dw=document.querySelector("[data-create-link-status]"),yr=document.querySelector("[data-link-existing-dialog]"),co=document.querySelector("[data-link-scene-search]"),lo=document.querySelector("[data-link-scene-options]"),oi=document.querySelector("[data-link-selected-scene]"),gw=document.querySelector("[data-link-dialog-cancel]"),ch=document.querySelector("[data-link-dialog-status]"),gi=document.querySelector("[data-create-scene-dialog]"),nb=document.querySelector("[data-create-dialog-scene]"),tb=document.querySelector("[data-create-dialog-chapter]"),ib=document.querySelector("[data-create-dialog-confirm]"),rb=document.querySelector("[data-create-dialog-cancel]"),pr=document.querySelector("[data-link-existing-chapter-dialog]"),ao=document.querySelector("[data-link-chapter-search]"),vo=document.querySelector("[data-link-chapter-options]"),si=document.querySelector("[data-link-selected-chapter]"),ub=document.querySelector("[data-link-chapter-dialog-cancel]"),lh=document.querySelector("[data-link-chapter-dialog-status]"),nr=document.querySelector("[data-create-chapter-dialog]"),fb=document.querySelector("[data-create-chapter-dialog-chapter]"),eb=document.querySelector("[data-create-chapter-dialog-book]"),ob=document.querySelector("[data-create-chapter-dialog-confirm]"),sb=document.querySelector("[data-create-chapter-dialog-cancel]"),tr=document.querySelector("[data-apply-structure-sync-dialog]"),ah=document.querySelector("[data-apply-structure-sync-summary]"),hb=document.querySelector("[data-apply-structure-sync-confirm]"),cb=document.querySelector("[data-apply-structure-sync-cancel]"),lb=document.querySelector("[data-resolve-project-id]"),ab=document.querySelector("[data-resolve-project-title]"),vb=document.querySelector("[data-resolve-book-id]"),yb=document.querySelector("[data-resolve-book-title]"),pb=document.querySelector("[data-resolve-detected-chapter]"),wb=document.querySelector("[data-resolve-detected-scene]"),bb=document.querySelector("[data-resolve-request-chapter]"),kb=document.querySelector("[data-resolve-request-scene]"),db=document.querySelector("[data-resolve-result]"),gb=document.querySelector("[data-resolve-chapter-id]"),nk=document.querySelector("[data-resolve-scene-id]"),ru=document.querySelector("[data-run-diagnostics]"),tk=document.querySelector("[data-diagnostic-host]"),ik=document.querySelector("[data-diagnostic-platform]"),rk=document.querySelector("[data-diagnostic-ready]"),uk=document.querySelector("[data-diagnostic-word-api]"),fk=document.querySelector("[data-diagnostic-last-scan]"),ek=document.querySelector("[data-diagnostic-last-error]"),ok=document.querySelector("[data-diagnostic-anchor-type]"),sk=document.querySelector("[data-diagnostic-stored-scene-id]"),hk=document.querySelector("[data-diagnostic-stored-chapter-id]"),ck=document.querySelector("[data-diagnostic-resolution-method]"),lk=document.querySelector("[data-diagnostic-paragraphs]"),ak=document.querySelector("[data-diagnostic-heading1]"),vk=document.querySelector("[data-diagnostic-heading2]"),uf=th?.dataset.authenticated==="true",vh=Number.parseInt(th?.dataset.userId||"",10),yk=String(th?.dataset.companionVersion||"20C").trim();let ir=[],ii=[],kt=!1,nt=!1,yo="Unknown",po="Unknown",w="",rt="",sv=null,fe=null,b=null,tt=null,u=null,o=null,ee="",rr="Title Match",dt=!1,yh=[],oe=null,wo=null,ph=[],se=null,bo=null,vi=null,ri=null,ur=null,l=null,he=null,ko=null,wr=null,ce=null,hi=[],go=null,ns=!1,ff=!1,le=0,ae=!1,wh=!1,ve=!1,ts=null,bh="Manual",ht=!1,uu=null,br=!1,hv=0,ef=!1,ye=0,pe=null;const we=1200;let kh=!1,is=!1,be=null,sf=!1,ke=!1,dh=null,gh=null,de=null,hf=!1,cf=!1,nc=null,tc="",lf=[],ic=null,rc="",uc=null,fc="",fu=[],ec=null,oc="",sc=null,hc="",eu=[],cc=null,lc="",ac="",rs="",vc="",cv=0,d=null,ou=null,ct={characters:[],assets:[],locations:[],primaryLocationId:null};const i=n=>{const t=Date.now();t-cv<1e3||(cv=t,console.debug(`[Word Companion Runtime] ${n}`))},ci=n=>{console.debug(`[Word Companion Timing] ${n}`)},yc=n=>{ia&&(ia.textContent=n)},pk=n=>{try{return window.localStorage.getItem(n)||""}catch{return""}},wk=(n,t)=>{try{t?window.localStorage.setItem(n,String(t)):window.localStorage.removeItem(n)}catch{}},lv=n=>n==="links"?"review":n==="structure"?"maintenance":n,av=(n,t=true)=>{const i=lv(n),r=pl.has(i)&&ih.some(n=>n.dataset.tabButton===i)?i:"scene";for(const n of ih){const t=n.dataset.tabButton===r;n.classList.toggle("is-active",t);n.setAttribute("aria-selected",t?"true":"false")}for(const n of wl){const t=n.dataset.tabPanel===r;n.classList.toggle("is-active",t);n.hidden=!t}t&&wk(s.activeTab,r)},vv=()=>{const n=lv(pk(s.activeTab));av(pl.has(n)?n:"scene",!1)},ge=n=>{ra&&(ra.textContent=n),ua&&(ua.textContent=n)},pc=n=>{oa&&(oa.textContent=n)},af=n=>{sa&&(sa.textContent=n)},t=n=>{va&&(va.textContent=n)},vf=n=>{pa&&(pa.textContent=n)},wc=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("anchorType")&&n(ok,a(t.anchorType));i("storedSceneId")&&n(sk,a(t.storedSceneId));i("storedChapterId")&&n(hk,a(t.storedChapterId));i("resolutionMethod")&&n(ck,a(t.resolutionMethod))},fr=()=>{const i=h(),f=Number.isInteger(u)&&u>0&&tt===u,e=!Number.isInteger(o)||o<=0||b===o,t=f&&e;n(fw,t?"Attached to PlotDirector":"Not attached");n(ew,i?.bookId?String(i.bookId):"-");n(ow,Number.isInteger(o)&&o>0?String(o):"-");n(sw,Number.isInteger(u)&&u>0?String(u):"-");ai&&(r(ai,t&&!dt),ai.disabled=!u||t&&!dt,ai.textContent=tt&&!t?"Reattach PlotDirector IDs":"Attach PlotDirector IDs");wc({anchorType:rr||"Title Match",storedSceneId:tt,storedChapterId:b,resolutionMethod:ee})},yf=(t,i,r,u=null,f=null,e=null)=>{const o=t||"",s=i||"",h=Number.isInteger(r)?r:null,c=Number.isInteger(e)&&e>0?e:null,l=Number.isInteger(u)&&u>0?u:null,a=Number.isInteger(f)&&f>0?f:null,v=w===o&&rt===s&&sv===h&&fe===c&&b===l&&tt===a;(w=t||"",rt=i||"",sv=Number.isInteger(r)?r:null,fe=Number.isInteger(e)&&e>0?e:null,b=Number.isInteger(u)&&u>0?u:null,tt=Number.isInteger(f)&&f>0?f:null,v)||(ha&&(ha.textContent=t||"Not detected"),ca&&(ca.textContent=i||"Not detected"),la&&(la.textContent=Number.isInteger(r)?String(r):"-"),n(hw,Number.isInteger(r)?String(r):"-"),fr())},pf=()=>{be&&(window.clearTimeout(be),be=null)},r=(n,t)=>{n&&(n.hidden=t)},bc=()=>{r(lr,!ri)},gt=t=>{n(cw,t)},er=t=>{n(uw,t)},wf=(n="Select a project and book to analyse manuscript structure.")=>{if(vi=null,rf){rf.innerHTML="";const n=document.createElement("p");n.textContent="No preview generated.";rf.append(n)}er(n);us()},bk=(n=vi)=>yy.flatMap(t=>Array.isArray(n?.[t.key])?n[t.key]:[]),su=(n=vi)=>bk(n).filter(n=>n.category==="couldLink"||n.category==="wouldCreateChapters"||n.category==="wouldCreateScenes"),us=()=>{fh&&(fh.disabled=ve||su().length===0)},fs=()=>{cr&&(cr.disabled=ve||!ni()||!h()),us()},kc=()=>{fv&&(fv.textContent=u?`Editing links for: ${rs||rt||"Current scene"}`:"Link a PlotDirector scene first.")},dc=()=>{const n=ht||!u,t=n||!o||sf;ar&&(ar.disabled=t);di&&(di.disabled=n);vr&&(vr.disabled=n);for(const t of[re,ue])for(const i of t?[...t.querySelectorAll("input[type='checkbox']")]:[])i.disabled=n},k=t=>{(t==="Live"||t==="Manual")&&(bh=t),n(aa,t||bh||"Manual")},li=(i,r="")=>{ht=!!i,ht&&(pf(),fo()),n(aa,ht?"Stale":bh),dc(),r&&(t(r),cu(r))},kr=(n,t=null,i="")=>{u=Number.isInteger(n)&&n>0?n:null,o=Number.isInteger(t)&&t>0?t:null,ee=i||"",u!==dh&&(gh=null),u||(pf(),fo()),dc(),gt(ht?"Refresh Current Scene before syncing.":u?"Ready to sync.":"No resolved PlotDirector scene."),cu(ht?"Refresh Current Scene before saving.":u?"Ready to save.":"Link a PlotDirector scene first."),kc(),fr()},yv=n=>{ho&&(ho.disabled=n,ho.textContent=n?"Refreshing...":"Refresh Current Scene")},a=n=>n===null||n===undefined||n===""?"-":String(n),ktt=n=>{if(!n)return"-";const t=new Date(n);return Number.isNaN(t.getTime())?"-":t.toLocaleString()},es=n=>{if(!n)return"-";const t=n instanceof Date?n:new Date(n);if(Number.isNaN(t.getTime()))return"-";const i=new Date,r=t.toDateString()===i.toDateString()?"Today":t.toLocaleDateString();return`Last synced: ${r} ${t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`},pv=t=>{ur=t||null;const i=ur?.lastSyncUtc||ur?.manuscriptDocument?.lastSyncUtc;n(nv,es(i));n(tv,es(i));tl()},bf=()=>{l=null,he=null,ko=null,ye+=1,pe=null,gn(),ntt(),ttt(),pv(null)},hu=()=>{he=null,ko=null},cu=t=>{n(yw,t)},lu=t=>{n(dw,t)},yi=t=>{n(ww,t)},gc=()=>!!h()&&!!w&&!o,nl=()=>!!h()&&!!rt&&Number.isInteger(o)&&o>0,no=()=>{r(ev,!0),yi(""),yt&&(yt.disabled=!0,yt.textContent="Create Chapter in PlotDirector"),pt&&(pt.disabled=!0,pt.textContent="Link to Existing Chapter")},os=(t="")=>{n(pw,a(w));r(ev,!1);yi(t);const i=gc();yt&&(yt.disabled=!i,yt.textContent="Create Chapter in PlotDirector");pt&&(pt.disabled=!i,pt.textContent="Link to Existing Chapter")},ss=()=>{r(ov,!0),lu(""),wt&&(wt.disabled=!0,wt.textContent="Create Scene in PlotDirector"),bt&&(bt.disabled=!0,bt.textContent="Link to Existing Scene")},to=(t="")=>{n(bw,a(w));n(kw,a(rt));r(ov,!1);lu(t);const i=nl();wt&&(wt.disabled=!i,wt.textContent="Create Scene in PlotDirector");bt&&(bt.disabled=!i,bt.textContent="Link to Existing Scene")},it=t=>{vf(t),r(wa,!0),r(iv,!0),r(uv,!1),no(),ss(),ee="",rs="",vc="",rr=tt?"SceneID Anchor":b?"ChapterID Anchor":"Title Match",dt=!1,ct={characters:[],assets:[],locations:[],primaryLocationId:null},cs(re,[],"character"),cs(ue,[],"asset"),wv([],null,!1),ey(),kr(null),n(hh,"-"),n(ba,"-"),n(ka,"-"),n(da,"-"),n(eh,"-"),n(ga,"-"),n(sh,"-"),r(oh,!0),fr(),kc()},hs=(n,t)=>t==="asset"?n?.assetId||n?.AssetId||n?.storyAssetId||n?.StoryAssetId||0:t==="location"?n?.locationId||n?.LocationId||0:n?.characterId||n?.CharacterId||0,cs=(n,t,i,r=false)=>{if(n){n.innerHTML="";const u=Array.isArray(t)?t:[];if(u.length===0){const t=document.createElement("p");t.className="word-companion-empty-list";t.textContent="None";n.append(t);return}for(const t of u){const f=Number.parseInt(hs(t,i),10);if(Number.isInteger(f)&&!(f<=0)){const e=document.createElement("label");e.className="word-companion-check-item";const u=document.createElement("input");u.type="checkbox";u.value=String(f);u.checked=!!t.linked;u.disabled=!r;const o=document.createElement("span");o.textContent=t.name||"Unnamed";e.append(u,o);n.append(e)}}}},wv=(n,t,i=false)=>{if(vr){vr.innerHTML="";const r=document.createElement("option");r.value="";r.textContent="None";vr.append(r);const u=Number.parseInt(t||"",10);for(const t of Array.isArray(n)?n:[]){const n=Number.parseInt(hs(t,"location"),10);if(Number.isInteger(n)&&!(n<=0)){const i=document.createElement("option");i.value=String(n);i.textContent=t.name||"Unnamed";i.selected=n===u;vr.append(i)}}vr.disabled=!i}},kk=t=>{rs=t?.sceneTitle||rt||"",vc=t?.chapterTitle||w||"",n(ba,a(t?.sceneTitle)),n(ka,a(t?.revisionStatus||t?.revisionStatusName||"Not provided")),n(da,a(t?.estimatedWords)),n(eh,a(t?.actualWords)),n(hh,a(t?.actualWords)),n(ga,t?.blocked?"Blocked":"Not blocked"),t?.blockedReason?(n(sh,t.blockedReason),r(oh,!1)):(n(sh,"-"),r(oh,!0)),rv&&(rv.textContent=t?.writingBrief||"No writing brief has been added for this scene."),ct={characters:Array.isArray(t?.characters)?t.characters:[],assets:Array.isArray(t?.assets)?t.assets:[],locations:Array.isArray(t?.locations)?t.locations:[],primaryLocationId:t?.primaryLocationId??null},cs(re,ct.characters,"character",!!u&&!ht),cs(ue,ct.assets,"asset",!!u&&!ht),wv(ct.locations,ct.primaryLocationId,!!u&&!ht),ey(),kc(),cu(ht?"Refresh Current Scene before saving.":u?"Ready to save.":"No resolved PlotDirector scene."),r(wa,!1),r(iv,!1),r(uv,!1)},au=n=>String(n||"").trim().replace(/\s+/g," "),ut=(n,t)=>{const i=au(n);if(!i)return"";const r=t==="scene"?"scene":"chapter",u=new RegExp(`^${r}\\s+${"(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)"}\\s*(?::|-|\\u2013|\\u2014)\\s*`,"i"),f=au(i.replace(u,""));return f||i},vt=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("projectId")&&n(lb,a(t.projectId));i("projectTitle")&&n(ab,a(t.projectTitle));i("bookId")&&n(vb,a(t.bookId));i("bookTitle")&&n(yb,a(t.bookTitle));i("detectedChapter")&&n(pb,a(t.detectedChapter));i("detectedScene")&&n(wb,a(t.detectedScene));i("requestChapter")&&n(bb,a(t.requestChapter));i("requestScene")&&n(kb,a(t.requestScene));i("result")&&n(db,a(t.result));i("chapterId")&&n(gb,a(t.chapterId));i("sceneId")&&n(nk,a(t.sceneId))},dk=async(n,t)=>{const i=await at(`/api/word-companion/books/${n}/structure`),r=Array.isArray(i?.chapters)?i.chapters:[];for(const n of r){const r=Array.isArray(n.scenes)?n.scenes:[],i=r.find(n=>n.sceneId===t);if(i)return i.revisionStatus||""}return""},gk=async(n,t)=>{const i=await at(`/api/word-companion/books/${n}/structure`),r=Array.isArray(i?.chapters)?i.chapters:[];for(const n of r){const i=Array.isArray(n.scenes)?n.scenes:[];for(const r of i)if(t(n,r))return{chapter:n,scene:r}}return null},ls=async n=>{if(ko===n&&Array.isArray(he?.chapters))return he.chapters;const t=await at(`/api/word-companion/books/${n}/structure`);return ko=n,he=t||null,Array.isArray(t?.chapters)?t.chapters:[]},bv=async n=>{const t=await at(`/api/word-companion/books/${n}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},kv=n=>{if(Number.isInteger(o)&&o>0){const t=n.find(n=>n.chapterId===o);if(t)return t}const t=ut(w,"chapter").toLocaleLowerCase();return t?n.find(n=>ut(n.title,"chapter").toLocaleLowerCase()===t)||null:null},dv=async()=>{const n=h();return n?kv(await ls(n.bookId)):null},as=async(n,i,r,u,f)=>{const e=await at(`/api/word-companion/scenes/${i}/companion`);try{e.revisionStatus=await dk(n,i)}catch{e.revisionStatus=""}rr=f||"Title Match";dt=!1;li(!1);vf("Linked to PlotDirector");t("");no();ss();kr(i,r,u);kk(e);rn(i,r);gs();nh()},n=(n,t)=>{if(n){const i=t===null||t===undefined?"":String(t);n.textContent!==i&&(n.textContent=i)}},f=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("host")&&n(tk,t.host);i("platform")&&n(ik,t.platform);i("ready")&&n(rk,t.ready);i("wordApi")&&n(uk,t.wordApi);i("lastScan")&&n(fk,t.lastScan);i("lastError")&&n(ek,t.lastError);i("paragraphs")&&n(lk,t.paragraphs);i("heading1")&&n(ak,t.heading1);i("heading2")&&n(vk,t.heading2)},e=n=>{const t=[];return n?.name&&t.push(n.name),n?.code&&n.code!==n.name&&t.push(n.code),n?.message&&t.push(n.message),n?.debugInfo?.errorLocation&&t.push(`Location: ${n.debugInfo.errorLocation}`),t.length>0?t.join(": "):String(n)},gv=async()=>{if(!window.Office||typeof window.Office.onReady!="function")return kt=!1,nt=!1,yo="Unavailable",po="Unavailable",f({host:yo,platform:po,ready:"No",wordApi:"No"}),null;const n=await window.Office.onReady();return kt=!0,yo=n?.host||"Unknown",po=n?.platform||"Unknown",nt=!!window.Word&&!!window.Office.HostType&&n?.host===window.Office.HostType.Word,f({host:yo,platform:po,ready:"Yes",wordApi:nt?"Yes":"No"}),n},vs=n=>{try{const i=window.localStorage.getItem(n),t=Number.parseInt(i||"",10);return Number.isInteger(t)&&t>0?t:null}catch{return null}},v=(n,t)=>{try{t?window.localStorage.setItem(n,String(t)):window.localStorage.removeItem(n)}catch{}},c=(n,t)=>{if(n){n.innerHTML="";const i=document.createElement("option");i.value="";i.textContent=t;n.append(i);n.disabled=!0}},ys=(n,t,i,r,u)=>{if(n){n.innerHTML="";const f=document.createElement("option");f.value="";f.textContent=t;n.append(f);for(const t of i){const i=document.createElement("option");i.value=String(t[r]);i.textContent=t[u];n.append(i)}n.disabled=i.length===0}},dr=n=>{const t=String(n?.displayTitle||"").trim();if(t)return t;const i=String(n?.title||"").trim(),r=String(n?.subtitle||"").trim();return r?`${i}: ${r}`:i},nd=()=>ur?.projectTitle||ni()?.title||"Project",td=()=>ur?.bookTitle||dr(h())||"Book",tl=()=>{const t=!!ri;r(bp,!t);r(rw,t);t&&(n(kp,nd()),n(dp,td()))},ni=()=>{const n=Number.parseInt(p?.value||"",10);return ir.find(t=>t.projectId===n)||null},h=()=>{const n=Number.parseInt(ot?.value||"",10);return ii.find(t=>t.bookId===n)||null},gr=()=>{const n=Number.parseInt(et?.value||"",10);return ir.find(t=>t.projectId===n)||null},vu=()=>{const n=Number.parseInt(g?.value||"",10);return ii.find(t=>t.bookId===n)||null},id=()=>{const n=ri?.projectId||gr()?.projectId||ni()?.projectId||vs(s.projectId);return Number.isInteger(n)&&n>0?n:null},rd=()=>{const n=ri?.bookId||vu()?.bookId||h()?.bookId||vs(s.bookId);return Number.isInteger(n)&&n>0?n:null},ny=()=>{const n=String(window.Office?.context?.document?.url||"").trim();if(!n)return"";const t=n.split(/[\\/]/).filter(Boolean).pop()||"";try{return decodeURIComponent(t)}catch{return t}},ty=()=>({userID:Number.isInteger(vh)&&vh>0?vh:null,companionVersion:yk,machineName:"",documentOpen:!!nt,currentDocumentName:ny(),linkedProjectID:id(),linkedBookID:rd()}),ud=async()=>{d&&d.state===signalR.HubConnectionState.Connected&&await d.invoke("CompanionHeartbeat",ty())},kf=()=>{ud().catch(n=>{console.debug("Word Companion heartbeat unavailable.",n)})},iy=async()=>{if(uf&&window.signalR&&!d){d=(new signalR.HubConnectionBuilder).withUrl("/hubs/word-companion-follow").withAutomaticReconnect().build();d.onreconnected(kf);d.on("ScanCurrentDocument",n=>{void bd(n)});d.on("UpdateOnboardingBuildMarkers",n=>{void kd(n)});d.onclose(()=>{ou&&(window.clearInterval(ou),ou=null)});await d.start();await d.invoke("RegisterCompanion",ty());ou=window.setInterval(kf,25e3)}};window.addEventListener("beforeunload",()=>{ou&&(window.clearInterval(ou),ou=null),d&&d.stop().catch(()=>{})});const ui=t=>n(tw,t),ft=()=>{const n=gr(),t=vu(),i=ff&&Date.now()-le>=750;sr&&(sr.disabled=!n||!t||ae);oo&&(oo.disabled=!n||!String(te?.value||"").trim()||ae);uh&&(uh.disabled=!wr?.canImport||!ce||ae);so&&(so.disabled=!i||wh||ry().length===0)},yu=n=>{r(gp,!n);r(wp,n);bc();tl();for(const t of wl)r(t,n?!0:t.dataset.tabPanel!=="scene"&&!t.classList.contains("is-active"));n||vv()},il=()=>{if(et){if(ir.length===0){c(et,"No projects available.");return}ys(et,"Choose a project",ir,"projectId","title");const n=Number.parseInt(p?.value||"",10);Number.isInteger(n)&&n>0&&(et.value=String(n))}},fd=(n=null)=>{if(g){if(ii.length===0){c(g,"No books available.");return}ys(g,"Choose a book",ii.map(n=>({...n,displayTitle:dr(n)})),"bookId","displayTitle");const i=n||Number.parseInt(ot?.value||"",10),t=ii.find(n=>n.bookId===i);t&&(g.value=String(t.bookId));ft()}},lt=(t="Select a Project and Book to begin.")=>{wr=null,ce=null,hi=[],ns=!1,ff=!1,le=0,r(hr,!0),r(rh,!0),r(ku,!0),r(gu,!0),hr&&(hr.innerHTML=""),ki&&(ki.innerHTML=""),n(du,""),ui(t),ft()},ry=()=>ki?[...ki.querySelectorAll("input[type='checkbox']:checked")].map(n=>String(n.value||"").trim()).filter(Boolean):[],ed=t=>{if(hi=Array.isArray(t)?t:[],ku&&ki){if(ki.innerHTML="",r(ku,!1),r(gu,!ns||hi.length===0),r(so,!1),r(bl,!1),r(kl,!0),hi.length===0){n(du,"No likely major characters found.");ft();return}n(du,`${hi.length} likely major characters found.`);for(const n of hi){const i=document.createElement("label");i.className="word-companion-character-candidate";const t=document.createElement("input");t.type="checkbox";t.value=n.text||"";t.checked=String(n.confidence||"").trim().toLowerCase()==="high";t.addEventListener("change",ft);const u=document.createElement("strong");u.textContent=n.text||"";const f=document.createElement("em"),e=String(n.reason||"").trim();f.textContent=e?`${Number(n.mentionCount||0).toLocaleString()} mentions · ${e}`:`${Number(n.mentionCount||0).toLocaleString()} mentions`;const r=document.createElement("span");r.className="word-companion-character-candidate-text";r.append(u,f);i.append(t,r);ki.append(i)}ft()}},od=n=>{if(hr){hr.innerHTML="";const t=document.createElement("strong");t.textContent="Manuscript Analysis";hr.append(t);const i=document.createElement("dl"),u=[["Project",n.projectTitle],["Book",dr({title:n.bookTitle,subtitle:n.bookSubtitle})],["Chapters",Number(n.chapterCount||0).toLocaleString()],["Scenes",Number(n.sceneCount||0).toLocaleString()],["Words",Number(n.wordCount||0).toLocaleString()]];for(const[n,t]of u){const r=document.createElement("dt");r.textContent=n;const u=document.createElement("dd");u.textContent=t||"-";i.append(r,u)}hr.append(i);r(hr,!1);r(rh,!1);ui(n.message||"Preview generated.");ft()}},rl=()=>{const n=window.Office?.context?.document?.settings;if(!n)return null;const u=String(n.get(bi.documentGuid)||"").trim(),t=Number.parseInt(n.get(bi.bookId)||"",10),i=Number.parseInt(n.get(bi.projectId)||"",10),r=Number.parseInt(n.get(bi.bindingVersion)||"",10);return!u||!Number.isInteger(t)||t<=0||!Number.isInteger(i)||i<=0?null:{documentGuid:u,bookId:t,projectId:i,bindingVersion:Number.isInteger(r)&&r>0?r:1}},sd=()=>{const i=ri||rl();if(i)return i;const r=ur?.manuscriptDocument?.documentGuid||"",n=Number.parseInt(ur?.bookId||"",10),t=Number.parseInt(ur?.projectId||"",10);return r&&Number.isInteger(n)&&n>0&&Number.isInteger(t)&&t>0?{documentGuid:r,bookId:n,projectId:t,bindingVersion:Number.parseInt(ur?.manuscriptDocument?.bindingVersion||"",10)||1}:null},hd=n=>new Promise((t,i)=>{const r=window.Office?.context?.document?.settings;if(!r){i(new Error("Word document settings are unavailable."));return}r.set(bi.documentGuid,n.documentGuid);r.set(bi.bookId,String(n.bookId));r.set(bi.projectId,String(n.projectId));r.set(bi.bindingVersion,String(n.bindingVersion||1));r.saveAsync(n=>{n.status===window.Office.AsyncResultStatus.Succeeded?t():i(n.error||new Error("Unable to save Word document metadata."))})}),uy=()=>new Promise((n,t)=>{const i=window.Office?.context?.document?.settings;if(!i){t(new Error("Word document settings are unavailable."));return}for(const n of Object.values(bi))typeof i.remove=="function"?i.remove(n):i.set(n,"");i.saveAsync(i=>{i.status===window.Office.AsyncResultStatus.Succeeded?n():t(i.error||new Error("Unable to remove Word document metadata."))})}),fy=()=>ri?.documentGuid?ri.documentGuid:window.crypto?.randomUUID?window.crypto.randomUUID():"10000000-1000-4000-8000-100000000000".replace(/[018]/g,n=>(Number(n)^Math.random()*16>>Number(n)/4).toString(16)),or=()=>ri?.documentGuid||rl()?.documentGuid||"",pi=()=>{const t=ni(),n=h();fa&&(fa.textContent=t?.title||"(Not connected)");ea&&(ea.textContent=n?dr(n):"(Not connected)");ya&&(ya.textContent=n?"":"Select a PlotDirector book before refreshing.");fs();tl()},ey=()=>{const t=Array.isArray(ct.characters)?ct.characters.length:0,i=Array.isArray(ct.assets)?ct.assets.length:0,r=Array.isArray(ct.locations)?ct.locations.length:0;n(lw,`Characters (${t})`);n(aw,`Assets (${i})`);n(vw,`Locations (${r})`)},io=n=>{const t=n?.styleBuiltIn||n?.style||"";return String(t).replace(/\s+/g,"").toLowerCase()},wi=(n,t)=>{const i=io(n);return i===`heading${t}`||i.endsWith(`.heading${t}`)||i.includes(`heading${t}`)},df=n=>{const t=String(n||"").trim().split(/\s+/).filter(Boolean);return t.length},cd=(n,t)=>String(n?.text||"").trim()===String(t?.text||"").trim()&&io(n)===io(t),oy=(n,t)=>{const r=String(n||"").match(new RegExp(`^${t}-(\\d+)$`,"i"));if(!r)return null;const i=Number.parseInt(r[1],10);return Number.isInteger(i)&&i>0?i:null},sy=n=>{try{return Array.isArray(n?.contentControls?.items)?n.contentControls.items:[]}catch(t){return console.warn("Word paragraph content controls were not available.",t),[]}},ps=(n,t)=>{const i=sy(n);for(const n of i){const i=oy(n.tag,t);if(i)return i}return null},ld=(n,t)=>{const u=[];let o=0,s=0,i=null,r=null;n.forEach((n,t)=>{const f=String(n.text||"").trim();if(f){if(wi(n,1)){o+=1;i={index:u.length+1,paragraphIndex:t,title:f,anchorId:ps(n,"PD-CHAPTER"),scenes:[]};u.push(i);r=null;return}if(wi(n,2)){if(s+=1,!i)return;r={index:i.scenes.length+1,paragraphIndex:t,title:f,anchorId:ps(n,"PD-SCENE"),wordCount:0};i.scenes.push(r);return}r&&(r.wordCount+=df(f))}});const h=t.find(n=>String(n.text||"").trim()),f=h?n.findIndex(n=>cd(n,h)):-1,e=f>=0?u.filter(n=>n.paragraphIndex<=f).at(-1)||null:null,c=e&&f>=0?e.scenes.filter(n=>n.paragraphIndex<=f).at(-1)||null:null;return{chapters:u,currentChapter:e,currentScene:c,paragraphCount:n.length,heading1Count:o,heading2Count:s}},ad=(n,t)=>{const r=[];let i=null,u=null,f=0;const e=[],s=new Set(["***","###"]),o=()=>{if(!i)return null;const n={title:`Scene ${i.scenes.length+1}`,sortOrder:(i.scenes.length+1)*10,wordCount:0};return i.scenes.push(n),n};return n.forEach(n=>{const h=String(n.text||"").trim();if(h){if(e.push(h),wi(n,1)){i={title:h,sortOrder:(r.length+1)*10,wordCount:0,scenes:[]};r.push(i);u=o();f+=df(h);return}if(i&&u){if(t&&s.has(h)){u=o();return}const c=df(h);i.wordCount+=c;u.wordCount+=c;f+=c}}}),{chapters:r,chapterCount:r.length,sceneCount:r.reduce((n,t)=>n+t.scenes.length,0),wordCount:f,documentText:e.join("\n")}},ws=new Set(["***","###"]),vd=(n,t)=>{const i=String(n?.text||"").trim();return{index:t,text:i,styleBuiltIn:n?.styleBuiltIn||"",style:n?.style||"",wordCount:df(i),chapterAnchorId:null,sceneAnchorId:null}},hy=(n,t)=>{n&&(n.endParagraphIndex=t)},cy=(n,t)=>{n&&(n.endParagraphIndex=t,hy(n.scenes.at(-1),t))},yd=(n,t)=>{const u=n.map(vd),f=[];let o=0,s=0,i=null,r=null,e=0;const h=(n,t=null,u=null)=>i?(hy(r,n.index-1),r={index:i.scenes.length+1,paragraphIndex:n.index,startParagraphIndex:n.index,endParagraphIndex:n.index,title:t||`Scene ${i.scenes.length+1}`,anchorId:u,wordCount:0},i.scenes.push(r),r):null;for(const n of u)if(n.text){if(wi(n,1)){cy(i,n.index-1);o+=1;i={index:f.length+1,paragraphIndex:n.index,startParagraphIndex:n.index,endParagraphIndex:n.index,title:n.text,anchorId:n.chapterAnchorId,wordCount:0,scenes:[]};f.push(i);r=null;h(n,t?"Scene 1":"Scene 1",n.sceneAnchorId);e+=n.wordCount;continue}if(i){if(t&&ws.has(n.text)){s+=1;h(n);continue}i.wordCount+=n.wordCount;r&&(r.wordCount+=n.wordCount);e+=n.wordCount}}return cy(i,u.length-1),{paragraphs:u,chapters:f,usesExplicitScenes:!!t,paragraphCount:u.length,heading1Count:o,heading2Count:s,documentWordCount:e,currentParagraphIndex:null,currentChapter:null,currentScene:null}},pu=(n,t,i)=>n?.[t]??n?.[i]??null,pd=n=>(Array.isArray(n)?n:[]).map((n,t)=>({temporaryCharacterKey:`character-${t+1}`,name:pu(n,"text","Text")||pu(n,"name","Name")||"",mentionCount:Number.parseInt(pu(n,"mentionCount","MentionCount")||"0",10)||0,qualityScore:Number.parseInt(pu(n,"qualityScore","QualityScore")||"0",10)||0,category:pu(n,"category","Category")||"PossibleCharacter",reason:pu(n,"reason","Reason")||"",isExistingCharacterMatch:!!pu(n,"isExistingCharacterMatch","IsExistingCharacterMatch"),suggestedImportance:null})).filter(n=>n.name),wd=(n,t)=>{const u=[],f=[],s=[];let i=null,r=null,e=0,h=0;const c=()=>{r=null},l=(n,t,r=false)=>(c(),i={temporaryChapterKey:`chapter-${u.length+1}`,chapterNumber:u.length+1,title:t,wordCount:0,chapterTextParagraphs:[],chapterText:"",startPosition:n?.index??null,existingChapterID:r?null:ps(n,"PD-CHAPTER")},u.push(i),o(n,null),i),o=(n,t=null)=>i?(c(),r={temporarySceneKey:`scene-${f.length+1}`,temporaryChapterKey:i.temporaryChapterKey,sceneNumberWithinChapter:f.filter(n=>n.temporaryChapterKey===i.temporaryChapterKey).length+1,title:t,wordCount:0,openingTextPreview:"",startPosition:n?.index??null,existingSceneID:n?ps(n,"PD-SCENE"):null},f.push(r),r):null,a=(n,t)=>{!i||!r||t<=0||(i.wordCount+=t,i.chapterTextParagraphs.push(n),r.wordCount+=t,r.openingTextPreview||!n||ws.has(n)||(r.openingTextPreview=n.length>180?`${n.slice(0,177)}...`:n))};if(n.forEach((n,t)=>{n.index=t;const r=String(n.text||"").trim();if(r){s.push(r);const u=df(r);if(wi(n,1)){h+=1;l(n,r);e+=u;i.wordCount+=u;i.chapterTextParagraphs.push(r);return}if(i||l(n,"Opening pages",!0),wi(n,2)){o(n,r);e+=u;a(r,u);return}if(ws.has(r)){o(n,null);return}e+=u;a(r,u)}}),e===0)throw new Error("The document appears to be empty. Add manuscript text, then try again.");if(h===0)throw new Error("No chapters were detected. Make sure your chapter headings use Heading 1, or add clear chapter headings.");u.forEach(n=>{n.chapterText=Array.isArray(n.chapterTextParagraphs)?n.chapterTextParagraphs.join("\n\n"):"",delete n.chapterTextParagraphs});const v=s.join("\n");return{previewID:"00000000-0000-0000-0000-000000000000",userID:nu(t,"userID","UserID","userId"),onboardingID:nu(t,"onboardingID","OnboardingID","onboardingId"),projectID:nu(t,"projectID","ProjectID","projectId"),bookID:nu(t,"bookID","BookID","bookId"),source:"WordCompanion",documentTitle:ny()||"Word manuscript",companionDocumentIdentifier:or(),totalWordCount:e,chapterCount:u.length,sceneCount:f.length,characterCandidateCount:0,createdUtc:(new Date).toISOString(),chapters:u,scenes:f,characterCandidates:[],documentTextForDiscovery:v}},nu=(n,...t)=>{for(const i of t)if(n?.[i]!==undefined&&n?.[i]!==null)return n[i];return null},gf=async(n,t,i,r={})=>{d&&d.state===signalR.HubConnectionState.Connected&&await d.invoke("ReportOnboardingScanProgress",{userID:nu(n,"userID","UserID","userId"),onboardingID:nu(n,"onboardingID","OnboardingID","onboardingId"),message:t,percentComplete:i,chapterCount:r.chapterCount||0,sceneCount:r.sceneCount||0,characterCandidateCount:r.characterCandidateCount||0,totalWordCount:r.totalWordCount||0})},ly=async(n,t)=>{d&&d.state===signalR.HubConnectionState.Connected&&await d.invoke("FailOnboardingScan",{userID:nu(n,"userID","UserID","userId"),onboardingID:nu(n,"onboardingID","OnboardingID","onboardingId"),message:t})},bd=async n=>{if(!nt||!window.Word){await ly(n,"Open your manuscript in Microsoft Word, then try the scan again.");return}try{await gf(n,"Preparing document scan",5);const i=await window.Word.run(async t=>{const i=t.document.body.paragraphs;i.load("items/text,items/style,items/styleBuiltIn");await t.sync();await gf(n,"Detecting chapters",20);for(const n of i.items)(wi(n,1)||wi(n,2))&&n.contentControls.load("items/tag,title");return await t.sync(),i.items}),t=wd(i,n);await gf(n,"Detecting scene breaks",50,t);await gf(n,`Scene ${t.sceneCount} of ${t.sceneCount} scanned`,70,t);await gf(n,"Finding character candidates",85,t);const r=t.documentTextForDiscovery||"";delete t.documentTextForDiscovery;try{const n=await st("/api/word-companion/manuscript/discover-characters",{projectId:t.projectID,documentText:r,includeExcluded:!0});t.characterCandidates=pd(n?.candidates);t.characterCandidateCount=t.characterCandidates.filter(n=>String(n.category||"").toLowerCase()!=="excluded").length}catch(u){console.warn("Unable to refine onboarding character candidates.",u);t.characterCandidates=[];t.characterCandidateCount=0}await gf(n,"Preparing preview",95,t);go=t;await d.invoke("CompleteOnboardingScan",t)}catch(t){console.error("Unable to complete onboarding scan.",t);await ly(n,dd(t))}},kd=async n=>{if(!go||!nt||!window.Word||typeof window.Word.run!="function")throw new Error("Word document access is unavailable.");const t=new Map((n?.chapterMappings||n?.ChapterMappings||[]).map(n=>[n.temporaryChapterKey||n.TemporaryChapterKey,n.chapterID||n.ChapterID])),i=new Map((n?.sceneMappings||n?.SceneMappings||[]).map(n=>[n.temporarySceneKey||n.TemporarySceneKey,n.sceneID||n.SceneID]));await window.Word.run(async n=>{const r=n.document.body.paragraphs;r.load("items/text,items/style,items/styleBuiltIn");await n.sync();for(const n of go.chapters||[]){const u=t.get(n.temporaryChapterKey),i=Number.parseInt(n.startPosition,10);u&&Number.isInteger(i)&&r.items[i]&&wu(r.items[i],"PlotDirector Chapter",`PD-CHAPTER-${u}`,"PD-CHAPTER")}for(const n of go.scenes||[]){const u=i.get(n.temporarySceneKey),t=Number.parseInt(n.startPosition,10);u&&Number.isInteger(t)&&r.items[t]&&wu(r.items[t],"PlotDirector Scene",`PD-SCENE-${u}`,"PD-SCENE")}await n.sync()})},dd=n=>{const t=e(n);return/No chapters were detected/i.test(t)?"No chapters were detected. Make sure your chapter headings use Heading 1, or add clear chapter headings.":/empty/i.test(t)?"The document appears to be empty. Add manuscript text, then try again.":/network|disconnect|connection/i.test(t)?"The Word Companion disconnected before the scan finished. Reopen Word and try again.":`The scan could not finish: ${t}`},gd=(n,t)=>String(n?.text||"").trim()===String(t?.text||"").trim()&&io(n)===io(t),ay=(n,t)=>{const r=(t||[]).find(n=>String(n.text||"").trim());if(!n||!r)return n?.currentParagraphIndex??-1;const i=n.paragraphs.filter(n=>gd(n,r)).map(n=>n.index);return i.length===0?n.currentParagraphIndex??-1:Number.isInteger(n.currentParagraphIndex)?i.reduce((t,i)=>Math.abs(i-n.currentParagraphIndex)!n||!Number.isInteger(t)||t<0?null:n.chapters.filter(n=>n.startParagraphIndex<=t).at(-1)||null,tg=(n,t)=>!n||!Number.isInteger(t)||t<0?null:n.scenes.filter(n=>n.startParagraphIndex<=t).at(-1)||null,vy=n=>{if(!l)return!1;const t=ng(l,n),i=tg(t,n),r=t?.startParagraphIndex!==l.currentChapter?.startParagraphIndex||i?.startParagraphIndex!==l.currentScene?.startParagraphIndex||t?.anchorId!==l.currentChapter?.anchorId||i?.anchorId!==l.currentScene?.anchorId;return(l.currentParagraphIndex=n,l.currentChapter=t,l.currentScene=i,!r)?!1:(yf(t?.title,i?.title,i?.wordCount,t?.anchorId,i?.anchorId,t?.index),r)},ul=n=>{if(ie){if(ie.innerHTML="",n.chapters.length===0){const n=document.createElement("p");n.textContent="No chapters detected. Use Heading 1 for chapter titles.";ie.append(n);return}const t=n.chapters.some(n=>n.scenes.length>0);if(!t){const n=document.createElement("p");n.textContent="No scenes detected. Use Heading 2 for scene titles.";ie.append(n)}for(const t of n.chapters){const n=document.createElement("div");n.className="word-companion-outline-chapter";const i=document.createElement("strong");if(i.textContent=t.title,n.append(i),t.scenes.length>0){const i=document.createElement("ul");for(const n of t.scenes){const t=document.createElement("li");t.textContent=n.title;i.append(t)}n.append(i)}ie.append(n)}}},yy=[{key:"alreadyLinked",title:"Already Linked"},{key:"couldLink",title:"Could Link"},{key:"wouldCreateChapters",title:"Would Create Chapters"},{key:"wouldCreateScenes",title:"Would Create Scenes"},{key:"manualReview",title:"Manual Review Required"}],ig={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},rg={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},bs=(n,t)=>ut(n,t).toLocaleLowerCase(),fi=({category:i,action:n,type:s,wordTitle:l,match:r="",anchorStatus:t="None",matches:u=[],pdChapter:e=null,pdScene:o=null,wordChapter:h=null,wordScene:c=null,parentItem:f=null})=>({id:`${s}-${h?.index||0}-${c?.index||0}-${h?.paragraphIndex??c?.paragraphIndex??0}`,category:i,action:n,type:s,wordTitle:l,match:r,anchorStatus:t,matches:u,pdChapter:e,pdScene:o,wordChapter:h,wordScene:c,parentItem:f,result:"Pending",error:""}),ei=(n,t)=>{Array.isArray(n[t.category])&&n[t.category].push(t)},fl=n=>Array.isArray(n?.scenes)?n.scenes:[],ug=(n,t)=>{for(const i of n){const n=fl(i).find(n=>n.sceneId===t);if(n)return{chapter:i,scene:n}}return null},fg=(n,t,i)=>{const u=n.anchorId?`PD-CHAPTER-${n.anchorId}`:"None";if(n.anchorId){const r=t.find(t=>t.chapterId===n.anchorId);if(r){const t=fi({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:n.title,match:`Chapter ${r.chapterId}: ${r.title}`,anchorStatus:u,pdChapter:r,wordChapter:n});return ei(i,t),t}const f=fi({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:n.title,anchorStatus:`${u} not found`,matches:[],pdChapter:null,wordChapter:n});return ei(i,f),f}const r=t.filter(t=>bs(t.title,"chapter")===bs(n.title,"chapter"));if(r.length===1){const t=fi({category:"couldLink",action:"couldLink",type:"Chapter",wordTitle:n.title,match:`Chapter ${r[0].chapterId}: ${r[0].title}`,anchorStatus:u,pdChapter:r[0],wordChapter:n});return ei(i,t),t}if(r.length>1){const t=fi({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:n.title,anchorStatus:u,matches:r.map(n=>`Chapter ${n.chapterId}: ${n.title}`),pdChapter:null,wordChapter:n});return ei(i,t),t}const f=fi({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:n.title,anchorStatus:u,pdChapter:null,wordChapter:n});return ei(i,f),f},eg=(n,t,i,r)=>{const u=n.anchorId?`PD-SCENE-${n.anchorId}`:"None";if(n.anchorId){const f=ug(i,n.anchorId);if(f){ei(r,fi({category:"alreadyLinked",action:"alreadyLinked",type:"Scene",wordTitle:n.title,match:`Scene ${f.scene.sceneId}: ${f.scene.title}`,anchorStatus:u,pdChapter:f.chapter,pdScene:f.scene,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}ei(r,fi({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:`${u} not found`,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}if(!t?.pdChapter&&t?.category==="manualReview"){ei(r,fi({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:u,matches:["Parent chapter requires manual review."],wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}if(!t?.pdChapter){ei(r,fi({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:n.title,anchorStatus:u,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}const f=fl(t.pdChapter).filter(t=>bs(t.title,"scene")===bs(n.title,"scene"));if(f.length===1){ei(r,fi({category:"couldLink",action:"couldLink",type:"Scene",wordTitle:n.title,match:`Scene ${f[0].sceneId}: ${f[0].title}`,anchorStatus:u,pdChapter:t.pdChapter,pdScene:f[0],wordChapter:t.wordChapter,wordScene:n,parentItem:t}));return}if(f.length>1){ei(r,fi({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:u,matches:f.map(n=>`Scene ${n.sceneId}: ${n.title}`),wordChapter:t.wordChapter,wordScene:n,parentItem:t}));return}ei(r,fi({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:n.title,anchorStatus:u,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:n,parentItem:t}))},og=(n,t)=>{const i={alreadyLinked:[],couldLink:[],wouldCreateChapters:[],wouldCreateScenes:[],manualReview:[]},r=Array.isArray(t?.chapters)?t.chapters:[];for(const t of Array.isArray(n?.chapters)?n.chapters:[]){const n=fg(t,r,i);for(const u of fl(t))eg(u,n,r,i)}return i},sg=n=>{const t=document.createElement("article");t.className="word-companion-preview-item";const i=document.createElement("strong");i.textContent=`${rg[n.action]||""} ${n.type}: ${n.wordTitle}`;t.append(i);const r=document.createElement("span");if(r.textContent=`Anchor: ${n.anchorStatus||"None"}`,t.append(r),n.match){const i=document.createElement("span");i.textContent=`Match: ${n.match}`;t.append(i)}if(Array.isArray(n.matches)&&n.matches.length>0){const i=document.createElement("div");i.className="word-companion-preview-matches";const r=document.createElement("span");r.textContent="Matches:";i.append(r);const u=document.createElement("ul");for(const t of n.matches){const n=document.createElement("li");n.textContent=t;u.append(n)}i.append(u);t.append(i)}const u=document.createElement("span");if(u.textContent=`Action: ${ig[n.action]||n.action}`,t.append(u),n.result&&n.result!=="Pending"){const i=document.createElement("span");i.textContent=n.error?`Result: ${n.result} - ${n.error}`:`Result: ${n.result}`;t.append(i)}return t},py=n=>{if(rf){rf.innerHTML="";for(const t of yy){const i=document.createElement("section");i.className="word-companion-preview-group";const r=document.createElement("strong");r.textContent=t.title;i.append(r);const u=Array.isArray(n?.[t.key])?n[t.key]:[];if(u.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="None";i.append(n)}else for(const n of u)i.append(sg(n));rf.append(i)}us()}},ne=async n=>{const t=n.document.body.paragraphs,i=n.document.getSelection().paragraphs;t.load("text,styleBuiltIn,style");i.load("text,styleBuiltIn,style");await n.sync();try{for(const n of t.items)(wi(n,1)||wi(n,2))&&n.contentControls.load("items/tag,title");await n.sync()}catch(u){console.warn("Unable to load Word heading content controls. Continuing without PlotDirector anchors.",u)}const r=ld(t.items,i.items);return r.bodyParagraphs=t.items,r},wy=async(n,t)=>{const u=n.document.body.paragraphs,f=n.document.getSelection().paragraphs;u.load("text,styleBuiltIn,style");f.load("text,styleBuiltIn,style");await n.sync();const r=yd(u.items,t),e=ay(r,f.items);return l=r,vy(e),i("Cache rebuilt."),r},dtt=async n=>{const t=n.document.getSelection().paragraphs;return t.load("text,styleBuiltIn,style"),await n.sync(),t.items},y=()=>window.performance&&typeof window.performance.now=="function"?window.performance.now():Date.now(),ti=n=>!!n&&!n.stale&&n.generation===ye&&n.documentGuid===or()&&n.sceneId===u,by=async(n={})=>{const r=!!n.includeSelection,w=n.updateDisplay!==!1,f=ye,b=y(),k=ni(),d=h(),e=l?.currentScene;if(!e||!Number.isInteger(e.startParagraphIndex)||!Number.isInteger(e.endParagraphIndex)||!kt||!nt||!window.Word||typeof window.Word.run!="function")return null;const g=y(),s=await window.Word.run(async n=>{const i=n.document.body.paragraphs;i.load("text");let t=null;return r&&(t=n.document.getSelection().paragraphs,t.load("text,styleBuiltIn,style")),await n.sync(),{bodyTexts:i.items.map(n=>String(n.text||"")),selectionParagraphs:r&&t?t.items.map(n=>({text:String(n.text||""),styleBuiltIn:n.styleBuiltIn,style:n.style})):[]}}),c=Math.round(y()-g);if(f!==ye)return ci(`Office snapshot: ${c}ms stale`),{stale:!0,generation:f};let a=!1;if(r){const n=ay(l,s.selectionParagraphs);a=vy(n)}const t=l?.currentScene;if(!t||!Number.isInteger(t.startParagraphIndex)||!Number.isInteger(t.endParagraphIndex))return null;const v=[];let i=0;const tt=Math.min(t.endParagraphIndex,s.bodyTexts.length-1),it=l.currentChapter?.startParagraphIndex;for(let n=t.startParagraphIndex;n<=tt;n+=1){const t=String(s.bodyTexts[n]||"").trim();t&&!ws.has(t)&&n!==it&&(v.push(t),i+=df(t))}t.wordCount=i;w&&yf(l.currentChapter?.title,t.title,i,l.currentChapter?.anchorId,t.anchorId,l.currentChapter?.index);const p={documentGuid:or(),projectId:k?.projectId||null,bookId:d?.bookId||null,chapterId:o,sceneId:u,chapterTitle:l.currentChapter?.title||"",sceneTitle:t.title||"",sceneText:v.join("\n"),wordCount:i,selectionSignature:`${l.currentParagraphIndex??-1}:${t.startParagraphIndex}:${t.endParagraphIndex}`,selectionChanged:a,generation:f};return pe=p,ci(`Office snapshot: ${c}ms; scene words: ${i}; total snapshot: ${Math.round(y()-b)}ms`),p},ky=async()=>ti(pe)?pe:await by(),dy=async()=>{if(t(""),!kt||!nt||!window.Word||typeof window.Word.run!="function")return yf(null,null,null),t("Word document access is unavailable."),f({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;tu&&(tu.disabled=!0,tu.textContent="Scanning...");t("Scanning document structure...");try{const n=await window.Word.run(async n=>{const t=h();return t?await wy(n,!!t.usesExplicitScenes):(l=null,await ne(n))});return l||yf(n.currentChapter?.title,n.currentScene?.title,n.currentScene?.wordCount,n.currentChapter?.anchorId,n.currentScene?.anchorId,n.currentChapter?.index),it("Not detected"),ul(n),t(""),f({lastScan:"Success",lastError:"-",paragraphs:String(n.paragraphCount),heading1:String(n.heading1Count),heading2:String(n.heading2Count)}),!0}catch(n){const i=e(n);return console.error("Unable to scan the Word document.",n),yf(null,null,null),t(`Unable to scan the Word document: ${i}`),f({lastScan:"Failure",lastError:i}),!1}finally{tu&&(tu.disabled=!1,tu.textContent="Refresh Document Structure")}},gy=async()=>{const n=h();if(!ni()||!n)return er("Select a project and book to analyse manuscript structure."),!1;if(!kt||!nt||!window.Word||typeof window.Word.run!="function")return er("Word document access is unavailable."),f({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;cr&&(cr.disabled=!0,cr.textContent="Analysing...");er("Analysing manuscript structure...");try{const t=await window.Word.run(async n=>await ne(n)),i=await at(`/api/word-companion/books/${n.bookId}/structure`);return yf(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),ul(t),vi=og(t,i),py(vi),er("Preview generated. No changes have been applied."),f({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),!0}catch(t){return console.error("Unable to analyse manuscript structure.",t),er("Unable to analyse manuscript structure."),f({lastScan:"Failure",lastError:e(t)}),!1}finally{cr&&(cr.textContent="Analyse Manuscript Structure",fs())}},hg=(n=vi)=>{const t=su(n),i=t.filter(n=>n.category==="couldLink"&&n.type==="Chapter").length,r=t.filter(n=>n.category==="couldLink"&&n.type==="Scene").length,u=t.filter(n=>n.category==="wouldCreateChapters").length,f=t.filter(n=>n.category==="wouldCreateScenes").length,e=Array.isArray(n?.manualReview)?n.manualReview.length:0;return{linkChapters:i,linkScenes:r,createChapters:u,createScenes:f,manualReview:e}},cg=n=>{if(ah){ah.innerHTML="";const i=[`Link ${n.linkChapters+n.linkScenes} chapters/scenes`,`Create ${n.createChapters} chapters`,`Create ${n.createScenes} scenes`],t=document.createElement("ul");for(const n of i){const i=document.createElement("li");i.textContent=n;t.append(i)}ah.append(t)}},el=n=>{ts&&(ts(n),ts=null),tr?.close?tr.close():tr&&(tr.hidden=!0)},lg=()=>{const n=hg();return(cg(n),!tr)?Promise.resolve(window.confirm(`Apply Structure Sync?
-
-This will:
-
-- Link ${n.linkChapters+n.linkScenes} chapters/scenes
-- Create ${n.createChapters} chapters
-- Create ${n.createScenes} scenes
-
-Manual review items will be skipped.`)):new Promise(n=>{ts=n,tr.showModal?tr.showModal():tr.hidden=!1})},ro=(n,t,i="")=>{n.result=t,n.error=i},np=n=>Number.isInteger(n?.wordChapter?.index)&&n.wordChapter.index>0?n.wordChapter.index*10:null,tp=n=>Number.isInteger(n?.wordScene?.index)&&n.wordScene.index>0?n.wordScene.index*10:null,ag=async(n,t)=>{const i=await st(`/api/word-companion/books/${n}/chapters`,{title:au(t.wordTitle),sortOrder:np(t)});if(!i?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");hu();t.pdChapter={chapterId:i.chapterId,title:i.title||t.wordTitle,sortOrder:i.sortOrder||np(t)||0,scenes:[]};t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},vg=async(n,t)=>{const i=t.pdChapter||t.parentItem?.pdChapter;if(!i?.chapterId)throw new Error("Scene parent chapter is not available.");const r=await st(`/api/word-companion/books/${n}/chapters/${i.chapterId}/scenes`,{sceneTitle:au(t.wordTitle),sortOrder:tp(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");hu();t.pdChapter=i;t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:tp(t)||0};t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},yg=async n=>{if(!kt||!nt||!window.Word||typeof window.Word.run!="function")throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const u=await ne(t),r=n.type==="Chapter"?n.wordChapter:n.wordScene,i=Number.isInteger(r?.paragraphIndex)?u.bodyParagraphs[r.paragraphIndex]:null;if(!i)throw new Error("Unable to locate the Word heading.");if(n.type==="Chapter"){const t=n.pdChapter?.chapterId;if(!t)throw new Error("Chapter ID is not available.");wu(i,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=n.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");wu(i,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})},pg=n=>`Structure Sync Complete. Created: ${n.createdChapters} Chapters, ${n.createdScenes} Scenes. Linked: ${n.linkedChapters} Chapters, ${n.linkedScenes} Scenes. Skipped: ${n.skipped} Manual Review items. Failed: ${n.failed} Items.`,wg=async()=>{const r=h();if(!r||su().length===0||ve){us();return}const f=await lg();if(f){ve=!0;fs();er("Applying structure sync...");const n={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(vi?.manualReview)?vi.manualReview.length:0,failed:0},o=su().filter(n=>n.category==="couldLink"&&n.type==="Chapter"),s=su().filter(n=>n.category==="wouldCreateChapters"),c=su().filter(n=>n.category==="couldLink"&&n.type==="Scene"),l=su().filter(n=>n.category==="wouldCreateScenes"),u=[];let t="";const i=(n,t)=>{u.push({item:n,counterName:t})},a=async(t,i)=>{try{await yg(t);ro(t,"Success");n[i]+=1}catch(r){ro(t,"Failed",e(r));n.failed+=1}};try{for(const n of o)i(n,"linkedChapters");for(const t of s)try{await ag(r.bookId,t);i(t,"createdChapters")}catch(u){ro(t,"Failed",e(u));n.failed+=1}for(const n of c)i(n,"linkedScenes");for(const t of l)try{await vg(r.bookId,t);i(t,"createdScenes")}catch(u){ro(t,"Failed",e(u));n.failed+=1}for(const n of u)await a(n.item,n.counterName);for(const n of vi.manualReview||[])ro(n,"Skipped");py(vi);t=pg(n);er(t)}finally{ve=!1;fs();t&&(hu(),await gy(),er(`${t} Preview refreshed.`))}}},bg=async()=>{ru&&(ru.disabled=!0,ru.textContent="Running...");try{if(await gv(),!kt||!nt||!window.Word||typeof window.Word.run!="function"){f({lastScan:"Failure",lastError:"Word document access is unavailable.",paragraphs:"-",heading1:"-",heading2:"-"});return}const n=await window.Word.run(async n=>{const t=n.document.body.paragraphs;return t.load("items"),await n.sync(),t.items.length});f({lastScan:"Success",lastError:"-",paragraphs:String(n)})}catch(n){console.error("Word Companion diagnostics failed.",n);const i=e(n);f({lastScan:"Failure",lastError:i});t(`Unable to scan the Word document: ${i}`)}finally{ru&&(ru.disabled=!1,ru.textContent="Run Diagnostics")}},at=async(n,t={})=>{const i=await window.fetch(n,{credentials:"same-origin",...t,headers:{Accept:"application/json",...(t.headers||{})}});if(!i.ok)throw new Error(`Request failed: ${i.status}`);return await i.json()},st=(n,t)=>at(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),kg=async()=>{const n=gr(),t=vu();if(!n||!t){lt("Select a Project and Book to begin.");return}if(!kt||!nt||!window.Word||typeof window.Word.run!="function"){lt("Word document access is unavailable.");return}sr&&(sr.disabled=!0,sr.textContent="Scanning...");ui("Scanning manuscript structure...");try{const i=await window.Word.run(async n=>{const i=n.document.body.paragraphs;return i.load("text,styleBuiltIn,style"),await n.sync(),ad(i.items,!!t.usesExplicitScenes)});ce=i;ns=!1;const u=await st("/api/word-companion/manuscript/analyse",{projectId:n.projectId,bookId:t.bookId,documentGuid:fy(),chapterCount:i.chapterCount,sceneCount:i.sceneCount,wordCount:i.wordCount});wr=u;od(u);try{const t=await st("/api/word-companion/manuscript/discover-characters",{projectId:n.projectId,documentText:i.documentText||""});hi=Array.isArray(t?.candidates)?t.candidates:[];r(ku,!0);r(gu,!0)}catch(e){console.error("Unable to discover character candidates.",e);hi=[];r(ku,!0);r(gu,!0)}f({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(i.chapterCount),heading2:"-"})}catch(i){console.error("Unable to scan manuscript for first-run import.",i);lt(`Unable to scan manuscript: ${e(i)}`);f({lastScan:"Failure",lastError:e(i)})}finally{sr&&(sr.textContent="Scan Manuscript");ft()}},dg=()=>new Promise(n=>{if(!nf||typeof nf.showModal!="function"){n(window.confirm("This Book already contains planned chapters and scenes.\n\nImporting this manuscript will replace the planned structure.\n\nContinue?"));return}const t=t=>{dl?.removeEventListener("click",i),gl?.removeEventListener("click",r),nf?.removeEventListener("cancel",u),nf?.close(),n(t)},i=()=>t(!0),r=()=>t(!1),u=n=>{n.preventDefault(),t(!1)};dl?.addEventListener("click",i);gl?.addEventListener("click",r);nf?.addEventListener("cancel",u);nf.showModal()}),gg=()=>new Promise(n=>{if(!tf||typeof tf.showModal!="function"){n(window.confirm("This will remove PlotDirector binding metadata from this Word document.\n\nIf PlotDirector is reachable, it will also unlink this Book in PlotDirector.\n\nYour manuscript text will not be changed.\n\nContinue?"));return}const t=t=>{na?.removeEventListener("click",i),ta?.removeEventListener("click",r),tf?.removeEventListener("cancel",u),tf?.close(),n(t)},i=()=>t(!0),r=()=>t(!1),u=n=>{n.preventDefault(),t(!1)};na?.addEventListener("click",i);ta?.addEventListener("click",r);tf?.addEventListener("cancel",u);tf.showModal()}),nn=async()=>{const i=gr(),u=vu();if(!i||!u||!ce||!wr?.canImport){ft();return}let n=!1;if(wr.requiresReplaceConfirmation&&(n=await dg(),!n)){ui("Import cancelled.");return}ae=!0;ft();ui("Importing manuscript structure...");try{const h=fy(),f=await st("/api/word-companion/manuscript/import",{projectId:i.projectId,bookId:u.bookId,documentGuid:h,bindingVersion:1,replacePlanned:n,chapters:ce.chapters});if(!f.imported){wr={...wr,canImport:!f.requiresReplaceConfirmation,requiresReplaceConfirmation:!!f.requiresReplaceConfirmation,message:f.message||wr.message};ui(f.message||"Import was not completed.");ft();return}const e=f.manuscriptDocument;await hd({documentGuid:e?.documentGuid||h,bookId:f.bookId,projectId:f.projectId,bindingVersion:e?.bindingVersion||1});ri={documentGuid:e?.documentGuid||h,bookId:f.bookId,projectId:f.projectId,bindingVersion:e?.bindingVersion||1};v(s.projectId,f.projectId);v(s.bookId,f.bookId);p&&(p.value=String(f.projectId));const o=hi;await bu(f.projectId,f.bookId);ge("Connected");ns=!0;ff=o.length>0;le=ff?Date.now():0;hi=o;o.length>0?(yu(!0),ed(o),r(rh,!0),r(gu,!1),ui(f.message||"Manuscript structure imported."),t(f.message||"Manuscript structure imported."),window.setTimeout(ft,750)):await ks(f.message||"Manuscript structure imported.")}catch(f){console.error("Unable to import manuscript structure.",f);ui(`Unable to import manuscript: ${e(f)}`)}finally{ae=!1;ft()}},ks=async(n="")=>{ff=!1;le=0;hi=[];ki&&(ki.innerHTML="");r(ku,!0);yu(!1);ui("");r(gu,!0);n&&t(n);const i=await ip();n&&i&&w&&t(n)},tn=async()=>{const i=gr()||ni(),r=ry();if(!ff||Date.now()-le<750||!i||r.length===0){ft();return}wh=!0;ft();n(du,"Creating selected characters...");try{const u=await st("/api/word-companion/manuscript/create-discovered-characters",{projectId:i.projectId,candidateNames:r});t(u.message||"Characters created.");n(du,`${u.createdCount||0} created, ${u.skippedCount||0} already existed.`);await ks(u.message||"Characters created.")}catch(u){console.error("Unable to create discovered characters.",u);n(du,`Unable to create characters: ${e(u)}`)}finally{wh=!1;ft()}},rn=async(n=u,t=o)=>{const f=ni(),e=h(),c=or(),r=Number.parseInt(n||"",10),s=Number.parseInt(t||"",10);if(f&&e&&c&&Number.isInteger(r)&&!(r<=0)&&Number.isInteger(s)&&!(s<=0)){const l=`${f.projectId}:${e.bookId}:${r}`;if(ac!==l){ac=l;try{await st("/api/word-companion/runtime/current-scene",{documentGuid:c,projectId:f.projectId,bookId:e.bookId,chapterId:s,sceneId:r});i("Current scene follow event sent.")}catch(a){ac="";console.debug("Unable to notify PlotDirector of current scene.",a)}}}},ip=async()=>{const n=h();if(!n||!kt||!nt||!window.Word||typeof window.Word.run!="function")return!1;t("Reading manuscript position...");try{hu();await Promise.all([hl(!0),cl(!0),ll(!0)]);await ls(n.bookId);const i=await window.Word.run(async t=>await wy(t,!!n.usesExplicitScenes));return(ul(i),f({lastScan:"Success",lastError:"-",paragraphs:String(i.paragraphCount),heading1:String(i.heading1Count),heading2:String(i.heading2Count)}),!w)?(it("Not detected"),li(!1),k("Live"),t("Manuscript linked. Click inside a chapter to show the current scene."),!0):(rt?await eo():await vl(),li(!1),k("Live"),t(""),!0)}catch(i){return console.error("Unable to initialise bound manuscript runtime.",i),l=null,k("Manual"),t(`Unable to read manuscript position: ${e(i)}`),f({lastScan:"Failure",lastError:e(i)}),!1}},un=async()=>{if(!uf||!nt){yu(!1);return}const n=rl();if(n)try{const t=await at(`/api/word-companion/runtime/book/${n.bookId}?documentGuid=${encodeURIComponent(n.documentGuid)}`),i=t?.manuscriptDocument;if(t?.bookId===n.bookId&&t?.projectId===n.projectId&&i&&String(i.documentGuid).toLowerCase()===n.documentGuid.toLowerCase()){ri=n;pv(t);v(s.projectId,t.projectId);v(s.bookId,t.bookId);p&&(p.value=String(t.projectId));await bu(t.projectId,t.bookId);yu(!1);ge("Connected");af("Bound manuscript detected.");await ip();return}}catch{}ri=null;bf();il();gr()?await bu(gr().projectId,null):c(g,"Select a project first");lt("Select a Project and Book to begin.");yu(!0)},rp=async n=>{ri=null,yp(),pf(),bf(),it("Not detected"),k("Manual"),ge("Connected"),v(s.projectId,null),v(s.bookId,null),p&&(p.value=""),c(ot,"Select a project first"),il(),et&&(et.value=""),c(g,"Select a project first"),lt(n||"Select a Project and Book to begin."),t(n||"Manuscript unlinked."),gt("No resolved PlotDirector scene."),yu(!0),bc()},fn=async()=>{console.debug("Word Companion unlink clicked");t("Preparing to unlink manuscript...");const n=sd();if(!n){t("This Word document is not linked.");return}if(!n.documentGuid||!Number.isInteger(n.bookId)||n.bookId<=0){t("Unable to unlink: bound document metadata is incomplete.");return}const r=await gg();if(!r){t("Unlink cancelled.");return}t("Unlinking manuscript...");lr&&(lr.disabled=!0,lr.textContent="Unlinking...");try{await st("/api/word-companion/manuscript/unlink",{documentGuid:n.documentGuid,bookId:n.bookId});await uy();await rp("Manuscript unlinked.")}catch(i){console.error("Unable to unlink manuscript binding.",i);t("Unable to unlink from PlotDirector.");const r=window.confirm("PlotDirector could not be updated, but you can still remove the binding from this Word document.\n\nYou may need to unlink the Book manually in PlotDirector later.\n\nRemove binding from this Word document only?");if(r)try{await uy();await rp("Word metadata removed. Unlink the Book manually in PlotDirector if it still shows as linked.")}catch(n){console.error("Unable to remove Word document metadata.",n);t(`Unable to remove Word metadata: ${e(n)}`)}else t(`Unable to unlink manuscript: ${e(i)}`)}finally{lr&&(lr.disabled=!1,lr.textContent="Unlink this Word document");bc()}},gtt=(n,t)=>at(n,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),en=(n,t)=>at(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),ds=n=>n?[...n.querySelectorAll("input[type='checkbox']:checked")].map(n=>Number.parseInt(n.value||"",10)).filter(n=>Number.isInteger(n)&&n>0):[],up=()=>{const n=Number.parseInt(vr?.value||"",10);return Number.isInteger(n)&&n>0?n:null},on=()=>{const n=new Set(ds(re)),t=new Set(ds(ue));ct={characters:ct.characters.map(t=>({...t,linked:n.has(Number.parseInt(hs(t,"character"),10))})),assets:ct.assets.map(n=>({...n,linked:t.has(Number.parseInt(hs(n,"asset"),10))})),locations:ct.locations,primaryLocationId:up()}},sn=async()=>{if(!u)return!1;if(!kt||!nt||!window.Word||typeof window.Word.run!="function")return li(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1;try{const n=await window.Word.run(async n=>await ne(n)),r=n.currentChapter?.title||"",f=n.currentScene?.title||"",t=n.currentScene?.anchorId||null,i=n.currentChapter?.anchorId||null,e=Number.isInteger(t)&&t===u,s=Number.isInteger(i)&&i===o,h=ut(f,"scene").toLocaleLowerCase()===ut(rs||rt,"scene").toLocaleLowerCase(),c=ut(r,"chapter").toLocaleLowerCase()===ut(vc||w,"chapter").toLocaleLowerCase(),l=e||h&&(s||c);return l?(li(!1),!0):(li(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1)}catch(n){return console.error("Unable to verify current Word scene before saving.",n),f({lastError:e(n)}),li(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}},hn=async()=>{if(!u){cu("Link a PlotDirector scene first.");return}if(ht||!await sn()){cu("The Word cursor is now in a different scene. Refresh Current Scene before saving.");return}di&&(di.disabled=!0,di.textContent="Saving...");try{await en(`/api/word-companion/scenes/${u}/links`,{characterIds:ds(re),assetIds:ds(ue),locationIds:[],primaryLocationId:up()});on();cu("Scene links saved successfully.");f({lastError:"-"})}catch(n){cu("Unable to save scene links.");f({lastError:e(n)})}finally{di&&(di.disabled=!u||ht,di.textContent="Save Scene Links")}},cn=(n,t)=>{const i=sy(n);return i.find(n=>oy(n.tag,t))||null},wu=(n,t,i,r)=>{const f=cn(n,r),u=f||n.getRange().insertContentControl();return u.title=t,u.tag=i,u.appearance="Hidden",u},fp=async(n="PlotDirector IDs attached successfully.")=>{if(!u||!o)return t("No resolved PlotDirector scene."),!1;const r=tt&&tt!==u||b&&b!==o;if(r&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!kt||!nt||!window.Word||typeof window.Word.run!="function")return t("Word document access is unavailable."),!1;ai&&(ai.disabled=!0,ai.textContent="Attaching...");try{return await window.Word.run(async n=>{const t=await ne(n);if(!t.currentChapter||!t.currentScene)throw new Error("No scene detected in Word. Use Heading 2 for scenes.");const i=t.bodyParagraphs[t.currentChapter.paragraphIndex],r=t.bodyParagraphs[t.currentScene.paragraphIndex];if(!i||!r)throw new Error("Unable to locate the current Word headings.");wu(i,"PlotDirector Chapter",`PD-CHAPTER-${o}`,"PD-CHAPTER");wu(r,"PlotDirector Scene",`PD-SCENE-${u}`,"PD-SCENE");await n.sync()}),b=o,tt=u,dt=!1,rr="SceneID Anchor",ee="Anchor",t(n),f({lastError:"-"}),fr(),!0}catch(i){return console.error("Unable to attach PlotDirector IDs.",i),t("Unable to attach PlotDirector IDs."),f({lastError:e(i)}),fr(),!1}finally{ai&&(ai.textContent=tt===u?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",fr())}},ep=async n=>{if(!o)return yi("No resolved PlotDirector chapter."),!1;if(!kt||!nt||!window.Word||typeof window.Word.run!="function")return yi("Word document access is unavailable."),!1;try{return await window.Word.run(async n=>{const t=await ne(n);if(!t.currentChapter)throw new Error("No chapter detected in Word. Use Heading 1 for chapters.");const i=t.bodyParagraphs[t.currentChapter.paragraphIndex];if(!i)throw new Error("Unable to locate the current Word chapter heading.");wu(i,"PlotDirector Chapter",`PD-CHAPTER-${o}`,"PD-CHAPTER");await n.sync()}),b=o,dt=!1,rr="ChapterID Anchor",ee="Chapter anchor",yi(n),t(n),f({lastError:"-"}),fr(),!0}catch(i){return console.error("Unable to attach PlotDirector chapter ID.",i),yi("Unable to attach PlotDirector chapter ID."),f({lastError:e(i)}),fr(),!1}},ln=async()=>{await fp()},op=async n=>{no(),await eo(),t(n),yi(n)},ol=n=>{bo&&(bo(n),bo=null),nr?.close?nr.close():nr&&(nr.hidden=!0)},an=(t,i)=>(n(fb,`"${t}"`),n(eb,`"${i}"`),!nr)?Promise.resolve(window.confirm(`Create PlotDirector chapter:
-
-"${t}"
-
-in book:
-
-"${i}"
-
-?`)):new Promise(n=>{bo=n,nr.showModal?nr.showModal():nr.hidden=!1}),vn=async()=>{const n=h();if(!n||!w||o){os("Chapter not found in PlotDirector.");return}const t=au(w),i=await an(t,dr(n)||"selected book");if(i){yt&&(yt.disabled=!0,yt.textContent="Creating...");try{const r=Number.isInteger(fe)&&fe>0?fe*10:null,i=await st(`/api/word-companion/books/${n.bookId}/chapters`,{title:t,sortOrder:r});if(!i?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");hu();kr(null,i.chapterId,"Manual chapter link");const u=await ep("Chapter created and linked successfully.");if(!u)return;await op("Chapter created and linked successfully.")}catch(r){yi("Unable to create chapter.");f({lastError:e(r)})}finally{yt&&(yt.disabled=!gc(),yt.textContent="Create Chapter in PlotDirector")}}},sp=()=>{if(vo){const n=au(ao?.value||"").toLocaleLowerCase(),t=ph.filter(t=>!n||String(t.title||"").toLocaleLowerCase().includes(n));if(vo.innerHTML="",se=null,si&&(si.disabled=!0),t.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="No chapters found.";vo.append(n);return}for(const n of t){const i=Number.parseInt(n.chapterId||"",10);if(Number.isInteger(i)&&!(i<=0)){const r=document.createElement("label");r.className="word-companion-scene-option";const t=document.createElement("input");t.type="radio";t.name="word-companion-link-chapter";t.value=String(i);t.addEventListener("change",()=>{se=i,si&&(si.disabled=!1)});const u=document.createElement("span");u.textContent=n.title||"Untitled chapter";r.append(t,u);vo.append(r)}}}},yn=async()=>{const t=h();if(!t||!w||o){os("Chapter not found in PlotDirector.");return}pt&&(pt.disabled=!0,pt.textContent="Loading...");try{ph=await bv(t.bookId);se=null;ao&&(ao.value="");n(lh,"");sp();pr?.showModal?pr.showModal():pr&&(pr.hidden=!1)}catch(i){yi("Unable to load chapters.");f({lastError:e(i)})}finally{pt&&(pt.disabled=!gc(),pt.textContent="Link to Existing Chapter")}},hp=()=>{pr?.close?pr.close():pr&&(pr.hidden=!0)},pn=async()=>{const t=ph.find(n=>n.chapterId===se);if(!t){n(lh,"Select a chapter.");return}si&&(si.disabled=!0,si.textContent="Linking...");try{kr(null,t.chapterId,"Manual chapter link");const n=await ep("Chapter linked successfully.");if(!n)return;hp();await op("Chapter linked successfully.")}catch(i){n(lh,"Unable to link chapter.");yi("Unable to link chapter.");f({lastError:e(i)})}finally{si&&(si.disabled=!se,si.textContent="Link Chapter")}},cp=async(n,t,i)=>{const r=h();if(!r)return lu("Select a PlotDirector book first."),!1;await as(r.bookId,n,t,"Manual link","Title Match");const u=await fp(i);return u?(lu(i),ss(),!0):!1},sl=n=>{wo&&(wo(n),wo=null),gi?.close?gi.close():gi&&(gi.hidden=!0)},wn=(t,i)=>(n(nb,`"${t}"`),n(tb,`"${i}"`),!gi)?Promise.resolve(window.confirm(`Create PlotDirector scene:
-
-"${t}"
-
-within chapter:
-
-"${i}"
-
-?`)):new Promise(n=>{wo=n,gi.showModal?gi.showModal():gi.hidden=!1}),bn=async()=>{const n=h();if(!n||!rt){to("Scene not found in PlotDirector.");return}const t=ut(rt,"scene"),i=ut(w,"chapter"),r=await wn(t,i);if(r){wt&&(wt.disabled=!0,wt.textContent="Creating...");try{const r=await dv();if(!r){to("This chapter does not exist in PlotDirector. Create or link the chapter first.");return}const i=await st(`/api/word-companion/books/${n.bookId}/chapters/${r.chapterId}/scenes`,{sceneTitle:t});if(!i?.sceneId||!i?.chapterId)throw new Error("Scene creation did not return a scene ID.");hu();await cp(i.sceneId,i.chapterId,"Scene created and linked successfully.")}catch(u){lu("Unable to create scene.");f({lastError:e(u)})}finally{wt&&(wt.disabled=!nl(),wt.textContent="Create Scene in PlotDirector")}}},lp=()=>{if(lo){const n=au(co?.value||"").toLocaleLowerCase(),t=yh.filter(t=>!n||String(t.title||"").toLocaleLowerCase().includes(n));if(lo.innerHTML="",oe=null,oi&&(oi.disabled=!0),t.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="No scenes found.";lo.append(n);return}for(const n of t){const i=Number.parseInt(n.sceneId||"",10);if(Number.isInteger(i)&&!(i<=0)){const r=document.createElement("label");r.className="word-companion-scene-option";const t=document.createElement("input");t.type="radio";t.name="word-companion-link-scene";t.value=String(i);t.addEventListener("change",()=>{oe=i,oi&&(oi.disabled=!1)});const u=document.createElement("span");u.textContent=n.title||"Untitled scene";r.append(t,u);lo.append(r)}}}},kn=async()=>{const t=h();if(!t||!rt){to("Scene not found in PlotDirector.");return}bt&&(bt.disabled=!0,bt.textContent="Loading...");try{const r=await ls(t.bookId),i=kv(r);if(!i){to("This chapter does not exist in PlotDirector. Create or link the chapter first.");return}yh=Array.isArray(i.scenes)?i.scenes:[];oe=null;co&&(co.value="");n(ch,"");lp();yr?.showModal?yr.showModal():yr&&(yr.hidden=!1)}catch(i){lu("Unable to load scenes.");f({lastError:e(i)})}finally{bt&&(bt.disabled=!nl(),bt.textContent="Link to Existing Scene")}},ap=()=>{yr?.close?yr.close():yr&&(yr.hidden=!0)},dn=async()=>{const i=h(),t=yh.find(n=>n.sceneId===oe);if(!i||!t){n(ch,"Select a scene.");return}oi&&(oi.disabled=!0,oi.textContent="Linking...");try{const n=await dv();if(!n)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");ap();await cp(t.sceneId,n.chapterId,"Scene linked successfully.")}catch(r){n(ch,"Unable to link scene.");lu("Unable to link scene.");f({lastError:e(r)})}finally{oi&&(oi.disabled=!oe,oi.textContent="Link Scene")}},uo=()=>{sf=!1,dc(),ke&&(ke=!1,gs(1e3))},vp=async(t={})=>{const p=t.source||"manual",w=y();if(!u){gt("No resolved PlotDirector scene.");return}if(!o){gt("No resolved PlotDirector chapter.");return}if(ht){gt("Refresh Current Scene before syncing.");return}const c=h(),l=or();if(!c||!l){gt("Bound manuscript metadata is unavailable.");return}if(sf){ke=!0;i("Scene sync deferred; sync already running.");return}pf();sf=!0;ke=!1;let r=t.snapshot||null;try{r=ti(r)?r:await ky()}catch(v){gt("Sync failed");f({lastError:e(v)});i("Scene sync failed.");uo();return}if(!ti(r)){gt("Waiting for typing to pause");i("Scene sync skipped (stale snapshot).");uo();return}const s=r.wordCount;if(!Number.isInteger(s)||s<0){gt("Sync failed");i("Scene sync failed.");uo();return}if(dh===r.sceneId&&gh===s){gt("Synced");i("Sync skipped (count unchanged).");uo();return}i("Scene word count changed.");ar&&(ar.disabled=!0,ar.textContent="Syncing...");gt("Syncing...");i(`Scene sync started (${p}).`);try{const f=y(),e=await st("/api/word-companion/runtime/scene-word-count",{documentGuid:r.documentGuid||l,bookId:r.bookId||c.bookId,chapterId:r.chapterId,sceneId:r.sceneId,wordCount:s});if(ci(`Word count sync API: ${Math.round(y()-f)}ms`),!ti(r)){i("Scene sync result ignored (stale snapshot).");return}const t=e?.actualWords??s,u=new Date;dh=r.sceneId;gh=t;n(hh,a(t));n(eh,a(t));n(tv,es(u));n(nv,es(u));gt("Synced");i("Scene sync succeeded.");ci(`Total word count sync: ${Math.round(y()-w)}ms`)}catch(v){gt("Sync failed");f({lastError:e(v)});i("Scene sync failed.")}finally{ar&&(ar.textContent="Sync Current Scene");uo()}},gs=(n=4e3)=>{(pf(),u&&o&&!ht&&!sf)&&(be=window.setTimeout(()=>{be=null,void vp({source:"automatic"})},n))},fo=()=>{de&&(window.clearTimeout(de),de=null)},gn=()=>{nc=null,tc="",lf=[],ic=null,rc="",fo()},ntt=()=>{uc=null,fc="",fu=[],ec=null,oc=""},ttt=()=>{sc=null,hc="",eu=[],cc=null,lc=""},hl=async(n=false)=>{const t=ni(),r=or();if(!t||!r)return lf=[],[];if(!n&&nc===t.projectId&&tc===r&&lf.length>0)return lf;const u=await at(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(r)}`);return nc=t.projectId,tc=r,lf=Array.isArray(u?.characters)?u.characters:[],i("Character alias cache refreshed."),lf},cl=async(n=false)=>{const t=ni(),r=or();if(!t||!r)return fu=[],[];if(!n&&uc===t.projectId&&fc===r&&fu.length>0)return fu;const u=await at(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(r)}`);return uc=t.projectId,fc=r,fu=Array.isArray(u?.assets)?u.assets:[],i(`Asset cache loaded: ${fu.length} aliases.`),fu},ll=async(n=false)=>{const t=ni(),r=or();if(!t||!r)return eu=[],[];if(!n&&sc===t.projectId&&hc===r&&eu.length>0)return eu;const u=await at(`/api/word-companion/runtime/locations?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(r)}`);return sc=t.projectId,hc=r,eu=Array.isArray(u?.locations)?u.locations:[],i(`Location cache loaded: ${eu.length} aliases.`),eu},itt=n=>String(n||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),al=(n,t)=>{const i=String(t||"").trim();if(!i)return!1;const r=itt(i).replace(/\s+/g,"\\s+");return new RegExp(`(^|[^\\p{L}\\p{N}_])${r}(?=$|[^\\p{L}\\p{N}_])`,"iu").test(n)},rtt=(n,t)=>{if(!n||!Array.isArray(t)||t.length===0)return[];const i=new Map;for(const r of t){const t=Number.parseInt(r.characterId||"",10);!Number.isInteger(t)||t<=0||i.has(t)||al(n,r.matchText)&&i.set(t,r.name||r.matchText||"Character")}return[...i.entries()].map(([n,t])=>({characterId:n,name:t}))},utt=(n,t)=>{if(!n||!Array.isArray(t)||t.length===0)return[];const i=new Map;for(const r of t){const t=Number.parseInt(r.assetId||"",10);!Number.isInteger(t)||t<=0||i.has(t)||al(n,r.matchText)&&i.set(t,r.name||r.matchText||"Asset")}return[...i.entries()].map(([n,t])=>({assetId:n,name:t}))},ftt=n=>String(n||"").trim().split(/\s+/).filter(Boolean).length,ett=n=>{if(n?.excludeFromCompanionDetection)return!1;const t=Number.parseInt(n?.detectionPriority||"0",10);return ftt(n?.matchText)>=2||Number.isInteger(t)&&t>=75},ott=(n,t)=>{if(!n||!Array.isArray(t)||t.length===0)return[];const i=new Map;for(const r of t){const t=Number.parseInt(r.locationId||"",10);!Number.isInteger(t)||t<=0||i.has(t)||!ett(r)||al(n,r.matchText)&&i.set(t,r.name||r.matchText||"Location")}return[...i.entries()].map(([n,t])=>({locationId:n,name:t}))},stt=()=>{hf=!1,cf&&(cf=!1,nh(1500))},htt=async()=>{if(de=null,u&&!ht&&or()){if(hf){cf=!0;i("Character suggestion detection deferred; detection already running.");return}hf=!0;cf=!1;const r=y();try{const n=await ky();if(!ti(n)){i("Runtime suggestions skipped (stale snapshot).");return}const[w,b,k]=await Promise.all([hl(),cl(),ll()]);if(!ti(n)){i("Runtime suggestions skipped after cache load (stale snapshot).");return}const s=n.sceneText||"",d=y(),o=rtt(s,w);ci(`Character detection: ${Math.round(y()-d)}ms`);const a=o.map(n=>n.characterId),h=a.slice().sort((n,t)=>n-t).join(","),g=y(),f=utt(s,b);ci(`Asset detection: ${Math.round(y()-g)}ms`);const v=f.map(n=>n.assetId),c=v.slice().sort((n,t)=>n-t).join(","),nt=y(),e=ott(s,k);ci(`Location detection: ${Math.round(y()-nt)}ms`);const p=e.map(n=>n.locationId),l=p.slice().sort((n,t)=>n-t).join(",");if(h&&(ic!==u||rc!==h)){if(!ti(n)){i("Character suggestions skipped before submit (stale snapshot).");return}const u=y(),r=await st("/api/word-companion/runtime/character-suggestions",{documentGuid:n.documentGuid,sceneId:n.sceneId,characterIds:a});if(ci(`Character suggestion API: ${Math.round(y()-u)}ms`),!ti(n)){i("Character suggestion result ignored (stale snapshot).");return}if(ic=n.sceneId,rc=h,(r?.createdCount||0)>0){const n=o.slice(0,3).map(n=>n.name).join(", "),i=o.length>3?` +${o.length-3}`:"";t(n?`Characters detected: ${n}${i}`:r.message)}i(r?.message||"Character suggestions submitted.")}else i("Character suggestions skipped.");if(c&&(ec!==u||oc!==c)){if(!ti(n)){i("Asset suggestions skipped before submit (stale snapshot).");return}i(`Asset matches found: ${f.map(n=>n.name).join(", ")}`);const u=y(),r=await st("/api/word-companion/runtime/asset-suggestions",{documentGuid:n.documentGuid,sceneId:n.sceneId,assetIds:v});if(ci(`Asset suggestion API: ${Math.round(y()-u)}ms`),!ti(n)){i("Asset suggestion result ignored (stale snapshot).");return}if(ec=n.sceneId,oc=c,(r?.createdCount||0)>0){const n=f.slice(0,3).map(n=>n.name).join(", "),i=f.length>3?` +${f.length-3}`:"";t(n?`Assets detected: ${n}${i}`:r.message)}i(r?.message||"Asset suggestions submitted.")}else i("Asset suggestions skipped.");if(l&&(cc!==u||lc!==l)){if(!ti(n)){i("Location suggestions skipped before submit (stale snapshot).");return}i(`Location matches found: ${e.map(n=>n.name).join(", ")}`);const u=y(),r=await st("/api/word-companion/runtime/location-suggestions",{documentGuid:n.documentGuid,sceneId:n.sceneId,locationIds:p});if(ci(`Location suggestion API: ${Math.round(y()-u)}ms`),!ti(n)){i("Location suggestion result ignored (stale snapshot).");return}if(cc=n.sceneId,lc=l,(r?.createdCount||0)>0){const n=e.slice(0,3).map(n=>n.name).join(", "),i=e.length>3?` +${e.length-3}`:"";t(n?`Locations detected: ${n}${i}`:r.message)}i(r?.message||"Location suggestions submitted.")}else i("Location suggestions skipped.");ci(`Total suggestion pass: ${Math.round(y()-r)}ms`)}catch(n){console.error("Unable to detect runtime suggestions.",n);f({lastError:e(n)})}finally{stt()}}},nh=(n=2500)=>{if(fo(),!u||ht||hf){hf&&(cf=!0);return}de=window.setTimeout(()=>{void htt()},n)},vl=async()=>{const i=ni(),n=h(),r=ut(w,"chapter");if(vt({projectId:i?.projectId,projectTitle:i?.title,bookId:n?.bookId,bookTitle:n?dr(n):undefined,detectedChapter:w,detectedScene:rt,requestChapter:r,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!n)return it("Not detected"),t("Select a PlotDirector book first."),!1;if(!w)return it("Not detected"),t("No chapter detected in Word. Use Heading 1 for chapters."),!1;it("Not detected");try{const f=await bv(n.bookId),i=b?f.find(n=>n.chapterId===b):null,e=r.toLocaleLowerCase(),o=e?f.find(n=>ut(n.title,"chapter").toLocaleLowerCase()===e):null,u=i||o;return u?(no(),kr(null,u.chapterId,i?"Chapter anchor":"Chapter title"),rr=i?"ChapterID Anchor":"Title Match",vf("Chapter linked to PlotDirector"),t("No scene detected in Word. Use Heading 2 for scenes."),vt({result:"Chapter matched",chapterId:u.chapterId,sceneId:null}),!0):(kr(null),vf("Chapter not found in PlotDirector."),t("Chapter not found in PlotDirector."),vt({result:"Chapter not matched",chapterId:null,sceneId:null}),os("Chapter not found in PlotDirector."),!1)}catch(u){return it("Not found in PlotDirector"),f({lastError:e(u)}),t("Unable to load PlotDirector chapter data."),!1}},eo=async()=>{const r=ni(),n=h(),u=ut(w,"chapter"),i=ut(rt,"scene");if(vt({projectId:r?.projectId,projectTitle:r?.title,bookId:n?.bookId,bookTitle:n?dr(n):undefined,detectedChapter:w,detectedScene:rt,requestChapter:u,requestScene:i,result:"Not run",chapterId:null,sceneId:null}),wc({anchorType:tt?"SceneID Anchor":b?"ChapterID Anchor":"Title Match",storedSceneId:tt,storedChapterId:b,resolutionMethod:"-"}),!n)return it("Not detected"),t("Select a PlotDirector book first."),vt({result:"Error"}),!1;if(!w||!rt)return it("Not detected"),t("No scene detected in Word. Use Heading 2 for scenes."),vt({result:"Error"}),!1;iu&&(iu.disabled=!0,iu.textContent="Refreshing...");const s=()=>{iu&&(iu.disabled=!1,iu.textContent="Refresh PlotDirector Scene")};it("Not detected");t("Resolving PlotDirector scene...");try{if(tt){const i=await gk(n.bookId,(n,t)=>t.sceneId===tt);if(i)return vt({result:"Matched",chapterId:i.chapter.chapterId,sceneId:i.scene.sceneId}),await as(n.bookId,i.scene.sceneId,i.chapter.chapterId,"Anchor","SceneID Anchor"),!0;dt=!0;rr="SceneID Anchor";vf("Not found in PlotDirector");t("Stored PlotDirector ID is invalid.");vt({result:"Error",chapterId:b,sceneId:tt});wc({anchorType:"SceneID Anchor",storedSceneId:tt,storedChapterId:b,resolutionMethod:"Anchor"})}if(b){const u=await ls(n.bookId),t=u.find(n=>n.chapterId===b),r=t?(Array.isArray(t.scenes)?t.scenes:[]).find(n=>ut(n.title,"scene").toLocaleLowerCase()===i.toLocaleLowerCase()):null;if(r)return vt({result:"Matched",chapterId:t.chapterId,sceneId:r.sceneId}),await as(n.bookId,r.sceneId,t.chapterId,"Anchor","ChapterID Anchor"),!0;t&&!tt?(rr="ChapterID Anchor",kr(null,b,"Chapter anchor"),vt({result:"Chapter matched",chapterId:b,sceneId:null})):tt||(rr="ChapterID Anchor",vt({result:"Chapter anchor not found",chapterId:b,sceneId:null}))}const r=await st(`/api/word-companion/books/${n.bookId}/resolve-scene`,{chapterTitle:u,sceneTitle:i});if(!r?.matched||!r.sceneId){const u=dt,f=Number.parseInt(r?.chapterId||"",10),e=Number.isInteger(o)&&o>0?o:null,n=Number.isInteger(f)&&f>0?f:e,i=!!r?.chapterMatched||!!n;return it("Not found in PlotDirector"),dt=u,i&&(kr(null,n,n===e?"Chapter anchor":"Chapter title"),vf("Scene not found in PlotDirector.")),t(u?"Stored PlotDirector ID is invalid.":i?"Scene not found in PlotDirector.":"This chapter does not exist in PlotDirector. Create or link the chapter first."),vt({result:"Not matched",chapterId:i?n:r?.chapterId,sceneId:r?.sceneId}),u||(i?(no(),to("Scene not found in PlotDirector.")):(ss(),os("Chapter not found in PlotDirector."))),s(),!1}const f=dt;return vt({result:f?"Matched by title fallback":"Matched",chapterId:r.chapterId,sceneId:r.sceneId}),await as(n.bookId,r.sceneId,r.chapterId,f?"Title fallback":"Title","Title Match"),f&&(dt=!0,t("Stored PlotDirector ID is invalid."),fr()),!0}catch(c){const n=dt;return f({lastError:e(c)}),it("Not found in PlotDirector"),dt=n,t(n?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),vt({result:"Error"}),!1}finally{s()}},nit=n=>{const t=n.currentChapter?.title||"",i=n.currentScene?.title||"",r=n.currentChapter?.anchorId||null,u=n.currentScene?.anchorId||null;return ut(t,"chapter")!==ut(w,"chapter")||ut(i,"scene")!==ut(rt,"scene")||r!==b||u!==tt},ctt=async()=>{if(uu=null,is){ef=!0;i("Runtime update deferred; update already running.");return}if(!uf||!h()){br=!1;i("Runtime update skipped.");return}if(!kt||!nt||!window.Word||typeof window.Word.run!="function"){br=!1;k("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");return}if(!l){br=!1;k("Manual");t("Document structure is not cached yet. Use Refresh Current Scene.");return}const n=Date.now()-hv;if(br&&n{uu&&window.clearTimeout(uu),uu=window.setTimeout(ctt,Math.max(0,n)),k("Waiting for typing to pause"),i("Runtime update scheduled.")},ltt=(n="selection",t=we)=>{if(br=!0,hv=Date.now(),ye+=1,pe=null,pf(),fo(),sf&&(ke=!0),hf&&(cf=!0),i(`${n} changed.`),is){ef=!0;k("Waiting for typing to pause");return}yl(t)},yp=()=>{uu&&(window.clearTimeout(uu),uu=null),br=!1,ef=!1},pp=()=>{ltt("Selection")},att=()=>{if(kh&&window.Office?.context?.document&&typeof window.Office.context.document.removeHandlerAsync=="function"&&window.Office?.EventType?.DocumentSelectionChanged)try{window.Office.context.document.removeHandlerAsync(window.Office.EventType.DocumentSelectionChanged,{handler:pp});kh=!1}catch(n){console.warn("Unable to remove Word selection tracking handler.",n)}},vtt=()=>{if(uf){if(!window.Office?.context?.document||typeof window.Office.context.document.addHandlerAsync!="function"||!window.Office?.EventType?.DocumentSelectionChanged){k("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");return}try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,pp,n=>{n?.status===window.Office.AsyncResultStatus.Succeeded?(kh=!0,k("Live")):(k("Manual"),t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))});window.addEventListener("beforeunload",att)}catch(n){console.warn("Unable to register Word selection tracking handler.",n);k("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}},ytt=async()=>{if(!h()){t("Select a PlotDirector book first.");it("Not detected");return}yp();yv(!0);k("Updating...");try{await Promise.all([hl(!0),cl(!0),ll(!0)]);const n=await dy();if(!n)return;if(li(!1),!rt){await vl();k("Current scene updated");return}await eo();k("Current scene updated")}finally{yv(!1)}},bu=async(n,t)=>{if(l=null,hu(),!n){ii=[];c(ot,"Select a project first");c(g,"Select a project first");af("");v(s.bookId,null);pi();it("Not detected");wf();return}c(ot,"Loading books...");af("");it("Not detected");wf("Select a book to analyse manuscript structure.");try{const r=await at(`/api/word-companion/projects/${n}/books`);if(ii=Array.isArray(r.books)?r.books:[],ii.length===0){c(ot,"No books available.");c(g,"No books available.");af("No books available.");v(s.bookId,null);pi();lt("No books available.");return}ys(ot,"Choose a book",ii.map(n=>({...n,displayTitle:dr(n)})),"bookId","displayTitle");const i=ii.find(n=>n.bookId===t);i&&ot?(ot.value=String(i.bookId),v(s.bookId,i.bookId)):v(s.bookId,null);fd(i?.bookId||t);pi();it(h()?"Not detected":"Not detected");wf(h()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure.");lt(vu()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{ii=[];c(ot,"Unable to load books.");c(g,"Unable to load books.");af("Unable to load books.");v(s.bookId,null);pi();it("Not detected");wf("Unable to load books.");lt("Unable to load books.")}},ptt=async()=>{c(p,"Loading projects...");c(ot,"Select a project first");c(et,"Loading projects...");c(g,"Select a project first");pc("");af("");try{const t=await at("/api/word-companion/projects");if(ir=Array.isArray(t.projects)?t.projects:[],ir.length===0){c(p,"No projects available.");c(et,"No projects available.");pc("No projects available.");v(s.projectId,null);v(s.bookId,null);pi();lt("No projects available.");return}ys(p,"Choose a project",ir,"projectId","title");il();const i=vs(s.projectId),n=ir.find(n=>n.projectId===i);n&&p?(p.value=String(n.projectId),et&&(et.value=String(n.projectId)),v(s.projectId,n.projectId),await bu(n.projectId,vs(s.bookId))):(v(s.projectId,null),v(s.bookId,null),pi(),lt("Select a Project and Book to begin."))}catch{ir=[];ii=[];c(p,"Unable to connect to PlotDirector.");c(ot,"Select a project first");c(et,"Unable to connect to PlotDirector.");c(g,"Select a project first");ge("Unable to connect to PlotDirector.");pc("Unable to connect to PlotDirector.");v(s.projectId,null);v(s.bookId,null);pi();lt("Unable to connect to PlotDirector.")}};for(const n of ih)n.addEventListener("click",()=>av(n.dataset.tabButton));vv();p?.addEventListener("change",async()=>{const n=Number.parseInt(p.value||"",10);bf();et&&Number.isInteger(n)&&n>0&&(et.value=String(n));v(s.projectId,Number.isInteger(n)&&n>0?n:null);v(s.bookId,null);it("Not detected");wf();lt("Select a Book to begin.");await bu(n,null);kf()});ot?.addEventListener("change",()=>{const n=Number.parseInt(ot.value||"",10);bf();v(s.bookId,Number.isInteger(n)&&n>0?n:null);g&&Number.isInteger(n)&&n>0&&(g.value=String(n));pi();it("Not detected");wf(h()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure.");lt(vu()?"Ready to scan manuscript structure.":"Select a Book to begin.");kf()});et?.addEventListener("change",async()=>{const n=Number.parseInt(et.value||"",10);bf();p&&Number.isInteger(n)&&n>0&&(p.value=String(n));v(s.projectId,Number.isInteger(n)&&n>0?n:null);v(s.bookId,null);lt("Select a Book to begin.");await bu(n,null);kf()});g?.addEventListener("change",()=>{const n=Number.parseInt(g.value||"",10);bf();ot&&Number.isInteger(n)&&n>0&&(ot.value=String(n));v(s.bookId,Number.isInteger(n)&&n>0?n:null);pi();lt(vu()?"Ready to scan manuscript structure.":"Select a Book to begin.");kf()});te?.addEventListener("input",ft);oo?.addEventListener("click",async()=>{const n=gr(),t=String(te?.value||"").trim();if(!n||!t){ft();return}oo.disabled=!0;ui("Creating Book...");try{const i=await st(`/api/word-companion/projects/${n.projectId}/books`,{title:t});te&&(te.value="");p&&(p.value=String(n.projectId));await bu(n.projectId,i.bookId);g&&(g.value=String(i.bookId));ui("Ready to scan manuscript structure.")}catch(i){console.error("Unable to create Book from Word Companion.",i);ui(`Unable to create Book: ${e(i)}`)}finally{ft()}});sr?.addEventListener("click",kg);uh?.addEventListener("click",nn);so?.addEventListener("click",tn);bl?.addEventListener("click",()=>ks("Character creation skipped."));kl?.addEventListener("click",()=>ks());nw?.addEventListener("click",()=>yu(!1));iw?.addEventListener("click",()=>lt("Import cancelled."));tu?.addEventListener("click",dy);cr?.addEventListener("click",gy);fh?.addEventListener("click",wg);hb?.addEventListener("click",()=>el(!0));cb?.addEventListener("click",()=>el(!1));tr?.addEventListener("cancel",n=>{n.preventDefault(),el(!1)});iu?.addEventListener("click",eo);ho?.addEventListener("click",ytt);ar?.addEventListener("click",()=>vp({source:"manual"}));di?.addEventListener("click",hn);ai?.addEventListener("click",ln);lr?.addEventListener("click",fn);yt?.addEventListener("click",vn);pt?.addEventListener("click",yn);ao?.addEventListener("input",sp);si?.addEventListener("click",pn);ub?.addEventListener("click",hp);ob?.addEventListener("click",()=>ol(!0));sb?.addEventListener("click",()=>ol(!1));nr?.addEventListener("cancel",n=>{n.preventDefault(),ol(!1)});wt?.addEventListener("click",bn);bt?.addEventListener("click",kn);co?.addEventListener("input",lp);oi?.addEventListener("click",dn);gw?.addEventListener("click",ap);ib?.addEventListener("click",()=>sl(!0));rb?.addEventListener("click",()=>sl(!1));gi?.addEventListener("cancel",n=>{n.preventDefault(),sl(!1)});ru?.addEventListener("click",bg);const wtt=uf?ptt():Promise.resolve();if(uf||(c(p,"Please sign in to PlotDirector."),c(ot,"Please sign in to PlotDirector."),c(et,"Please sign in to PlotDirector."),c(g,"Please sign in to PlotDirector."),pi()),!window.Office||typeof window.Office.onReady!="function"){yc("Word Companion ready");t("Word document access is unavailable.");k("Manual");f({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});iy().catch(n=>{console.debug("Word Companion presence unavailable.",n)});return}gv().then(async()=>{yc("Word Companion ready"),await wtt,await un(),await iy(),nt?vtt():(t("Word document access is unavailable."),k("Manual"))}).catch(n=>{console.error("Office readiness check failed.",n),ge("Unable to connect to PlotDirector."),yc("Word Companion unavailable"),t("Word document access is unavailable."),f({ready:"No",wordApi:"No",lastScan:"Failure"})})})();
\ No newline at end of file
+(()=>{const e="plotdirector.word.projectId",t="plotdirector.word.bookId",n="plotdirector.word.activeTab",r={documentGuid:"plotdirector.word.documentGuid",bookId:"plotdirector.word.boundBookId",projectId:"plotdirector.word.boundProjectId",bindingVersion:"plotdirector.word.bindingVersion"},o=new Set(["scene","review","maintenance","diagnostics"]),a=document.querySelector(".word-companion-shell"),c=document.querySelector(".word-companion-tabs"),i=[...document.querySelectorAll("[data-tab-button]")],s=[...document.querySelectorAll("[data-tab-panel]")],d=document.querySelector("[data-linked-manuscript-card]"),l=document.querySelector("[data-linked-project-title]"),u=document.querySelector("[data-linked-book-title]"),p=document.querySelector("[data-first-run-wizard]"),h=document.querySelector("[data-first-run-project-select]"),m=document.querySelector("[data-first-run-book-select]"),g=document.querySelector("[data-first-run-new-book-title]"),y=document.querySelector("[data-first-run-create-book]"),w=document.querySelector("[data-first-run-scan]"),f=document.querySelector("[data-first-run-cancel]"),b=document.querySelector("[data-first-run-status]"),I=document.querySelector("[data-first-run-summary]"),C=document.querySelector("[data-first-run-character-section]"),S=document.querySelector("[data-first-run-character-status]"),k=document.querySelector("[data-first-run-character-candidates]"),v=document.querySelector("[data-first-run-character-actions]"),x=document.querySelector("[data-first-run-create-characters]"),P=document.querySelector("[data-first-run-skip-characters]"),D=document.querySelector("[data-first-run-continue]"),E=document.querySelector("[data-first-run-import-actions]"),N=document.querySelector("[data-first-run-import]"),L=document.querySelector("[data-first-run-import-cancel]"),q=document.querySelector("[data-first-run-replace-dialog]"),A=document.querySelector("[data-first-run-replace-confirm]"),$=document.querySelector("[data-first-run-replace-cancel]"),T=document.querySelector("[data-unlink-word-document-dialog]"),W=document.querySelector("[data-unlink-word-document-confirm]"),j=document.querySelector("[data-unlink-word-document-cancel]"),R=document.querySelector("[data-clean-unlink-word-document-dialog]"),U=document.querySelector("[data-clean-unlink-word-document-confirm]"),M=document.querySelector("[data-clean-unlink-word-document-cancel]"),O=document.querySelector("[data-office-status]"),B=document.querySelector("[data-connection-status]"),H=document.querySelector("[data-summary-connection]"),G=document.querySelector("[data-summary-project]"),F=document.querySelector("[data-summary-book]"),V=document.querySelector("[data-project-select]"),K=document.querySelector("[data-book-select]"),Y=document.querySelector("[data-runtime-book-selectors]"),J=document.querySelector("[data-project-message]"),_=document.querySelector("[data-book-message]"),z=document.querySelector("[data-refresh-current-scene]"),Q=document.querySelector("[data-refresh-document]"),X=document.querySelector("[data-current-chapter]"),Z=document.querySelector("[data-current-scene]"),ee=document.querySelector("[data-current-word-count]"),te=document.querySelector("[data-scene-tracking-status]"),ne=document.querySelector("[data-document-message]"),re=document.querySelector("[data-sync-note]"),oe=document.querySelector("[data-document-outline]"),ae=document.querySelector("[data-analyse-manuscript-structure]"),ce=document.querySelector("[data-apply-structure-sync]"),ie=document.querySelector("[data-structure-preview-status]"),se=document.querySelector("[data-structure-preview-results]"),de=document.querySelector("[data-refresh-plotdirector-scene]"),le=document.querySelector("[data-plotdirector-scene-status]"),ue=document.querySelector("[data-anchor-status]"),pe=document.querySelector("[data-anchor-book-id]"),he=document.querySelector("[data-anchor-chapter-id]"),me=document.querySelector("[data-anchor-scene-id]"),ge=document.querySelector("[data-attach-plotdirector-ids]"),ye=document.querySelector("[data-unlink-word-document]"),we=document.querySelector("[data-clean-unlink-word-document]"),fe=document.querySelector("[data-marker-binding-status]"),be=document.querySelector("[data-marker-chapter-count]"),Ie=document.querySelector("[data-marker-scene-count]"),Ce=document.querySelector("[data-unlink-dialog-chapter-count]"),Se=document.querySelector("[data-unlink-dialog-scene-count]"),ke=document.querySelector("[data-clean-dialog-chapter-count]"),ve=document.querySelector("[data-clean-dialog-scene-count]"),xe=document.querySelector("[data-plotdirector-scene-details]"),Pe=document.querySelector("[data-plotdirector-scene-title]"),De=document.querySelector("[data-plotdirector-revision-status]"),Ee=document.querySelector("[data-plotdirector-estimated-words]"),Ne=document.querySelector("[data-plotdirector-actual-words]"),Le=document.querySelector("[data-plotdirector-blocked-status]"),qe=document.querySelector("[data-plotdirector-blocked-reason-row]"),Ae=document.querySelector("[data-plotdirector-blocked-reason]"),$e=document.querySelector("[data-runtime-last-sync]"),Te=document.querySelector("[data-sync-scene-progress]"),We=document.querySelector("[data-sync-word-count]"),je=document.querySelector("[data-sync-plotdirector-count]"),Re=document.querySelector("[data-sync-last-synced]"),Ue=document.querySelector("[data-sync-status]"),Me=document.querySelector("[data-writing-brief-block]"),Oe=document.querySelector("[data-writing-brief]"),Be=document.querySelector("[data-plotdirector-link-groups]"),He=document.querySelector("[data-character-review-summary]"),Ge=document.querySelector("[data-asset-review-summary]"),Fe=document.querySelector("[data-location-review-summary]"),Ve=document.querySelector("[data-character-chips]"),Ke=document.querySelector("[data-asset-chips]"),Ye=(document.querySelector("[data-location-chips]"),document.querySelector("[data-primary-location-select]")),Je=document.querySelector("[data-save-scene-links]"),_e=document.querySelector("[data-scene-links-status]"),ze=document.querySelector("[data-links-editing-scene]"),Qe=document.querySelector("[data-chapter-create-link]"),Xe=document.querySelector("[data-chapter-create-link-chapter]"),Ze=document.querySelector("[data-create-plotdirector-chapter]"),et=document.querySelector("[data-link-existing-chapter]"),tt=document.querySelector("[data-chapter-create-link-status]"),nt=document.querySelector("[data-scene-create-link]"),rt=document.querySelector("[data-create-link-chapter]"),ot=document.querySelector("[data-create-link-scene]"),at=document.querySelector("[data-create-plotdirector-scene]"),ct=document.querySelector("[data-link-existing-scene]"),it=document.querySelector("[data-create-link-status]"),st=document.querySelector("[data-link-existing-dialog]"),dt=document.querySelector("[data-link-scene-search]"),lt=document.querySelector("[data-link-scene-options]"),ut=document.querySelector("[data-link-selected-scene]"),pt=document.querySelector("[data-link-dialog-cancel]"),ht=document.querySelector("[data-link-dialog-status]"),mt=document.querySelector("[data-create-scene-dialog]"),gt=document.querySelector("[data-create-dialog-scene]"),yt=document.querySelector("[data-create-dialog-chapter]"),wt=document.querySelector("[data-create-dialog-confirm]"),ft=document.querySelector("[data-create-dialog-cancel]"),bt=document.querySelector("[data-link-existing-chapter-dialog]"),It=document.querySelector("[data-link-chapter-search]"),Ct=document.querySelector("[data-link-chapter-options]"),St=document.querySelector("[data-link-selected-chapter]"),kt=document.querySelector("[data-link-chapter-dialog-cancel]"),vt=document.querySelector("[data-link-chapter-dialog-status]"),xt=document.querySelector("[data-create-chapter-dialog]"),Pt=document.querySelector("[data-create-chapter-dialog-chapter]"),Dt=document.querySelector("[data-create-chapter-dialog-book]"),Et=document.querySelector("[data-create-chapter-dialog-confirm]"),Nt=document.querySelector("[data-create-chapter-dialog-cancel]"),Lt=document.querySelector("[data-apply-structure-sync-dialog]"),qt=document.querySelector("[data-apply-structure-sync-summary]"),At=document.querySelector("[data-apply-structure-sync-confirm]"),$t=document.querySelector("[data-apply-structure-sync-cancel]"),Tt=document.querySelector("[data-resolve-project-id]"),Wt=document.querySelector("[data-resolve-project-title]"),jt=document.querySelector("[data-resolve-book-id]"),Rt=document.querySelector("[data-resolve-book-title]"),Ut=document.querySelector("[data-resolve-detected-chapter]"),Mt=document.querySelector("[data-resolve-detected-scene]"),Ot=document.querySelector("[data-resolve-request-chapter]"),Bt=document.querySelector("[data-resolve-request-scene]"),Ht=document.querySelector("[data-resolve-result]"),Gt=document.querySelector("[data-resolve-chapter-id]"),Ft=document.querySelector("[data-resolve-scene-id]"),Vt=document.querySelector("[data-run-diagnostics]"),Kt=document.querySelector("[data-diagnostic-host]"),Yt=document.querySelector("[data-diagnostic-platform]"),Jt=document.querySelector("[data-diagnostic-ready]"),_t=document.querySelector("[data-diagnostic-word-api]"),zt=document.querySelector("[data-diagnostic-last-scan]"),Qt=document.querySelector("[data-diagnostic-last-error]"),Xt=document.querySelector("[data-diagnostic-anchor-type]"),Zt=document.querySelector("[data-diagnostic-stored-scene-id]"),en=document.querySelector("[data-diagnostic-stored-chapter-id]"),tn=document.querySelector("[data-diagnostic-resolution-method]"),nn=document.querySelector("[data-diagnostic-paragraphs]"),rn=document.querySelector("[data-diagnostic-heading1]"),on=document.querySelector("[data-diagnostic-heading2]"),an="true"===a?.dataset.authenticated,cn=Number.parseInt(a?.dataset.userId||"",10),sn=String(a?.dataset.companionVersion||"20C").trim();let dn=[],ln=[],un=!1,pn=!1,hn="Unknown",mn="Unknown",gn="",yn="",wn=null,fn=null,bn=null,In=null,Cn=null,Sn=null,kn="",vn="Title Match",xn=!1,Pn=[],Dn=null,En=null,Nn=[],Ln=null,qn=null,An=null,$n=null,Tn=null,Wn=null,jn=null,Rn=null,Un=null,Mn=null,On=[],Bn=null,Hn=!1,Gn=!1,Fn=0,Vn=!1,Kn=!1,Yn=!1,Jn=null,_n="Manual",zn=!1,Qn=null,Xn=!1,Zn=0,er=!1,tr=0,nr=null;const rr=1200;let or=!1,ar=!1,cr=null,ir=!1,sr=!1,dr=null,lr=null,ur=null,pr=!1,hr=!1,mr=null,gr="",yr=[],wr=null,fr="",br=null,Ir="",Cr=[],Sr=null,kr="",vr=null,xr="",Pr=[],Dr=null,Er="",Nr="",Lr="",qr="",Ar=0,$r=null,Tr=null,Wr={characters:[],assets:[],locations:[],primaryLocationId:null},jr={chapterCount:0,sceneCount:0,totalCount:0,available:!1,message:"Not inspected"};const Rr="PD-CHAPTER-",Ur="PD-SCENE-",Mr=e=>{const t=String(e?.tag||"").trim().toUpperCase();return t.startsWith(Rr)?"chapter":t.startsWith(Ur)?"scene":""};window.PlotDirectorWordMarkers={classify:Mr};const Or=e=>{const t=Date.now();t-Ar<1e3||(Ar=t,console.debug(`[Word Companion Runtime] ${e}`))},Br=e=>{console.debug(`[Word Companion Timing] ${e}`)},Hr=e=>{O&&(O.textContent=e)},Gr=e=>"links"===e?"review":"structure"===e?"maintenance":e,Fr=(e,t=!0)=>{const r=Gr(e),a=o.has(r)&&i.some(e=>e.dataset.tabButton===r)?r:"scene";for(const e of i){const t=e.dataset.tabButton===a;e.classList.toggle("is-active",t),e.setAttribute("aria-selected",t?"true":"false")}for(const e of s){const t=e.dataset.tabPanel===a;e.classList.toggle("is-active",t),e.hidden=!t}t&&((e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}})(n,a)},Vr=()=>{const e=Gr((e=>{try{return window.localStorage.getItem(e)||""}catch{return""}})(n));Fr(o.has(e)?e:"scene",!1)},Kr=e=>{B&&(B.textContent=e),H&&(H.textContent=e)},Yr=e=>{J&&(J.textContent=e)},Jr=e=>{_&&(_.textContent=e)},_r=e=>{ne&&(ne.textContent=e)},zr=e=>{le&&(le.textContent=e)},Qr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("anchorType")&&Fo(Xt,fo(e.anchorType)),t("storedSceneId")&&Fo(Zt,fo(e.storedSceneId)),t("storedChapterId")&&Fo(en,fo(e.storedChapterId)),t("resolutionMethod")&&Fo(tn,fo(e.resolutionMethod))},Xr=()=>{const e=ta(),t=Number.isInteger(Cn)&&Cn>0&&In===Cn,n=!Number.isInteger(Sn)||Sn<=0||bn===Sn,r=t&&n;Fo(ue,r?"Attached to PlotDirector":"Not attached"),Fo(pe,e?.bookId?String(e.bookId):"-"),Fo(he,Number.isInteger(Sn)&&Sn>0?String(Sn):"-"),Fo(me,Number.isInteger(Cn)&&Cn>0?String(Cn):"-"),ge&&(to(ge,r&&!xn),ge.disabled=!Cn||r&&!xn,ge.textContent=In&&!r?"Reattach PlotDirector IDs":"Attach PlotDirector IDs"),Qr({anchorType:vn||"Title Match",storedSceneId:In,storedChapterId:bn,resolutionMethod:kn})},Zr=(e,t,n,r=null,o=null,a=null)=>{const c=e||"",i=t||"",s=Number.isInteger(n)?n:null,d=Number.isInteger(a)&&a>0?a:null,l=Number.isInteger(r)&&r>0?r:null,u=Number.isInteger(o)&&o>0?o:null,p=gn===c&&yn===i&&wn===s&&fn===d&&bn===l&&In===u;gn=e||"",yn=t||"",wn=Number.isInteger(n)?n:null,fn=Number.isInteger(a)&&a>0?a:null,bn=Number.isInteger(r)&&r>0?r:null,In=Number.isInteger(o)&&o>0?o:null,p||(X&&(X.textContent=e||"Not detected"),Z&&(Z.textContent=t||"Not detected"),ee&&(ee.textContent=Number.isInteger(n)?String(n):"-"),Fo(We,Number.isInteger(n)?String(n):"-"),Xr())},eo=()=>{cr&&(window.clearTimeout(cr),cr=null)},to=(e,t)=>{e&&(e.hidden=t)},no=()=>{to(ye,!$n)},ro=(e=jr)=>{const t=fa();Fo(fe,t?"Linked":"Not linked"),Fo(be,e.available?String(e.chapterCount):"-"),Fo(Ie,e.available?String(e.sceneCount):"-"),Fo(Ce,e.available?String(e.chapterCount):"-"),Fo(Se,e.available?String(e.sceneCount):"-"),Fo(ke,e.available?String(e.chapterCount):"-"),Fo(ve,e.available?String(e.sceneCount):"-"),we&&(we.disabled=!pn||!un)},oo=async()=>{if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return jr={chapterCount:0,sceneCount:0,totalCount:0,available:!1,message:"Word document access is unavailable."},ro(),jr;try{return jr=await window.Word.run(async e=>{const t=e.document.contentControls;t.load("items/tag,title"),await e.sync();let n=0,r=0;for(const e of t.items||[]){const t=Mr(e);"chapter"===t?n+=1:"scene"===t&&(r+=1)}return{chapterCount:n,sceneCount:r,totalCount:n+r,available:!0,message:"Marker inspection complete."}}),ro(jr),jr}catch(e){throw console.error("Unable to inspect PlotDirector markers.",e),jr={chapterCount:0,sceneCount:0,totalCount:0,available:!1,message:`Unable to inspect markers: ${Ko(e)}`},ro(),e}},ao=e=>{Fo(Ue,e)},co=e=>{Fo(ie,e)},io=(e="Select a project and book to analyse manuscript structure.")=>{if(An=null,se){se.innerHTML="";const e=document.createElement("p");e.textContent="No preview generated.",se.append(e)}co(e),lo()},so=(e=An)=>((e=An)=>Ka.flatMap(t=>Array.isArray(e?.[t.key])?e[t.key]:[]))(e).filter(e=>"couldLink"===e.category||"wouldCreateChapters"===e.category||"wouldCreateScenes"===e.category),lo=()=>{ce&&(ce.disabled=Yn||0===so().length)},uo=()=>{ae&&(ae.disabled=Yn||!ea()||!ta()),lo()},po=()=>{ze&&(ze.textContent=Cn?`Editing links for: ${Lr||yn||"Current scene"}`:"Link a PlotDirector scene first.")},ho=()=>{const e=zn||!Cn,t=e||!Sn||ir;Te&&(Te.disabled=t),Je&&(Je.disabled=e),Ye&&(Ye.disabled=e);for(const t of[Ve,Ke])for(const n of t?[...t.querySelectorAll("input[type='checkbox']")]:[])n.disabled=e},mo=e=>{"Live"!==e&&"Manual"!==e||(_n=e),Fo(te,e||_n||"Manual")},go=(e,t="")=>{zn=!!e,zn&&(eo(),Oc()),Fo(te,zn?"Stale":_n),ho(),t&&(_r(t),ko(t))},yo=(e,t=null,n="")=>{Cn=Number.isInteger(e)&&e>0?e:null,Sn=Number.isInteger(t)&&t>0?t:null,kn=n||"",Cn!==dr&&(lr=null),Cn||(eo(),Oc()),ho(),ao(zn?"Refresh Current Scene before syncing.":Cn?"Ready to sync.":"No resolved PlotDirector scene."),ko(zn?"Refresh Current Scene before saving.":Cn?"Ready to save.":"Link a PlotDirector scene first."),po(),Xr()},wo=e=>{z&&(z.disabled=e,z.textContent=e?"Refreshing...":"Refresh Current Scene")},fo=e=>null==e||""===e?"-":String(e),bo=e=>{if(!e)return"-";const t=e instanceof Date?e:new Date(e);if(Number.isNaN(t.getTime()))return"-";const n=new Date;return`Last synced: ${t.toDateString()===n.toDateString()?"Today":t.toLocaleDateString()} ${t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`},Io=e=>{Tn=e||null;const t=Tn?.lastSyncUtc||Tn?.manuscriptDocument?.lastSyncUtc;Fo($e,bo(t)),Fo(Re,bo(t)),Zo()},Co=()=>{Wn=null,jn=null,Rn=null,tr+=1,nr=null,Bc(),Hc(),Gc(),Io(null)},So=()=>{jn=null,Rn=null},ko=e=>{Fo(_e,e)},vo=e=>{Fo(it,e)},xo=e=>{Fo(tt,e)},Po=()=>!!ta()&&!!gn&&!Sn,Do=()=>!!ta()&&!!yn&&Number.isInteger(Sn)&&Sn>0,Eo=()=>{to(Qe,!0),xo(""),Ze&&(Ze.disabled=!0,Ze.textContent="Create Chapter in PlotDirector"),et&&(et.disabled=!0,et.textContent="Link to Existing Chapter")},No=(e="")=>{Fo(Xe,fo(gn)),to(Qe,!1),xo(e);const t=Po();Ze&&(Ze.disabled=!t,Ze.textContent="Create Chapter in PlotDirector"),et&&(et.disabled=!t,et.textContent="Link to Existing Chapter")},Lo=()=>{to(nt,!0),vo(""),at&&(at.disabled=!0,at.textContent="Create Scene in PlotDirector"),ct&&(ct.disabled=!0,ct.textContent="Link to Existing Scene")},qo=(e="")=>{Fo(rt,fo(gn)),Fo(ot,fo(yn)),to(nt,!1),vo(e);const t=Do();at&&(at.disabled=!t,at.textContent="Create Scene in PlotDirector"),ct&&(ct.disabled=!t,ct.textContent="Link to Existing Scene")},Ao=e=>{zr(e),to(xe,!0),to(Me,!0),to(Be,!1),Eo(),Lo(),kn="",Lr="",qr="",vn=In?"SceneID Anchor":bn?"ChapterID Anchor":"Title Match",xn=!1,Wr={characters:[],assets:[],locations:[],primaryLocationId:null},To(Ve,[],"character"),To(Ke,[],"asset"),Wo([],null,!1),ka(),yo(null),Fo(je,"-"),Fo(Pe,"-"),Fo(De,"-"),Fo(Ee,"-"),Fo(Ne,"-"),Fo(Le,"-"),Fo(Ae,"-"),to(qe,!0),Xr(),po()},$o=(e,t)=>"asset"===t?e?.assetId||e?.AssetId||e?.storyAssetId||e?.StoryAssetId||0:"location"===t?e?.locationId||e?.LocationId||0:e?.characterId||e?.CharacterId||0,To=(e,t,n,r=!1)=>{if(!e)return;e.innerHTML="";const o=Array.isArray(t)?t:[];if(0===o.length){const t=document.createElement("p");return t.className="word-companion-empty-list",t.textContent="None",void e.append(t)}for(const t of o){const o=Number.parseInt($o(t,n),10);if(!Number.isInteger(o)||o<=0)continue;const a=document.createElement("label");a.className="word-companion-check-item";const c=document.createElement("input");c.type="checkbox",c.value=String(o),c.checked=!!t.linked,c.disabled=!r;const i=document.createElement("span");i.textContent=t.name||"Unnamed",a.append(c,i),e.append(a)}},Wo=(e,t,n=!1)=>{if(!Ye)return;Ye.innerHTML="";const r=document.createElement("option");r.value="",r.textContent="None",Ye.append(r);const o=Number.parseInt(t||"",10);for(const t of Array.isArray(e)?e:[]){const e=Number.parseInt($o(t,"location"),10);if(!Number.isInteger(e)||e<=0)continue;const n=document.createElement("option");n.value=String(e),n.textContent=t.name||"Unnamed",n.selected=e===o,Ye.append(n)}Ye.disabled=!n},jo=e=>String(e||"").trim().replace(/\s+/g," "),Ro=(e,t)=>{const n=jo(e);if(!n)return"";const r=new RegExp(`^${"scene"===t?"scene":"chapter"}\\s+(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\\s*(?::|-|\\u2013|\\u2014)\\s*`,"i");return jo(n.replace(r,""))||n},Uo=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("projectId")&&Fo(Tt,fo(e.projectId)),t("projectTitle")&&Fo(Wt,fo(e.projectTitle)),t("bookId")&&Fo(jt,fo(e.bookId)),t("bookTitle")&&Fo(Rt,fo(e.bookTitle)),t("detectedChapter")&&Fo(Ut,fo(e.detectedChapter)),t("detectedScene")&&Fo(Mt,fo(e.detectedScene)),t("requestChapter")&&Fo(Ot,fo(e.requestChapter)),t("requestScene")&&Fo(Bt,fo(e.requestScene)),t("result")&&Fo(Ht,fo(e.result)),t("chapterId")&&Fo(Gt,fo(e.chapterId)),t("sceneId")&&Fo(Ft,fo(e.sceneId))},Mo=async e=>{if(Rn===e&&Array.isArray(jn?.chapters))return jn.chapters;const t=await fc(`/api/word-companion/books/${e}/structure`);return Rn=e,jn=t||null,Array.isArray(t?.chapters)?t.chapters:[]},Oo=async e=>{const t=await fc(`/api/word-companion/books/${e}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},Bo=e=>{if(Number.isInteger(Sn)&&Sn>0){const t=e.find(e=>e.chapterId===Sn);if(t)return t}const t=Ro(gn,"chapter").toLocaleLowerCase();return t&&e.find(e=>Ro(e.title,"chapter").toLocaleLowerCase()===t)||null},Ho=async()=>{const e=ta();return e?Bo(await Mo(e.bookId)):null},Go=async(e,t,n,r,o)=>{const a=await fc(`/api/word-companion/scenes/${t}/companion`);try{a.revisionStatus=await(async(e,t)=>{const n=await fc(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=(Array.isArray(e.scenes)?e.scenes:[]).find(e=>e.sceneId===t);if(n)return n.revisionStatus||""}return""})(e,t)}catch{a.revisionStatus=""}var c;vn=o||"Title Match",xn=!1,go(!1),zr("Linked to PlotDirector"),_r(""),Eo(),Lo(),yo(t,n,r),c=a,Lr=c?.sceneTitle||yn||"",qr=c?.chapterTitle||gn||"",Fo(Pe,fo(c?.sceneTitle)),Fo(De,fo(c?.revisionStatus||c?.revisionStatusName||"Not provided")),Fo(Ee,fo(c?.estimatedWords)),Fo(Ne,fo(c?.actualWords)),Fo(je,fo(c?.actualWords)),Fo(Le,c?.blocked?"Blocked":"Not blocked"),c?.blockedReason?(Fo(Ae,c.blockedReason),to(qe,!1)):(Fo(Ae,"-"),to(qe,!0)),Oe&&(Oe.textContent=c?.writingBrief||"No writing brief has been added for this scene."),Wr={characters:Array.isArray(c?.characters)?c.characters:[],assets:Array.isArray(c?.assets)?c.assets:[],locations:Array.isArray(c?.locations)?c.locations:[],primaryLocationId:c?.primaryLocationId??null},To(Ve,Wr.characters,"character",!!Cn&&!zn),To(Ke,Wr.assets,"asset",!!Cn&&!zn),Wo(Wr.locations,Wr.primaryLocationId,!!Cn&&!zn),ka(),po(),ko(zn?"Refresh Current Scene before saving.":Cn?"Ready to save.":"No resolved PlotDirector scene."),to(xe,!1),to(Me,!1),to(Be,!1),Cc(t,n),Mc(),zc()},Fo=(e,t)=>{if(e){const n=null==t?"":String(t);e.textContent!==n&&(e.textContent=n)}},Vo=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("host")&&Fo(Kt,e.host),t("platform")&&Fo(Yt,e.platform),t("ready")&&Fo(Jt,e.ready),t("wordApi")&&Fo(_t,e.wordApi),t("lastScan")&&Fo(zt,e.lastScan),t("lastError")&&Fo(Qt,e.lastError),t("paragraphs")&&Fo(nn,e.paragraphs),t("heading1")&&Fo(rn,e.heading1),t("heading2")&&Fo(on,e.heading2)},Ko=e=>{const t=[];return e?.name&&t.push(e.name),e?.code&&e.code!==e.name&&t.push(e.code),e?.message&&t.push(e.message),e?.debugInfo?.errorLocation&&t.push(`Location: ${e.debugInfo.errorLocation}`),t.length>0?t.join(": "):String(e)},Yo=async()=>{if(!window.Office||"function"!=typeof window.Office.onReady)return un=!1,pn=!1,hn="Unavailable",mn="Unavailable",Vo({host:hn,platform:mn,ready:"No",wordApi:"No"}),null;const e=await window.Office.onReady();return un=!0,hn=e?.host||"Unknown",mn=e?.platform||"Unknown",pn=!!window.Word&&!!window.Office.HostType&&e?.host===window.Office.HostType.Word,Vo({host:hn,platform:mn,ready:"Yes",wordApi:pn?"Yes":"No"}),e},Jo=e=>{try{const t=window.localStorage.getItem(e),n=Number.parseInt(t||"",10);return Number.isInteger(n)&&n>0?n:null}catch{return null}},_o=(e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}},zo=(e,t)=>{if(!e)return;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent=t,e.append(n),e.disabled=!0},Qo=(e,t,n,r,o)=>{if(!e)return;e.innerHTML="";const a=document.createElement("option");a.value="",a.textContent=t,e.append(a);for(const t of n){const n=document.createElement("option");n.value=String(t[r]),n.textContent=t[o],e.append(n)}e.disabled=0===n.length},Xo=e=>{const t=String(e?.displayTitle||"").trim();if(t)return t;const n=String(e?.title||"").trim(),r=String(e?.subtitle||"").trim();return r?`${n}: ${r}`:n},Zo=()=>{const e=!!$n;to(d,!e),to(Y,e),e&&(Fo(l,Tn?.projectTitle||ea()?.title||"Project"),Fo(u,Tn?.bookTitle||Xo(ta())||"Book")),ro()},ea=()=>{const e=Number.parseInt(V?.value||"",10);return dn.find(t=>t.projectId===e)||null},ta=()=>{const e=Number.parseInt(K?.value||"",10);return ln.find(t=>t.bookId===e)||null},na=()=>{const e=Number.parseInt(h?.value||"",10);return dn.find(t=>t.projectId===e)||null},ra=()=>{const e=Number.parseInt(m?.value||"",10);return ln.find(t=>t.bookId===e)||null},oa=()=>{const t=$n?.projectId||na()?.projectId||ea()?.projectId||Jo(e);return Number.isInteger(t)&&t>0?t:null},aa=()=>{const e=$n?.bookId||ra()?.bookId||ta()?.bookId||Jo(t);return Number.isInteger(e)&&e>0?e:null},ca=()=>{const e=String(window.Office?.context?.document?.url||"").trim();if(!e)return"";const t=e.split(/[\\/]/).filter(Boolean).pop()||"";try{return decodeURIComponent(t)}catch{return t}},ia=()=>({userID:Number.isInteger(cn)&&cn>0?cn:null,companionVersion:sn,machineName:"",documentOpen:!!pn,currentDocumentName:ca(),linkedProjectID:oa(),linkedBookID:aa()}),sa=()=>{(async()=>{$r&&$r.state===signalR.HubConnectionState.Connected&&await $r.invoke("CompanionHeartbeat",ia())})().catch(e=>{console.debug("Word Companion heartbeat unavailable.",e)})},da=async()=>{an&&window.signalR&&!$r&&($r=(new signalR.HubConnectionBuilder).withUrl("/hubs/word-companion-follow").withAutomaticReconnect().build(),$r.onreconnected(sa),$r.on("ScanCurrentDocument",e=>{Oa(e)}),$r.on("UpdateOnboardingBuildMarkers",e=>{Ba(e)}),$r.onclose(()=>{Tr&&(window.clearInterval(Tr),Tr=null)}),await $r.start(),await $r.invoke("RegisterCompanion",ia()),Tr=window.setInterval(sa,25e3))};window.addEventListener("beforeunload",()=>{Tr&&(window.clearInterval(Tr),Tr=null),$r&&$r.stop().catch(()=>{})});const la=e=>Fo(b,e),ua=()=>{const e=na(),t=ra(),n=Gn&&Date.now()-Fn>=750;w&&(w.disabled=!e||!t||Vn),y&&(y.disabled=!e||!String(g?.value||"").trim()||Vn),N&&(N.disabled=!Un?.canImport||!Mn||Vn),x&&(x.disabled=!n||Kn||0===ga().length)},pa=e=>{to(p,!e),to(c,e),no(),Zo();for(const t of s)to(t,!!e||"scene"!==t.dataset.tabPanel&&!t.classList.contains("is-active"));e||Vr()},ha=()=>{if(!h)return;if(0===dn.length)return void zo(h,"No projects available.");Qo(h,"Choose a project",dn,"projectId","title");const e=Number.parseInt(V?.value||"",10);Number.isInteger(e)&&e>0&&(h.value=String(e))},ma=(e="Select a Project and Book to begin.")=>{Un=null,Mn=null,On=[],Hn=!1,Gn=!1,Fn=0,to(I,!0),to(E,!0),to(C,!0),to(v,!0),I&&(I.innerHTML=""),k&&(k.innerHTML=""),Fo(S,""),la(e),ua()},ga=()=>k?[...k.querySelectorAll("input[type='checkbox']:checked")].map(e=>String(e.value||"").trim()).filter(Boolean):[],ya=e=>{if(On=Array.isArray(e)?e:[],C&&k){if(k.innerHTML="",to(C,!1),to(v,!Hn||0===On.length),to(x,!1),to(P,!1),to(D,!0),0===On.length)return Fo(S,"No likely major characters found."),void ua();Fo(S,`${On.length} likely major characters found.`);for(const e of On){const t=document.createElement("label");t.className="word-companion-character-candidate";const n=document.createElement("input");n.type="checkbox",n.value=e.text||"",n.checked="high"===String(e.confidence||"").trim().toLowerCase(),n.addEventListener("change",ua);const r=document.createElement("strong");r.textContent=e.text||"";const o=document.createElement("em"),a=String(e.reason||"").trim();o.textContent=a?`${Number(e.mentionCount||0).toLocaleString()} mentions · ${a}`:`${Number(e.mentionCount||0).toLocaleString()} mentions`;const c=document.createElement("span");c.className="word-companion-character-candidate-text",c.append(r,o),t.append(n,c),k.append(t)}ua()}},wa=()=>{const e=window.Office?.context?.document?.settings;if(!e)return null;const t=String(e.get(r.documentGuid)||"").trim(),n=Number.parseInt(e.get(r.bookId)||"",10),o=Number.parseInt(e.get(r.projectId)||"",10),a=Number.parseInt(e.get(r.bindingVersion)||"",10);return!t||!Number.isInteger(n)||n<=0||!Number.isInteger(o)||o<=0?null:{documentGuid:t,bookId:n,projectId:o,bindingVersion:Number.isInteger(a)&&a>0?a:1}},fa=()=>{const e=$n||wa();if(e)return e;const t=Tn?.manuscriptDocument?.documentGuid||"",n=Number.parseInt(Tn?.bookId||"",10),r=Number.parseInt(Tn?.projectId||"",10);return t&&Number.isInteger(n)&&n>0&&Number.isInteger(r)&&r>0?{documentGuid:t,bookId:n,projectId:r,bindingVersion:Number.parseInt(Tn?.manuscriptDocument?.bindingVersion||"",10)||1}:null},ba=()=>new Promise((e,t)=>{const n=window.Office?.context?.document?.settings;if(n){for(const e of Object.values(r))"function"==typeof n.remove?n.remove(e):n.set(e,"");n.saveAsync(n=>{n.status===window.Office.AsyncResultStatus.Succeeded?e():t(n.error||new Error("Unable to remove Word document metadata."))})}else t(new Error("Word document settings are unavailable."))}),Ia=()=>$n?.documentGuid?$n.documentGuid:window.crypto?.randomUUID?window.crypto.randomUUID():"10000000-1000-4000-8000-100000000000".replace(/[018]/g,e=>(Number(e)^16*Math.random()>>Number(e)/4).toString(16)),Ca=()=>$n?.documentGuid||wa()?.documentGuid||"",Sa=()=>{const e=ea(),t=ta();G&&(G.textContent=e?.title||"(Not connected)"),F&&(F.textContent=t?Xo(t):"(Not connected)"),re&&(re.textContent=t?"":"Select a PlotDirector book before refreshing."),uo(),Zo()},ka=()=>{const e=Array.isArray(Wr.characters)?Wr.characters.length:0,t=Array.isArray(Wr.assets)?Wr.assets.length:0,n=Array.isArray(Wr.locations)?Wr.locations.length:0;Fo(He,`Characters (${e})`),Fo(Ge,`Assets (${t})`),Fo(Fe,`Locations (${n})`)},va=e=>String(e?.styleBuiltIn||e?.style||"").replace(/\s+/g,"").toLowerCase(),xa=(e,t)=>{const n=va(e);return n===`heading${t}`||n.endsWith(`.heading${t}`)||n.includes(`heading${t}`)},Pa=e=>String(e||"").trim().split(/\s+/).filter(Boolean).length,Da=(e,t)=>{const n=String(e||"").match(new RegExp(`^${t}-(\\d+)$`,"i"));if(!n)return null;const r=Number.parseInt(n[1],10);return Number.isInteger(r)&&r>0?r:null},Ea=e=>{try{return Array.isArray(e?.contentControls?.items)?e.contentControls.items:[]}catch(e){return console.warn("Word paragraph content controls were not available.",e),[]}},Na=(e,t)=>{const n=Ea(e);for(const e of n){const n=Da(e.tag,t);if(n)return n}return null},La=(e,t)=>{const n=[];let r=0,o=0,a=null,c=null;e.forEach((e,t)=>{const i=String(e.text||"").trim();if(i){if(xa(e,1))return r+=1,a={index:n.length+1,paragraphIndex:t,title:i,anchorId:Na(e,"PD-CHAPTER"),scenes:[]},n.push(a),void(c=null);if(xa(e,2)){if(o+=1,!a)return;return c={index:a.scenes.length+1,paragraphIndex:t,title:i,anchorId:Na(e,"PD-SCENE"),wordCount:0},void a.scenes.push(c)}c&&(c.wordCount+=Pa(i))}});const i=t.find(e=>String(e.text||"").trim()),s=i?e.findIndex(e=>{return t=e,n=i,String(t?.text||"").trim()===String(n?.text||"").trim()&&va(t)===va(n);var t,n}):-1,d=s>=0&&n.filter(e=>e.paragraphIndex<=s).at(-1)||null,l=d&&s>=0&&d.scenes.filter(e=>e.paragraphIndex<=s).at(-1)||null;return{chapters:n,currentChapter:d,currentScene:l,paragraphCount:e.length,heading1Count:r,heading2Count:o}},qa=new Set(["***","###"]),Aa=(e,t)=>{const n=String(e?.text||"").trim();return{index:t,text:n,styleBuiltIn:e?.styleBuiltIn||"",style:e?.style||"",wordCount:Pa(n),chapterAnchorId:null,sceneAnchorId:null}},$a=(e,t)=>{e&&(e.endParagraphIndex=t)},Ta=(e,t)=>{e&&(e.endParagraphIndex=t,$a(e.scenes.at(-1),t))},Wa=(e,t,n)=>e?.[t]??e?.[n]??null,ja=(e,t)=>{const n=[],r=[],o=[];let a=null,c=null,i=0,s=0,d=!1;const l=()=>{c=null},u=(e,t,r=!1)=>(l(),a={temporaryChapterKey:`chapter-${n.length+1}`,chapterNumber:n.length+1,title:t,wordCount:0,chapterTextParagraphs:[],chapterText:"",startPosition:e?.index??null,existingChapterID:r?null:Na(e,"PD-CHAPTER")},n.push(a),p(e,null),a),p=(e,t=null)=>a?(l(),c={temporarySceneKey:`scene-${r.length+1}`,temporaryChapterKey:a.temporaryChapterKey,sceneNumberWithinChapter:r.filter(e=>e.temporaryChapterKey===a.temporaryChapterKey).length+1,title:t,wordCount:0,openingTextPreview:"",startPosition:e?.index??null,existingSceneID:e?Na(e,"PD-SCENE"):null},r.push(c),c):null,h=(e,t)=>{!a||!c||t<=0||(a.wordCount+=t,a.chapterTextParagraphs.push(e),c.wordCount+=t,c.openingTextPreview||!e||qa.has(e)||(c.openingTextPreview=e.length>180?`${e.slice(0,177)}...`:e))};if(e.forEach((e,t)=>{e.index=t;const n=String(e.text||"").trim();if(!n)return;const r=Pa(n);if(xa(e,1)){if(!d&&(e=>{const t=Ro(e||"","").toLocaleLowerCase();return["title page","copyright","dedication","contents","table of contents","acknowledgements","acknowledgments","about the author"].includes(t)})(n))return;return d=!0,o.push(n),s+=1,u(e,n),i+=r,a.wordCount+=r,void a.chapterTextParagraphs.push(n)}if(!a){if(!d)return;u(e,"Opening pages",!0)}if(o.push(n),xa(e,2))return p(e,n),i+=r,void h(n,r);qa.has(n)?p(e,null):(i+=r,h(n,r))}),0===i)throw new Error("The document appears to be empty. Add manuscript text, then try again.");if(0===s)throw new Error("No chapters were detected. Make sure your chapter headings use Heading 1, or add clear chapter headings.");n.forEach(e=>{e.chapterText=Array.isArray(e.chapterTextParagraphs)?e.chapterTextParagraphs.join("\n\n"):"",delete e.chapterTextParagraphs});const m=o.join("\n");return{previewID:"00000000-0000-0000-0000-000000000000",userID:Ra(t,"userID","UserID","userId"),onboardingID:Ra(t,"onboardingID","OnboardingID","onboardingId"),projectID:Ra(t,"projectID","ProjectID","projectId"),bookID:Ra(t,"bookID","BookID","bookId"),source:"WordCompanion",documentTitle:ca()||"Word manuscript",companionDocumentIdentifier:Ca(),totalWordCount:i,chapterCount:n.length,sceneCount:r.length,characterCandidateCount:0,createdUtc:(new Date).toISOString(),chapters:n,scenes:r,characterCandidates:[],documentTextForDiscovery:m}},Ra=(e,...t)=>{for(const n of t)if(null!=e?.[n])return e[n];return null},Ua=async(e,t,n,r={})=>{$r&&$r.state===signalR.HubConnectionState.Connected&&await $r.invoke("ReportOnboardingScanProgress",{userID:Ra(e,"userID","UserID","userId"),onboardingID:Ra(e,"onboardingID","OnboardingID","onboardingId"),message:t,percentComplete:n,chapterCount:r.chapterCount||0,sceneCount:r.sceneCount||0,characterCandidateCount:r.characterCandidateCount||0,totalWordCount:r.totalWordCount||0})},Ma=async(e,t)=>{$r&&$r.state===signalR.HubConnectionState.Connected&&await $r.invoke("FailOnboardingScan",{userID:Ra(e,"userID","UserID","userId"),onboardingID:Ra(e,"onboardingID","OnboardingID","onboardingId"),message:t})},Oa=async e=>{var t;if(pn&&window.Word)try{await Ua(e,"Preparing document scan",5);const n=await window.Word.run(async t=>{const n=t.document.body.paragraphs;n.load("items/text,items/style,items/styleBuiltIn"),await t.sync(),await Ua(e,"Detecting chapters",20);for(const e of n.items)(xa(e,1)||xa(e,2))&&e.contentControls.load("items/tag,title");return await t.sync(),n.items}),r=ja(n,e);await Ua(e,"Detecting scene breaks",50,r),await Ua(e,`Scene ${r.sceneCount} of ${r.sceneCount} scanned`,70,r),await Ua(e,"Finding character candidates",85,r);const o=r.documentTextForDiscovery||"";delete r.documentTextForDiscovery;try{const e=await bc("/api/word-companion/manuscript/discover-characters",{projectId:r.projectID,documentText:o,includeExcluded:!0});r.characterCandidates=(t=e?.candidates,(Array.isArray(t)?t:[]).map((e,t)=>({temporaryCharacterKey:`character-${t+1}`,name:Wa(e,"text","Text")||Wa(e,"name","Name")||"",mentionCount:Number.parseInt(Wa(e,"mentionCount","MentionCount")||"0",10)||0,qualityScore:Number.parseInt(Wa(e,"qualityScore","QualityScore")||"0",10)||0,category:Wa(e,"category","Category")||"PossibleCharacter",reason:Wa(e,"reason","Reason")||"",isExistingCharacterMatch:!!Wa(e,"isExistingCharacterMatch","IsExistingCharacterMatch"),suggestedImportance:null})).filter(e=>e.name)),r.characterCandidateCount=r.characterCandidates.filter(e=>"excluded"!==String(e.category||"").toLowerCase()).length}catch(e){console.warn("Unable to refine onboarding character candidates.",e),r.characterCandidates=[],r.characterCandidateCount=0}await Ua(e,"Preparing preview",95,r),Bn=r,await $r.invoke("CompleteOnboardingScan",r)}catch(t){console.error("Unable to complete onboarding scan.",t),await Ma(e,Ha(t))}else await Ma(e,"Open your manuscript in Microsoft Word, then try the scan again.")},Ba=async e=>{if(!Bn||!pn||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");const t=new Map((e?.chapterMappings||e?.ChapterMappings||[]).map(e=>[e.temporaryChapterKey||e.TemporaryChapterKey,e.chapterID||e.ChapterID])),n=new Map((e?.sceneMappings||e?.SceneMappings||[]).map(e=>[e.temporarySceneKey||e.TemporarySceneKey,e.sceneID||e.SceneID]));await window.Word.run(async e=>{const r=e.document.body.paragraphs;r.load("items/text,items/style,items/styleBuiltIn"),await e.sync();for(const e of Bn.chapters||[]){const n=t.get(e.temporaryChapterKey),o=Number.parseInt(e.startPosition,10);n&&Number.isInteger(o)&&r.items[o]&&Pc(r.items[o],"PlotDirector Chapter",`PD-CHAPTER-${n}`,"PD-CHAPTER")}for(const e of Bn.scenes||[]){const t=n.get(e.temporarySceneKey),o=Number.parseInt(e.startPosition,10);t&&Number.isInteger(o)&&r.items[o]&&Pc(r.items[o],"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await e.sync()}),await oo().catch(()=>null)},Ha=e=>{const t=Ko(e);return/No chapters were detected/i.test(t)?"No chapters were detected. Make sure your chapter headings use Heading 1, or add clear chapter headings.":/empty/i.test(t)?"The document appears to be empty. Add manuscript text, then try again.":/network|disconnect|connection/i.test(t)?"The Word Companion disconnected before the scan finished. Reopen Word and try again.":`The scan could not finish: ${t}`},Ga=(e,t)=>{const n=(t||[]).find(e=>String(e.text||"").trim());if(!e||!n)return e?.currentParagraphIndex??-1;const r=e.paragraphs.filter(e=>((e,t)=>String(e?.text||"").trim()===String(t?.text||"").trim()&&va(e)===va(t))(e,n)).map(e=>e.index);return 0===r.length?e.currentParagraphIndex??-1:Number.isInteger(e.currentParagraphIndex)?r.reduce((t,n)=>Math.abs(n-e.currentParagraphIndex){if(!Wn)return!1;const t=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.chapters.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(Wn,e),n=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.scenes.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(t,e),r=t?.startParagraphIndex!==Wn.currentChapter?.startParagraphIndex||n?.startParagraphIndex!==Wn.currentScene?.startParagraphIndex||t?.anchorId!==Wn.currentChapter?.anchorId||n?.anchorId!==Wn.currentScene?.anchorId;return Wn.currentParagraphIndex=e,Wn.currentChapter=t,Wn.currentScene=n,!!r&&(Zr(t?.title,n?.title,n?.wordCount,t?.anchorId,n?.anchorId,t?.index),r)},Va=e=>{if(!oe)return;if(oe.innerHTML="",0===e.chapters.length){const e=document.createElement("p");return e.textContent="No chapters detected. Use Heading 1 for chapter titles.",void oe.append(e)}if(!e.chapters.some(e=>e.scenes.length>0)){const e=document.createElement("p");e.textContent="No scenes detected. Use Heading 2 for scene titles.",oe.append(e)}for(const t of e.chapters){const e=document.createElement("div");e.className="word-companion-outline-chapter";const n=document.createElement("strong");if(n.textContent=t.title,e.append(n),t.scenes.length>0){const n=document.createElement("ul");for(const e of t.scenes){const t=document.createElement("li");t.textContent=e.title,n.append(t)}e.append(n)}oe.append(e)}},Ka=[{key:"alreadyLinked",title:"Already Linked"},{key:"couldLink",title:"Could Link"},{key:"wouldCreateChapters",title:"Would Create Chapters"},{key:"wouldCreateScenes",title:"Would Create Scenes"},{key:"manualReview",title:"Manual Review Required"}],Ya={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},Ja={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},_a=(e,t)=>Ro(e,t).toLocaleLowerCase(),za=({category:e,action:t,type:n,wordTitle:r,match:o="",anchorStatus:a="None",matches:c=[],pdChapter:i=null,pdScene:s=null,wordChapter:d=null,wordScene:l=null,parentItem:u=null})=>({id:`${n}-${d?.index||0}-${l?.index||0}-${d?.paragraphIndex??l?.paragraphIndex??0}`,category:e,action:t,type:n,wordTitle:r,match:o,anchorStatus:a,matches:c,pdChapter:i,pdScene:s,wordChapter:d,wordScene:l,parentItem:u,result:"Pending",error:""}),Qa=(e,t)=>{Array.isArray(e[t.category])&&e[t.category].push(t)},Xa=e=>Array.isArray(e?.scenes)?e.scenes:[],Za=(e,t,n)=>{const r=e.anchorId?`PD-CHAPTER-${e.anchorId}`:"None";if(e.anchorId){const o=t.find(t=>t.chapterId===e.anchorId);if(o){const t=za({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:e.title,match:`Chapter ${o.chapterId}: ${o.title}`,anchorStatus:r,pdChapter:o,wordChapter:e});return Qa(n,t),t}const a=za({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:`${r} not found`,matches:[],pdChapter:null,wordChapter:e});return Qa(n,a),a}const o=t.filter(t=>_a(t.title,"chapter")===_a(e.title,"chapter"));if(1===o.length){const t=za({category:"couldLink",action:"couldLink",type:"Chapter",wordTitle:e.title,match:`Chapter ${o[0].chapterId}: ${o[0].title}`,anchorStatus:r,pdChapter:o[0],wordChapter:e});return Qa(n,t),t}if(o.length>1){const t=za({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:r,matches:o.map(e=>`Chapter ${e.chapterId}: ${e.title}`),pdChapter:null,wordChapter:e});return Qa(n,t),t}const a=za({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:e.title,anchorStatus:r,pdChapter:null,wordChapter:e});return Qa(n,a),a},ec=(e,t,n,r)=>{const o=e.anchorId?`PD-SCENE-${e.anchorId}`:"None";if(e.anchorId){const a=((e,t)=>{for(const n of e){const e=Xa(n).find(e=>e.sceneId===t);if(e)return{chapter:n,scene:e}}return null})(n,e.anchorId);return a?void Qa(r,za({category:"alreadyLinked",action:"alreadyLinked",type:"Scene",wordTitle:e.title,match:`Scene ${a.scene.sceneId}: ${a.scene.title}`,anchorStatus:o,pdChapter:a.chapter,pdScene:a.scene,wordChapter:t?.wordChapter,wordScene:e,parentItem:t})):void Qa(r,za({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:`${o} not found`,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}))}if(!t?.pdChapter&&"manualReview"===t?.category)return void Qa(r,za({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:o,matches:["Parent chapter requires manual review."],wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));if(!t?.pdChapter)return void Qa(r,za({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));const a=Xa(t.pdChapter).filter(t=>_a(t.title,"scene")===_a(e.title,"scene"));1!==a.length?a.length>1?Qa(r,za({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:e.title,anchorStatus:o,matches:a.map(e=>`Scene ${e.sceneId}: ${e.title}`),wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Qa(r,za({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:e,parentItem:t})):Qa(r,za({category:"couldLink",action:"couldLink",type:"Scene",wordTitle:e.title,match:`Scene ${a[0].sceneId}: ${a[0].title}`,anchorStatus:o,pdChapter:t.pdChapter,pdScene:a[0],wordChapter:t.wordChapter,wordScene:e,parentItem:t}))},tc=e=>{const t=document.createElement("article");t.className="word-companion-preview-item";const n=document.createElement("strong");n.textContent=`${Ja[e.action]||""} ${e.type}: ${e.wordTitle}`,t.append(n);const r=document.createElement("span");if(r.textContent=`Anchor: ${e.anchorStatus||"None"}`,t.append(r),e.match){const n=document.createElement("span");n.textContent=`Match: ${e.match}`,t.append(n)}if(Array.isArray(e.matches)&&e.matches.length>0){const n=document.createElement("div");n.className="word-companion-preview-matches";const r=document.createElement("span");r.textContent="Matches:",n.append(r);const o=document.createElement("ul");for(const t of e.matches){const e=document.createElement("li");e.textContent=t,o.append(e)}n.append(o),t.append(n)}const o=document.createElement("span");if(o.textContent=`Action: ${Ya[e.action]||e.action}`,t.append(o),e.result&&"Pending"!==e.result){const n=document.createElement("span");n.textContent=e.error?`Result: ${e.result} - ${e.error}`:`Result: ${e.result}`,t.append(n)}return t},nc=e=>{if(se){se.innerHTML="";for(const t of Ka){const n=document.createElement("section");n.className="word-companion-preview-group";const r=document.createElement("strong");r.textContent=t.title,n.append(r);const o=Array.isArray(e?.[t.key])?e[t.key]:[];if(0===o.length){const e=document.createElement("p");e.className="word-companion-empty-list",e.textContent="None",n.append(e)}else for(const e of o)n.append(tc(e));se.append(n)}lo()}},rc=async e=>{const t=e.document.body.paragraphs,n=e.document.getSelection().paragraphs;t.load("text,styleBuiltIn,style"),n.load("text,styleBuiltIn,style"),await e.sync();try{for(const e of t.items)(xa(e,1)||xa(e,2))&&e.contentControls.load("items/tag,title");await e.sync()}catch(e){console.warn("Unable to load Word heading content controls. Continuing without PlotDirector anchors.",e)}const r=La(t.items,n.items);return r.bodyParagraphs=t.items,r},oc=async(e,t)=>{const n=e.document.body.paragraphs,r=e.document.getSelection().paragraphs;n.load("text,styleBuiltIn,style"),r.load("text,styleBuiltIn,style"),await e.sync();const o=((e,t)=>{const n=e.map(Aa),r=[];let o=0,a=0,c=null,i=null,s=0;const d=(e,t=null,n=null)=>c?($a(i,e.index-1),i={index:c.scenes.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:t||`Scene ${c.scenes.length+1}`,anchorId:n,wordCount:0},c.scenes.push(i),i):null;for(const e of n)e.text&&(xa(e,1)?(Ta(c,e.index-1),o+=1,c={index:r.length+1,paragraphIndex:e.index,startParagraphIndex:e.index,endParagraphIndex:e.index,title:e.text,anchorId:e.chapterAnchorId,wordCount:0,scenes:[]},r.push(c),i=null,d(e,"Scene 1",e.sceneAnchorId),s+=e.wordCount):c&&(t&&qa.has(e.text)?(a+=1,d(e)):(c.wordCount+=e.wordCount,i&&(i.wordCount+=e.wordCount),s+=e.wordCount)));return Ta(c,n.length-1),{paragraphs:n,chapters:r,usesExplicitScenes:!!t,paragraphCount:n.length,heading1Count:o,heading2Count:a,documentWordCount:s,currentParagraphIndex:null,currentChapter:null,currentScene:null}})(n.items,t),a=Ga(o,r.items);return Wn=o,Fa(a),Or("Cache rebuilt."),o},ac=()=>window.performance&&"function"==typeof window.performance.now?window.performance.now():Date.now(),cc=e=>!!e&&!e.stale&&e.generation===tr&&e.documentGuid===Ca()&&e.sceneId===Cn,ic=async(e={})=>{const t=!!e.includeSelection,n=!1!==e.updateDisplay,r=tr,o=ac(),a=ea(),c=ta(),i=Wn?.currentScene;if(!i||!Number.isInteger(i.startParagraphIndex)||!Number.isInteger(i.endParagraphIndex))return null;if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return null;const s=ac(),d=await window.Word.run(async e=>{const n=e.document.body.paragraphs;n.load("text");let r=null;return t&&(r=e.document.getSelection().paragraphs,r.load("text,styleBuiltIn,style")),await e.sync(),{bodyTexts:n.items.map(e=>String(e.text||"")),selectionParagraphs:t&&r?r.items.map(e=>({text:String(e.text||""),styleBuiltIn:e.styleBuiltIn,style:e.style})):[]}}),l=Math.round(ac()-s);if(r!==tr)return Br(`Office snapshot: ${l}ms stale`),{stale:!0,generation:r};let u=!1;if(t){const e=Ga(Wn,d.selectionParagraphs);u=Fa(e)}const p=Wn?.currentScene;if(!p||!Number.isInteger(p.startParagraphIndex)||!Number.isInteger(p.endParagraphIndex))return null;const h=[];let m=0;const g=Math.min(p.endParagraphIndex,d.bodyTexts.length-1),y=Wn.currentChapter?.startParagraphIndex;for(let e=p.startParagraphIndex;e<=g;e+=1){const t=String(d.bodyTexts[e]||"").trim();t&&!qa.has(t)&&e!==y&&(h.push(t),m+=Pa(t))}p.wordCount=m,n&&Zr(Wn.currentChapter?.title,p.title,m,Wn.currentChapter?.anchorId,p.anchorId,Wn.currentChapter?.index);const w={documentGuid:Ca(),projectId:a?.projectId||null,bookId:c?.bookId||null,chapterId:Sn,sceneId:Cn,chapterTitle:Wn.currentChapter?.title||"",sceneTitle:p.title||"",sceneText:h.join("\n"),wordCount:m,selectionSignature:`${Wn.currentParagraphIndex??-1}:${p.startParagraphIndex}:${p.endParagraphIndex}`,selectionChanged:u,generation:r};return nr=w,Br(`Office snapshot: ${l}ms; scene words: ${m}; total snapshot: ${Math.round(ac()-o)}ms`),w},sc=async()=>cc(nr)?nr:await ic(),dc=async()=>{if(_r(""),!un||!pn||!window.Word||"function"!=typeof window.Word.run)return Zr(null,null,null),_r("Word document access is unavailable."),Vo({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;Q&&(Q.disabled=!0,Q.textContent="Scanning..."),_r("Scanning document structure...");try{const e=await window.Word.run(async e=>{const t=ta();return t?await oc(e,!!t.usesExplicitScenes):(Wn=null,await rc(e))});return Wn||Zr(e.currentChapter?.title,e.currentScene?.title,e.currentScene?.wordCount,e.currentChapter?.anchorId,e.currentScene?.anchorId,e.currentChapter?.index),Ao("Not detected"),Va(e),_r(""),Vo({lastScan:"Success",lastError:"-",paragraphs:String(e.paragraphCount),heading1:String(e.heading1Count),heading2:String(e.heading2Count)}),!0}catch(e){const t=Ko(e);return console.error("Unable to scan the Word document.",e),Zr(null,null,null),_r(`Unable to scan the Word document: ${t}`),Vo({lastScan:"Failure",lastError:t}),!1}finally{Q&&(Q.disabled=!1,Q.textContent="Refresh Document Structure"),await oo().catch(()=>null)}},lc=async()=>{const e=ta();if(!ea()||!e)return co("Select a project and book to analyse manuscript structure."),!1;if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return co("Word document access is unavailable."),Vo({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;ae&&(ae.disabled=!0,ae.textContent="Analysing..."),co("Analysing manuscript structure...");try{const t=await window.Word.run(async e=>await rc(e)),n=await fc(`/api/word-companion/books/${e.bookId}/structure`);return Zr(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),Va(t),An=((e,t)=>{const n={alreadyLinked:[],couldLink:[],wouldCreateChapters:[],wouldCreateScenes:[],manualReview:[]},r=Array.isArray(t?.chapters)?t.chapters:[];for(const t of Array.isArray(e?.chapters)?e.chapters:[]){const e=Za(t,r,n);for(const o of Xa(t))ec(o,e,r,n)}return n})(t,n),nc(An),co("Preview generated. No changes have been applied."),Vo({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),!0}catch(e){return console.error("Unable to analyse manuscript structure.",e),co("Unable to analyse manuscript structure."),Vo({lastScan:"Failure",lastError:Ko(e)}),!1}finally{ae&&(ae.textContent="Analyse Manuscript Structure",uo())}},uc=e=>{Jn&&(Jn(e),Jn=null),Lt?.close?Lt.close():Lt&&(Lt.hidden=!0)},pc=()=>{const e=((e=An)=>{const t=so(e);return{linkChapters:t.filter(e=>"couldLink"===e.category&&"Chapter"===e.type).length,linkScenes:t.filter(e=>"couldLink"===e.category&&"Scene"===e.type).length,createChapters:t.filter(e=>"wouldCreateChapters"===e.category).length,createScenes:t.filter(e=>"wouldCreateScenes"===e.category).length,manualReview:Array.isArray(e?.manualReview)?e.manualReview.length:0}})();return(e=>{if(!qt)return;qt.innerHTML="";const t=[`Link ${e.linkChapters+e.linkScenes} chapters/scenes`,`Create ${e.createChapters} chapters`,`Create ${e.createScenes} scenes`],n=document.createElement("ul");for(const e of t){const t=document.createElement("li");t.textContent=e,n.append(t)}qt.append(n)})(e),Lt?new Promise(e=>{Jn=e,Lt.showModal?Lt.showModal():Lt.hidden=!1}):Promise.resolve(window.confirm(`Apply Structure Sync?\n\nThis will:\n\n- Link ${e.linkChapters+e.linkScenes} chapters/scenes\n- Create ${e.createChapters} chapters\n- Create ${e.createScenes} scenes\n\nManual review items will be skipped.`))},hc=(e,t,n="")=>{e.result=t,e.error=n},mc=e=>Number.isInteger(e?.wordChapter?.index)&&e.wordChapter.index>0?10*e.wordChapter.index:null,gc=e=>Number.isInteger(e?.wordScene?.index)&&e.wordScene.index>0?10*e.wordScene.index:null,yc=async(e,t)=>{const n=await bc(`/api/word-companion/books/${e}/chapters`,{title:jo(t.wordTitle),sortOrder:mc(t)});if(!n?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");So(),t.pdChapter={chapterId:n.chapterId,title:n.title||t.wordTitle,sortOrder:n.sortOrder||mc(t)||0,scenes:[]},t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},wc=async(e,t)=>{const n=t.pdChapter||t.parentItem?.pdChapter;if(!n?.chapterId)throw new Error("Scene parent chapter is not available.");const r=await bc(`/api/word-companion/books/${e}/chapters/${n.chapterId}/scenes`,{sceneTitle:jo(t.wordTitle),sortOrder:gc(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");So(),t.pdChapter=n,t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:gc(t)||0},t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},fc=async(e,t={})=>{const n=await window.fetch(e,{credentials:"same-origin",...t,headers:{Accept:"application/json",...t.headers||{}}});if(!n.ok)throw new Error(`Request failed: ${n.status}`);return await n.json()},bc=(e,t)=>fc(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),Ic=async(e="")=>{Gn=!1,Fn=0,On=[],k&&(k.innerHTML=""),to(C,!0),pa(!1),la(""),to(v,!0),e&&_r(e);const t=await Sc();e&&t&&gn&&_r(e)},Cc=async(e=Cn,t=Sn)=>{const n=ea(),r=ta(),o=Ca(),a=Number.parseInt(e||"",10),c=Number.parseInt(t||"",10);if(!n||!r||!o||!Number.isInteger(a)||a<=0||!Number.isInteger(c)||c<=0)return;const i=`${n.projectId}:${r.bookId}:${a}`;if(Nr!==i){Nr=i;try{await bc("/api/word-companion/runtime/current-scene",{documentGuid:o,projectId:n.projectId,bookId:r.bookId,chapterId:c,sceneId:a}),Or("Current scene follow event sent.")}catch(e){Nr="",console.debug("Unable to notify PlotDirector of current scene.",e)}}},Sc=async()=>{const e=ta();if(!(e&&un&&pn&&window.Word&&"function"==typeof window.Word.run))return!1;_r("Reading manuscript position...");try{So(),await Promise.all([Fc(!0),Vc(!0),Kc(!0)]),await Mo(e.bookId);const t=await window.Word.run(async t=>await oc(t,!!e.usesExplicitScenes));return Va(t),Vo({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),gn?(yn?await Xc():await Qc(),go(!1),mo("Live"),_r(""),!0):(Ao("Not detected"),go(!1),mo("Live"),_r("Manuscript linked. Click inside a chapter to show the current scene."),!0)}catch(e){return console.error("Unable to initialise bound manuscript runtime.",e),Wn=null,mo("Manual"),_r(`Unable to read manuscript position: ${Ko(e)}`),Vo({lastScan:"Failure",lastError:Ko(e)}),!1}},kc=async n=>{$n=null,ti(),eo(),Co(),Ao("Not detected"),mo("Manual"),Kr("Connected"),_o(e,null),_o(t,null),V&&(V.value=""),zo(K,"Select a project first"),ha(),h&&(h.value=""),zo(m,"Select a project first"),ma(n||"Select a Project and Book to begin."),_r(n||"Manuscript unlinked."),ao("No resolved PlotDirector scene."),pa(!0),no()},vc=e=>e?[...e.querySelectorAll("input[type='checkbox']:checked")].map(e=>Number.parseInt(e.value||"",10)).filter(e=>Number.isInteger(e)&&e>0):[],xc=()=>{const e=Number.parseInt(Ye?.value||"",10);return Number.isInteger(e)&&e>0?e:null},Pc=(e,t,n,r)=>{const o=((e,t)=>Ea(e).find(e=>Da(e.tag,t))||null)(e,r),a=o||e.getRange().insertContentControl();return a.title=t,a.tag=n,a.appearance="Hidden",a},Dc=async(e="PlotDirector IDs attached successfully.")=>{if(!Cn||!Sn)return _r("No resolved PlotDirector scene."),!1;if((In&&In!==Cn||bn&&bn!==Sn)&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return _r("Word document access is unavailable."),!1;ge&&(ge.disabled=!0,ge.textContent="Attaching...");try{return await window.Word.run(async e=>{const t=await rc(e);if(!t.currentChapter||!t.currentScene)throw new Error("No scene detected in Word. Use Heading 2 for scenes.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex],r=t.bodyParagraphs[t.currentScene.paragraphIndex];if(!n||!r)throw new Error("Unable to locate the current Word headings.");Pc(n,"PlotDirector Chapter",`PD-CHAPTER-${Sn}`,"PD-CHAPTER"),Pc(r,"PlotDirector Scene",`PD-SCENE-${Cn}`,"PD-SCENE"),await e.sync()}),await oo().catch(()=>null),bn=Sn,In=Cn,xn=!1,vn="SceneID Anchor",kn="Anchor",_r(e),Vo({lastError:"-"}),Xr(),!0}catch(e){return console.error("Unable to attach PlotDirector IDs.",e),_r("Unable to attach PlotDirector IDs."),Vo({lastError:Ko(e)}),Xr(),!1}finally{ge&&(ge.textContent=In===Cn?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",Xr())}},Ec=async e=>{if(!Sn)return xo("No resolved PlotDirector chapter."),!1;if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return xo("Word document access is unavailable."),!1;try{return await window.Word.run(async e=>{const t=await rc(e);if(!t.currentChapter)throw new Error("No chapter detected in Word. Use Heading 1 for chapters.");const n=t.bodyParagraphs[t.currentChapter.paragraphIndex];if(!n)throw new Error("Unable to locate the current Word chapter heading.");Pc(n,"PlotDirector Chapter",`PD-CHAPTER-${Sn}`,"PD-CHAPTER"),await e.sync()}),await oo().catch(()=>null),bn=Sn,xn=!1,vn="ChapterID Anchor",kn="Chapter anchor",xo(e),_r(e),Vo({lastError:"-"}),Xr(),!0}catch(e){return console.error("Unable to attach PlotDirector chapter ID.",e),xo("Unable to attach PlotDirector chapter ID."),Vo({lastError:Ko(e)}),Xr(),!1}},Nc=async e=>{Eo(),await Xc(),_r(e),xo(e)},Lc=e=>{qn&&(qn(e),qn=null),xt?.close?xt.close():xt&&(xt.hidden=!0)},qc=()=>{if(!Ct)return;const e=jo(It?.value||"").toLocaleLowerCase(),t=Nn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(Ct.innerHTML="",Ln=null,St&&(St.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No chapters found.",void Ct.append(e)}for(const e of t){const t=Number.parseInt(e.chapterId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-chapter",r.value=String(t),r.addEventListener("change",()=>{Ln=t,St&&(St.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled chapter",n.append(r,o),Ct.append(n)}},Ac=()=>{bt?.close?bt.close():bt&&(bt.hidden=!0)},$c=async(e,t,n)=>{const r=ta();if(!r)return vo("Select a PlotDirector book first."),!1;await Go(r.bookId,e,t,"Manual link","Title Match");return!!await Dc(n)&&(vo(n),Lo(),!0)},Tc=e=>{En&&(En(e),En=null),mt?.close?mt.close():mt&&(mt.hidden=!0)},Wc=()=>{if(!lt)return;const e=jo(dt?.value||"").toLocaleLowerCase(),t=Pn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(lt.innerHTML="",Dn=null,ut&&(ut.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No scenes found.",void lt.append(e)}for(const e of t){const t=Number.parseInt(e.sceneId||"",10);if(!Number.isInteger(t)||t<=0)continue;const n=document.createElement("label");n.className="word-companion-scene-option";const r=document.createElement("input");r.type="radio",r.name="word-companion-link-scene",r.value=String(t),r.addEventListener("change",()=>{Dn=t,ut&&(ut.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled scene",n.append(r,o),lt.append(n)}},jc=()=>{st?.close?st.close():st&&(st.hidden=!0)},Rc=()=>{ir=!1,ho(),sr&&(sr=!1,Mc(1e3))},Uc=async(e={})=>{const t=e.source||"manual",n=ac();if(!Cn)return void ao("No resolved PlotDirector scene.");if(!Sn)return void ao("No resolved PlotDirector chapter.");if(zn)return void ao("Refresh Current Scene before syncing.");const r=ta(),o=Ca();if(!r||!o)return void ao("Bound manuscript metadata is unavailable.");if(ir)return sr=!0,void Or("Scene sync deferred; sync already running.");eo(),ir=!0,sr=!1;let a=e.snapshot||null;try{a=cc(a)?a:await sc()}catch(e){return ao("Sync failed"),Vo({lastError:Ko(e)}),Or("Scene sync failed."),void Rc()}if(!cc(a))return ao("Waiting for typing to pause"),Or("Scene sync skipped (stale snapshot)."),void Rc();const c=a.wordCount;if(!Number.isInteger(c)||c<0)return ao("Sync failed"),Or("Scene sync failed."),void Rc();if(dr===a.sceneId&&lr===c)return ao("Synced"),Or("Sync skipped (count unchanged)."),void Rc();Or("Scene word count changed."),Te&&(Te.disabled=!0,Te.textContent="Syncing..."),ao("Syncing..."),Or(`Scene sync started (${t}).`);try{const e=ac(),t=await bc("/api/word-companion/runtime/scene-word-count",{documentGuid:a.documentGuid||o,bookId:a.bookId||r.bookId,chapterId:a.chapterId,sceneId:a.sceneId,wordCount:c});if(Br(`Word count sync API: ${Math.round(ac()-e)}ms`),!cc(a))return void Or("Scene sync result ignored (stale snapshot).");const i=t?.actualWords??c,s=new Date;dr=a.sceneId,lr=i,Fo(je,fo(i)),Fo(Ne,fo(i)),Fo(Re,bo(s)),Fo($e,bo(s)),ao("Synced"),Or("Scene sync succeeded."),Br(`Total word count sync: ${Math.round(ac()-n)}ms`)}catch(e){ao("Sync failed"),Vo({lastError:Ko(e)}),Or("Scene sync failed.")}finally{Te&&(Te.textContent="Sync Current Scene"),Rc()}},Mc=(e=4e3)=>{eo(),Cn&&Sn&&!zn&&!ir&&(cr=window.setTimeout(()=>{cr=null,Uc({source:"automatic"})},e))},Oc=()=>{ur&&(window.clearTimeout(ur),ur=null)},Bc=()=>{mr=null,gr="",yr=[],wr=null,fr="",Oc()},Hc=()=>{br=null,Ir="",Cr=[],Sr=null,kr=""},Gc=()=>{vr=null,xr="",Pr=[],Dr=null,Er=""},Fc=async(e=!1)=>{const t=ea(),n=Ca();if(!t||!n)return yr=[],[];if(!e&&mr===t.projectId&&gr===n&&yr.length>0)return yr;const r=await fc(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return mr=t.projectId,gr=n,yr=Array.isArray(r?.characters)?r.characters:[],Or("Character alias cache refreshed."),yr},Vc=async(e=!1)=>{const t=ea(),n=Ca();if(!t||!n)return Cr=[],[];if(!e&&br===t.projectId&&Ir===n&&Cr.length>0)return Cr;const r=await fc(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return br=t.projectId,Ir=n,Cr=Array.isArray(r?.assets)?r.assets:[],Or(`Asset cache loaded: ${Cr.length} aliases.`),Cr},Kc=async(e=!1)=>{const t=ea(),n=Ca();if(!t||!n)return Pr=[],[];if(!e&&vr===t.projectId&&xr===n&&Pr.length>0)return Pr;const r=await fc(`/api/word-companion/runtime/locations?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return vr=t.projectId,xr=n,Pr=Array.isArray(r?.locations)?r.locations:[],Or(`Location cache loaded: ${Pr.length} aliases.`),Pr},Yc=(e,t)=>{const n=String(t||"").trim();if(!n)return!1;const r=(o=n,String(o||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).replace(/\s+/g,"\\s+");var o;return new RegExp(`(^|[^\\p{L}\\p{N}_])${r}(?=$|[^\\p{L}\\p{N}_])`,"iu").test(e)},Jc=e=>{if(e?.excludeFromCompanionDetection)return!1;const t=Number.parseInt(e?.detectionPriority||"0",10);return n=e?.matchText,String(n||"").trim().split(/\s+/).filter(Boolean).length>=2||Number.isInteger(t)&&t>=75;var n},_c=async()=>{if(ur=null,!Cn||zn||!Ca())return;if(pr)return hr=!0,void Or("Character suggestion detection deferred; detection already running.");pr=!0,hr=!1;const e=ac();try{const t=await sc();if(!cc(t))return void Or("Runtime suggestions skipped (stale snapshot).");const[n,r,o]=await Promise.all([Fc(),Vc(),Kc()]);if(!cc(t))return void Or("Runtime suggestions skipped after cache load (stale snapshot).");const a=t.sceneText||"",c=ac(),i=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.characterId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||Yc(e,r.matchText)&&n.set(t,r.name||r.matchText||"Character")}return[...n.entries()].map(([e,t])=>({characterId:e,name:t}))})(a,n);Br(`Character detection: ${Math.round(ac()-c)}ms`);const s=i.map(e=>e.characterId),d=s.slice().sort((e,t)=>e-t).join(","),l=ac(),u=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.assetId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||Yc(e,r.matchText)&&n.set(t,r.name||r.matchText||"Asset")}return[...n.entries()].map(([e,t])=>({assetId:e,name:t}))})(a,r);Br(`Asset detection: ${Math.round(ac()-l)}ms`);const p=u.map(e=>e.assetId),h=p.slice().sort((e,t)=>e-t).join(","),m=ac(),g=((e,t)=>{if(!e||!Array.isArray(t)||0===t.length)return[];const n=new Map;for(const r of t){const t=Number.parseInt(r.locationId||"",10);!Number.isInteger(t)||t<=0||n.has(t)||!Jc(r)||Yc(e,r.matchText)&&n.set(t,r.name||r.matchText||"Location")}return[...n.entries()].map(([e,t])=>({locationId:e,name:t}))})(a,o);Br(`Location detection: ${Math.round(ac()-m)}ms`);const y=g.map(e=>e.locationId),w=y.slice().sort((e,t)=>e-t).join(",");if(!d||wr===Cn&&fr===d)Or("Character suggestions skipped.");else{if(!cc(t))return void Or("Character suggestions skipped before submit (stale snapshot).");const e=ac(),n=await bc("/api/word-companion/runtime/character-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,characterIds:s});if(Br(`Character suggestion API: ${Math.round(ac()-e)}ms`),!cc(t))return void Or("Character suggestion result ignored (stale snapshot).");if(wr=t.sceneId,fr=d,(n?.createdCount||0)>0){const e=i.slice(0,3).map(e=>e.name).join(", "),t=i.length>3?" +"+(i.length-3):"";_r(e?`Characters detected: ${e}${t}`:n.message)}Or(n?.message||"Character suggestions submitted.")}if(!h||Sr===Cn&&kr===h)Or("Asset suggestions skipped.");else{if(!cc(t))return void Or("Asset suggestions skipped before submit (stale snapshot).");Or(`Asset matches found: ${u.map(e=>e.name).join(", ")}`);const e=ac(),n=await bc("/api/word-companion/runtime/asset-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,assetIds:p});if(Br(`Asset suggestion API: ${Math.round(ac()-e)}ms`),!cc(t))return void Or("Asset suggestion result ignored (stale snapshot).");if(Sr=t.sceneId,kr=h,(n?.createdCount||0)>0){const e=u.slice(0,3).map(e=>e.name).join(", "),t=u.length>3?" +"+(u.length-3):"";_r(e?`Assets detected: ${e}${t}`:n.message)}Or(n?.message||"Asset suggestions submitted.")}if(!w||Dr===Cn&&Er===w)Or("Location suggestions skipped.");else{if(!cc(t))return void Or("Location suggestions skipped before submit (stale snapshot).");Or(`Location matches found: ${g.map(e=>e.name).join(", ")}`);const e=ac(),n=await bc("/api/word-companion/runtime/location-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,locationIds:y});if(Br(`Location suggestion API: ${Math.round(ac()-e)}ms`),!cc(t))return void Or("Location suggestion result ignored (stale snapshot).");if(Dr=t.sceneId,Er=w,(n?.createdCount||0)>0){const e=g.slice(0,3).map(e=>e.name).join(", "),t=g.length>3?" +"+(g.length-3):"";_r(e?`Locations detected: ${e}${t}`:n.message)}Or(n?.message||"Location suggestions submitted.")}Br(`Total suggestion pass: ${Math.round(ac()-e)}ms`)}catch(e){console.error("Unable to detect runtime suggestions.",e),Vo({lastError:Ko(e)})}finally{pr=!1,hr&&(hr=!1,zc(1500))}},zc=(e=2500)=>{Oc(),!Cn||zn||pr?pr&&(hr=!0):ur=window.setTimeout(()=>{_c()},e)},Qc=async()=>{const e=ea(),t=ta(),n=Ro(gn,"chapter");if(Uo({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Xo(t):void 0,detectedChapter:gn,detectedScene:yn,requestChapter:n,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!t)return Ao("Not detected"),_r("Select a PlotDirector book first."),!1;if(!gn)return Ao("Not detected"),_r("No chapter detected in Word. Use Heading 1 for chapters."),!1;Ao("Not detected");try{const e=await Oo(t.bookId),r=bn?e.find(e=>e.chapterId===bn):null,o=n.toLocaleLowerCase(),a=o?e.find(e=>Ro(e.title,"chapter").toLocaleLowerCase()===o):null,c=r||a;return c?(Eo(),yo(null,c.chapterId,r?"Chapter anchor":"Chapter title"),vn=r?"ChapterID Anchor":"Title Match",zr("Chapter linked to PlotDirector"),_r("No scene detected in Word. Use Heading 2 for scenes."),Uo({result:"Chapter matched",chapterId:c.chapterId,sceneId:null}),!0):(yo(null),zr("Chapter not found in PlotDirector."),_r("Chapter not found in PlotDirector."),Uo({result:"Chapter not matched",chapterId:null,sceneId:null}),No("Chapter not found in PlotDirector."),!1)}catch(e){return Ao("Not found in PlotDirector"),Vo({lastError:Ko(e)}),_r("Unable to load PlotDirector chapter data."),!1}},Xc=async()=>{const e=ea(),t=ta(),n=Ro(gn,"chapter"),r=Ro(yn,"scene");if(Uo({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Xo(t):void 0,detectedChapter:gn,detectedScene:yn,requestChapter:n,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),Qr({anchorType:In?"SceneID Anchor":bn?"ChapterID Anchor":"Title Match",storedSceneId:In,storedChapterId:bn,resolutionMethod:"-"}),!t)return Ao("Not detected"),_r("Select a PlotDirector book first."),Uo({result:"Error"}),!1;if(!gn||!yn)return Ao("Not detected"),_r("No scene detected in Word. Use Heading 2 for scenes."),Uo({result:"Error"}),!1;de&&(de.disabled=!0,de.textContent="Refreshing...");const o=()=>{de&&(de.disabled=!1,de.textContent="Refresh PlotDirector Scene")};Ao("Not detected"),_r("Resolving PlotDirector scene...");try{if(In){const e=await(async(e,t)=>{const n=await fc(`/api/word-companion/books/${e}/structure`),r=Array.isArray(n?.chapters)?n.chapters:[];for(const e of r){const n=Array.isArray(e.scenes)?e.scenes:[];for(const r of n)if(t(e,r))return{chapter:e,scene:r}}return null})(t.bookId,(e,t)=>t.sceneId===In);if(e)return Uo({result:"Matched",chapterId:e.chapter.chapterId,sceneId:e.scene.sceneId}),await Go(t.bookId,e.scene.sceneId,e.chapter.chapterId,"Anchor","SceneID Anchor"),!0;xn=!0,vn="SceneID Anchor",zr("Not found in PlotDirector"),_r("Stored PlotDirector ID is invalid."),Uo({result:"Error",chapterId:bn,sceneId:In}),Qr({anchorType:"SceneID Anchor",storedSceneId:In,storedChapterId:bn,resolutionMethod:"Anchor"})}if(bn){const e=(await Mo(t.bookId)).find(e=>e.chapterId===bn),n=e?(Array.isArray(e.scenes)?e.scenes:[]).find(e=>Ro(e.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(n)return Uo({result:"Matched",chapterId:e.chapterId,sceneId:n.sceneId}),await Go(t.bookId,n.sceneId,e.chapterId,"Anchor","ChapterID Anchor"),!0;e&&!In?(vn="ChapterID Anchor",yo(null,bn,"Chapter anchor"),Uo({result:"Chapter matched",chapterId:bn,sceneId:null})):In||(vn="ChapterID Anchor",Uo({result:"Chapter anchor not found",chapterId:bn,sceneId:null}))}const e=await bc(`/api/word-companion/books/${t.bookId}/resolve-scene`,{chapterTitle:n,sceneTitle:r});if(!e?.matched||!e.sceneId){const t=xn,n=Number.parseInt(e?.chapterId||"",10),r=Number.isInteger(Sn)&&Sn>0?Sn:null,a=Number.isInteger(n)&&n>0?n:r,c=!!e?.chapterMatched||!!a;return Ao("Not found in PlotDirector"),xn=t,c&&(yo(null,a,a===r?"Chapter anchor":"Chapter title"),zr("Scene not found in PlotDirector.")),_r(t?"Stored PlotDirector ID is invalid.":c?"Scene not found in PlotDirector.":"This chapter does not exist in PlotDirector. Create or link the chapter first."),Uo({result:"Not matched",chapterId:c?a:e?.chapterId,sceneId:e?.sceneId}),t||(c?(Eo(),qo("Scene not found in PlotDirector.")):(Lo(),No("Chapter not found in PlotDirector."))),o(),!1}const a=xn;return Uo({result:a?"Matched by title fallback":"Matched",chapterId:e.chapterId,sceneId:e.sceneId}),await Go(t.bookId,e.sceneId,e.chapterId,a?"Title fallback":"Title","Title Match"),a&&(xn=!0,_r("Stored PlotDirector ID is invalid."),Xr()),!0}catch(e){const t=xn;return Vo({lastError:Ko(e)}),Ao("Not found in PlotDirector"),xn=t,_r(t?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),Uo({result:"Error"}),!1}finally{o()}},Zc=async()=>{if(Qn=null,ar)return er=!0,void Or("Runtime update deferred; update already running.");if(!an||!ta())return Xn=!1,void Or("Runtime update skipped.");if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return Xn=!1,mo("Manual"),void _r("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");if(!Wn)return Xn=!1,mo("Manual"),void _r("Document structure is not cached yet. Use Refresh Current Scene.");const e=Date.now()-Zn;if(Xn&&e{Qn&&window.clearTimeout(Qn),Qn=window.setTimeout(Zc,Math.max(0,e)),mo("Waiting for typing to pause"),Or("Runtime update scheduled.")},ti=()=>{Qn&&(window.clearTimeout(Qn),Qn=null),Xn=!1,er=!1},ni=()=>{((e="selection",t=1200)=>{if(Xn=!0,Zn=Date.now(),tr+=1,nr=null,eo(),Oc(),ir&&(sr=!0),pr&&(hr=!0),Or(`${e} changed.`),ar)return er=!0,void mo("Waiting for typing to pause");ei(t)})("Selection")},ri=()=>{if(or&&window.Office?.context?.document&&"function"==typeof window.Office.context.document.removeHandlerAsync&&window.Office?.EventType?.DocumentSelectionChanged)try{window.Office.context.document.removeHandlerAsync(window.Office.EventType.DocumentSelectionChanged,{handler:ni}),or=!1}catch(e){console.warn("Unable to remove Word selection tracking handler.",e)}},oi=async(e,n)=>{if(Wn=null,So(),!e)return ln=[],zo(K,"Select a project first"),zo(m,"Select a project first"),Jr(""),_o(t,null),Sa(),Ao("Not detected"),void io();zo(K,"Loading books..."),Jr(""),Ao("Not detected"),io("Select a book to analyse manuscript structure.");try{const r=await fc(`/api/word-companion/projects/${e}/books`);if(ln=Array.isArray(r.books)?r.books:[],0===ln.length)return zo(K,"No books available."),zo(m,"No books available."),Jr("No books available."),_o(t,null),Sa(),void ma("No books available.");Qo(K,"Choose a book",ln.map(e=>({...e,displayTitle:Xo(e)})),"bookId","displayTitle");const o=ln.find(e=>e.bookId===n);o&&K?(K.value=String(o.bookId),_o(t,o.bookId)):_o(t,null),((e=null)=>{if(!m)return;if(0===ln.length)return void zo(m,"No books available.");Qo(m,"Choose a book",ln.map(e=>({...e,displayTitle:Xo(e)})),"bookId","displayTitle");const t=e||Number.parseInt(K?.value||"",10),n=ln.find(e=>e.bookId===t);n&&(m.value=String(n.bookId)),ua()})(o?.bookId||n),Sa(),Ao((ta(),"Not detected")),io(ta()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),ma(ra()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{ln=[],zo(K,"Unable to load books."),zo(m,"Unable to load books."),Jr("Unable to load books."),_o(t,null),Sa(),Ao("Not detected"),io("Unable to load books."),ma("Unable to load books.")}};for(const e of i)e.addEventListener("click",()=>Fr(e.dataset.tabButton));Vr(),V?.addEventListener("change",async()=>{const n=Number.parseInt(V.value||"",10);Co(),h&&Number.isInteger(n)&&n>0&&(h.value=String(n)),_o(e,Number.isInteger(n)&&n>0?n:null),_o(t,null),Ao("Not detected"),io(),ma("Select a Book to begin."),await oi(n,null),sa()}),K?.addEventListener("change",()=>{const e=Number.parseInt(K.value||"",10);Co(),_o(t,Number.isInteger(e)&&e>0?e:null),m&&Number.isInteger(e)&&e>0&&(m.value=String(e)),Sa(),Ao("Not detected"),io(ta()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),ma(ra()?"Ready to scan manuscript structure.":"Select a Book to begin."),sa()}),h?.addEventListener("change",async()=>{const n=Number.parseInt(h.value||"",10);Co(),V&&Number.isInteger(n)&&n>0&&(V.value=String(n)),_o(e,Number.isInteger(n)&&n>0?n:null),_o(t,null),ma("Select a Book to begin."),await oi(n,null),sa()}),m?.addEventListener("change",()=>{const e=Number.parseInt(m.value||"",10);Co(),K&&Number.isInteger(e)&&e>0&&(K.value=String(e)),_o(t,Number.isInteger(e)&&e>0?e:null),Sa(),ma(ra()?"Ready to scan manuscript structure.":"Select a Book to begin."),sa()}),g?.addEventListener("input",ua),y?.addEventListener("click",async()=>{const e=na(),t=String(g?.value||"").trim();if(e&&t){y.disabled=!0,la("Creating Book...");try{const n=await bc(`/api/word-companion/projects/${e.projectId}/books`,{title:t});g&&(g.value=""),V&&(V.value=String(e.projectId)),await oi(e.projectId,n.bookId),m&&(m.value=String(n.bookId)),la("Ready to scan manuscript structure.")}catch(e){console.error("Unable to create Book from Word Companion.",e),la(`Unable to create Book: ${Ko(e)}`)}finally{ua()}}else ua()}),w?.addEventListener("click",async()=>{const e=na(),t=ra();if(e&&t)if(un&&pn&&window.Word&&"function"==typeof window.Word.run){w&&(w.disabled=!0,w.textContent="Scanning..."),la("Scanning manuscript structure...");try{const n=await window.Word.run(async e=>{const n=e.document.body.paragraphs;return n.load("text,styleBuiltIn,style"),await e.sync(),((e,t)=>{const n=[];let r=null,o=null,a=0;const c=[],i=new Set(["***","###"]),s=()=>{if(!r)return null;const e={title:`Scene ${r.scenes.length+1}`,sortOrder:10*(r.scenes.length+1),wordCount:0};return r.scenes.push(e),e};return e.forEach(e=>{const d=String(e.text||"").trim();if(!d)return;if(c.push(d),xa(e,1))return r={title:d,sortOrder:10*(n.length+1),wordCount:0,scenes:[]},n.push(r),o=s(),void(a+=Pa(d));if(!r||!o)return;if(t&&i.has(d))return void(o=s());const l=Pa(d);r.wordCount+=l,o.wordCount+=l,a+=l}),{chapters:n,chapterCount:n.length,sceneCount:n.reduce((e,t)=>e+t.scenes.length,0),wordCount:a,documentText:c.join("\n")}})(n.items,!!t.usesExplicitScenes)});Mn=n,Hn=!1;const r=await bc("/api/word-companion/manuscript/analyse",{projectId:e.projectId,bookId:t.bookId,documentGuid:Ia(),chapterCount:n.chapterCount,sceneCount:n.sceneCount,wordCount:n.wordCount});Un=r,(e=>{if(!I)return;I.innerHTML="";const t=document.createElement("strong");t.textContent="Manuscript Analysis",I.append(t);const n=document.createElement("dl"),r=[["Project",e.projectTitle],["Book",Xo({title:e.bookTitle,subtitle:e.bookSubtitle})],["Chapters",Number(e.chapterCount||0).toLocaleString()],["Scenes",Number(e.sceneCount||0).toLocaleString()],["Words",Number(e.wordCount||0).toLocaleString()]];for(const[e,t]of r){const r=document.createElement("dt");r.textContent=e;const o=document.createElement("dd");o.textContent=t||"-",n.append(r,o)}I.append(n),to(I,!1),to(E,!1),la(e.message||"Preview generated."),ua()})(r);try{const t=await bc("/api/word-companion/manuscript/discover-characters",{projectId:e.projectId,documentText:n.documentText||""});On=Array.isArray(t?.candidates)?t.candidates:[],to(C,!0),to(v,!0)}catch(e){console.error("Unable to discover character candidates.",e),On=[],to(C,!0),to(v,!0)}Vo({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(n.chapterCount),heading2:"-"})}catch(e){console.error("Unable to scan manuscript for first-run import.",e),ma(`Unable to scan manuscript: ${Ko(e)}`),Vo({lastScan:"Failure",lastError:Ko(e)})}finally{w&&(w.textContent="Scan Manuscript"),ua()}}else ma("Word document access is unavailable.");else ma("Select a Project and Book to begin.")}),N?.addEventListener("click",async()=>{const n=na(),o=ra();if(!(n&&o&&Mn&&Un?.canImport))return void ua();let a=!1;if(!Un.requiresReplaceConfirmation||(a=await new Promise(e=>{if(!q||"function"!=typeof q.showModal)return void e(window.confirm("This Book already contains planned chapters and scenes.\n\nImporting this manuscript will replace the planned structure.\n\nContinue?"));const t=t=>{A?.removeEventListener("click",n),$?.removeEventListener("click",r),q?.removeEventListener("cancel",o),q?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),o=e=>{e.preventDefault(),t(!1)};A?.addEventListener("click",n),$?.addEventListener("click",r),q?.addEventListener("cancel",o),q.showModal()}),a)){Vn=!0,ua(),la("Importing manuscript structure...");try{const i=Ia(),s=await bc("/api/word-companion/manuscript/import",{projectId:n.projectId,bookId:o.bookId,documentGuid:i,bindingVersion:1,replacePlanned:a,chapters:Mn.chapters});if(!s.imported)return Un={...Un,canImport:!s.requiresReplaceConfirmation,requiresReplaceConfirmation:!!s.requiresReplaceConfirmation,message:s.message||Un.message},la(s.message||"Import was not completed."),void ua();const d=s.manuscriptDocument;await(c={documentGuid:d?.documentGuid||i,bookId:s.bookId,projectId:s.projectId,bindingVersion:d?.bindingVersion||1},new Promise((e,t)=>{const n=window.Office?.context?.document?.settings;n?(n.set(r.documentGuid,c.documentGuid),n.set(r.bookId,String(c.bookId)),n.set(r.projectId,String(c.projectId)),n.set(r.bindingVersion,String(c.bindingVersion||1)),n.saveAsync(n=>{n.status===window.Office.AsyncResultStatus.Succeeded?e():t(n.error||new Error("Unable to save Word document metadata."))})):t(new Error("Word document settings are unavailable."))})),$n={documentGuid:d?.documentGuid||i,bookId:s.bookId,projectId:s.projectId,bindingVersion:d?.bindingVersion||1},_o(e,s.projectId),_o(t,s.bookId),V&&(V.value=String(s.projectId));const l=On;await oi(s.projectId,s.bookId),Kr("Connected"),Hn=!0,Gn=l.length>0,Fn=Gn?Date.now():0,On=l,l.length>0?(pa(!0),ya(l),to(E,!0),to(v,!1),la(s.message||"Manuscript structure imported."),_r(s.message||"Manuscript structure imported."),window.setTimeout(ua,750)):await Ic(s.message||"Manuscript structure imported.")}catch(e){console.error("Unable to import manuscript structure.",e),la(`Unable to import manuscript: ${Ko(e)}`)}finally{Vn=!1,ua()}var c}else la("Import cancelled.")}),x?.addEventListener("click",async()=>{const e=na()||ea(),t=ga();if(!Gn||Date.now()-Fn<750||!e||0===t.length)ua();else{Kn=!0,ua(),Fo(S,"Creating selected characters...");try{const n=await bc("/api/word-companion/manuscript/create-discovered-characters",{projectId:e.projectId,candidateNames:t});_r(n.message||"Characters created."),Fo(S,`${n.createdCount||0} created, ${n.skippedCount||0} already existed.`),await Ic(n.message||"Characters created.")}catch(e){console.error("Unable to create discovered characters.",e),Fo(S,`Unable to create characters: ${Ko(e)}`)}finally{Kn=!1,ua()}}}),P?.addEventListener("click",()=>Ic("Character creation skipped.")),D?.addEventListener("click",()=>Ic()),f?.addEventListener("click",()=>pa(!1)),L?.addEventListener("click",()=>ma("Import cancelled.")),Q?.addEventListener("click",dc),ae?.addEventListener("click",lc),ce?.addEventListener("click",async()=>{const e=ta();if(!e||0===so().length||Yn)return void lo();if(!await pc())return;Yn=!0,uo(),co("Applying structure sync...");const t={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(An?.manualReview)?An.manualReview.length:0,failed:0},n=so().filter(e=>"couldLink"===e.category&&"Chapter"===e.type),r=so().filter(e=>"wouldCreateChapters"===e.category),o=so().filter(e=>"couldLink"===e.category&&"Scene"===e.type),a=so().filter(e=>"wouldCreateScenes"===e.category),c=[];let i="";const s=(e,t)=>{c.push({item:e,counterName:t})},d=async(e,n)=>{try{await(async e=>{if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const n=await rc(t),r="Chapter"===e.type?e.wordChapter:e.wordScene,o=Number.isInteger(r?.paragraphIndex)?n.bodyParagraphs[r.paragraphIndex]:null;if(!o)throw new Error("Unable to locate the Word heading.");if("Chapter"===e.type){const t=e.pdChapter?.chapterId;if(!t)throw new Error("Chapter ID is not available.");Pc(o,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=e.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");Pc(o,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()}),await oo().catch(()=>null)})(e),hc(e,"Success"),t[n]+=1}catch(n){hc(e,"Failed",Ko(n)),t.failed+=1}};try{for(const e of n)s(e,"linkedChapters");for(const n of r)try{await yc(e.bookId,n),s(n,"createdChapters")}catch(e){hc(n,"Failed",Ko(e)),t.failed+=1}for(const e of o)s(e,"linkedScenes");for(const n of a)try{await wc(e.bookId,n),s(n,"createdScenes")}catch(e){hc(n,"Failed",Ko(e)),t.failed+=1}for(const e of c)await d(e.item,e.counterName);for(const e of An.manualReview||[])hc(e,"Skipped");nc(An),i=(e=>`Structure Sync Complete. Created: ${e.createdChapters} Chapters, ${e.createdScenes} Scenes. Linked: ${e.linkedChapters} Chapters, ${e.linkedScenes} Scenes. Skipped: ${e.skipped} Manual Review items. Failed: ${e.failed} Items.`)(t),co(i)}finally{Yn=!1,uo(),i&&(So(),await lc(),co(`${i} Preview refreshed.`))}}),At?.addEventListener("click",()=>uc(!0)),$t?.addEventListener("click",()=>uc(!1)),Lt?.addEventListener("cancel",e=>{e.preventDefault(),uc(!1)}),de?.addEventListener("click",Xc),z?.addEventListener("click",async()=>{if(!ta())return _r("Select a PlotDirector book first."),void Ao("Not detected");ti(),wo(!0),mo("Updating...");try{await Promise.all([Fc(!0),Vc(!0),Kc(!0)]);if(!await dc())return;if(go(!1),!yn)return await Qc(),void mo("Current scene updated");await Xc(),mo("Current scene updated")}finally{wo(!1)}}),Te?.addEventListener("click",()=>Uc({source:"manual"})),Je?.addEventListener("click",async()=>{if(Cn)if(!zn&&await(async()=>{if(!Cn)return!1;if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return go(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1;try{const e=await window.Word.run(async e=>await rc(e)),t=e.currentChapter?.title||"",n=e.currentScene?.title||"",r=e.currentScene?.anchorId||null,o=e.currentChapter?.anchorId||null,a=Number.isInteger(r)&&r===Cn,c=Number.isInteger(o)&&o===Sn,i=Ro(n,"scene").toLocaleLowerCase()===Ro(Lr||yn,"scene").toLocaleLowerCase(),s=Ro(t,"chapter").toLocaleLowerCase()===Ro(qr||gn,"chapter").toLocaleLowerCase();return a||i&&(c||s)?(go(!1),!0):(go(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1)}catch(e){return console.error("Unable to verify current Word scene before saving.",e),Vo({lastError:Ko(e)}),go(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}})()){Je&&(Je.disabled=!0,Je.textContent="Saving...");try{await(e=`/api/word-companion/scenes/${Cn}/links`,t={characterIds:vc(Ve),assetIds:vc(Ke),locationIds:[],primaryLocationId:xc()},fc(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})),(()=>{const e=new Set(vc(Ve)),t=new Set(vc(Ke));Wr={characters:Wr.characters.map(t=>({...t,linked:e.has(Number.parseInt($o(t,"character"),10))})),assets:Wr.assets.map(e=>({...e,linked:t.has(Number.parseInt($o(e,"asset"),10))})),locations:Wr.locations,primaryLocationId:xc()}})(),ko("Scene links saved successfully."),Vo({lastError:"-"})}catch(e){ko("Unable to save scene links."),Vo({lastError:Ko(e)})}finally{Je&&(Je.disabled=!Cn||zn,Je.textContent="Save Scene Links")}var e,t}else ko("The Word cursor is now in a different scene. Refresh Current Scene before saving.");else ko("Link a PlotDirector scene first.")}),ge?.addEventListener("click",async()=>{await Dc()}),ye?.addEventListener("click",async()=>{console.debug("Word Companion unlink clicked"),_r("Preparing to unlink manuscript...");const e=fa();if(!e)return void _r("This Word document is not linked.");if(!e.documentGuid||!Number.isInteger(e.bookId)||e.bookId<=0)return void _r("Unable to unlink: bound document metadata is incomplete.");try{await oo()}catch{_r("Marker counts are unavailable. You can still unlink without removing hidden anchors.")}if(await new Promise(e=>{if(!T||"function"!=typeof T.showModal)return void e(window.confirm(`This will remove PlotDirector binding metadata from this Word document and unlink this Book in PlotDirector.\n\nHidden PlotDirector anchors will be left in place for possible reuse.\n\nCurrent marker count:\n${jr.chapterCount} chapter markers\n${jr.sceneCount} scene markers\n\nYour manuscript text will not be changed.\n\nContinue?`));const t=t=>{W?.removeEventListener("click",n),j?.removeEventListener("click",r),T?.removeEventListener("cancel",o),T?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),o=e=>{e.preventDefault(),t(!1)};W?.addEventListener("click",n),j?.addEventListener("click",r),T?.addEventListener("cancel",o),T.showModal()})){_r("Unlinking manuscript..."),ye&&(ye.disabled=!0,ye.textContent="Unlinking...");try{await bc("/api/word-companion/manuscript/unlink",{documentGuid:e.documentGuid,bookId:e.bookId}),await ba(),await oo().catch(()=>null),await kc("Manuscript unlinked.")}catch(e){console.error("Unable to unlink manuscript binding.",e),_r("Unable to unlink from PlotDirector.");if(window.confirm("PlotDirector could not be updated, but you can still remove the binding from this Word document.\n\nYou may need to unlink the Book manually in PlotDirector later.\n\nRemove binding from this Word document only?"))try{await ba(),await oo().catch(()=>null),await kc("Word metadata removed. Unlink the Book manually in PlotDirector if it still shows as linked.")}catch(e){console.error("Unable to remove Word document metadata.",e),_r(`Unable to remove Word metadata: ${Ko(e)}`)}else _r(`Unable to unlink manuscript: ${Ko(e)}`)}finally{ye&&(ye.disabled=!1,ye.textContent="Unlink from PlotDirector"),no()}}else _r("Unlink cancelled.")}),we?.addEventListener("click",async()=>{console.debug("Word Companion clean and unlink clicked");const e=fa();if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)return void _r("Word document access is unavailable.");_r("Inspecting PlotDirector markers...");try{await oo()}catch(e){return void _r(`Unable to inspect markers: ${Ko(e)}`)}if(await new Promise(e=>{const t=`This will remove PlotDirector hidden anchors from this Word document while preserving manuscript text.\n\nThis will remove:\n${jr.chapterCount} PlotDirector chapter markers\n${jr.sceneCount} PlotDirector scene markers\nthe document's PlotDirector binding\n\nThe document can be linked again later if desired.\n\nContinue?`;if(!R||"function"!=typeof R.showModal)return void e(window.confirm(t));const n=t=>{U?.removeEventListener("click",r),M?.removeEventListener("click",o),R?.removeEventListener("cancel",a),R?.close(),e(t)},r=()=>n(!0),o=()=>n(!1),a=e=>{e.preventDefault(),n(!1)};U?.addEventListener("click",r),M?.addEventListener("click",o),R?.addEventListener("cancel",a),R.showModal()})){we&&(we.disabled=!0,we.textContent="Cleaning..."),ye&&(ye.disabled=!0);try{_r("Removing PlotDirector hidden anchors..."),await(async()=>{if(!un||!pn||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");return await window.Word.run(async e=>{const t=e.document.contentControls;t.load("items/tag,title"),await e.sync();let n=0,r=0;for(const e of t.items||[]){const t=Mr(e);t&&("chapter"===t?n+=1:"scene"===t&&(r+=1),e.delete(!0))}return await e.sync(),{chapterCount:n,sceneCount:r,totalCount:n+r,available:!0,message:"PlotDirector markers removed."}})})(),await new Promise(e=>{const t=window.Office?.context?.document;t&&"function"==typeof t.saveAsync?t.saveAsync(t=>{e(t.status===window.Office.AsyncResultStatus.Succeeded)}):e(!1)});try{await oo()}catch(e){return console.error("Unable to verify PlotDirector marker cleanup.",e),void _r(`PlotDirector markers were removed, but cleanup verification failed: ${Ko(e)}`)}if(jr.available&&jr.totalCount>0)return void _r(`Cleanup stopped: ${jr.totalCount} PlotDirector marker${1===jr.totalCount?"":"s"} remain.`);_r("Removing PlotDirector binding metadata...");try{await ba()}catch(e){return console.error("Unable to remove Word document metadata after marker cleanup.",e),void _r(`PlotDirector markers were removed, but Word binding metadata remains: ${Ko(e)}`)}let t="";if(e?.documentGuid&&Number.isInteger(e.bookId)&&e.bookId>0)try{await bc("/api/word-companion/manuscript/unlink",{documentGuid:e.documentGuid,bookId:e.bookId})}catch(e){console.error("Word document cleaned, but PlotDirector server unlink failed.",e),t=" Word document is clean, but unlink the Book manually in PlotDirector if it still shows as linked."}await oo().catch(()=>null),await kc(`Word document cleaned and unlinked.${t}`)}catch(e){console.error("Unable to clean PlotDirector markers.",e),_r(`Cleanup failed before unlinking: ${Ko(e)}`)}finally{we&&(we.disabled=!1,we.textContent="Clean and unlink"),ye&&(ye.disabled=!1),no(),ro()}}else _r("Clean and unlink cancelled.")}),Ze?.addEventListener("click",async()=>{const e=ta();if(!e||!gn||Sn)return void No("Chapter not found in PlotDirector.");const t=jo(gn),n=await((e,t)=>(Fo(Pt,`"${e}"`),Fo(Dt,`"${t}"`),xt?new Promise(e=>{qn=e,xt.showModal?xt.showModal():xt.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector chapter:\n\n"${e}"\n\nin book:\n\n"${t}"\n\n?`))))(t,Xo(e)||"selected book");if(n){Ze&&(Ze.disabled=!0,Ze.textContent="Creating...");try{const n=Number.isInteger(fn)&&fn>0?10*fn:null,r=await bc(`/api/word-companion/books/${e.bookId}/chapters`,{title:t,sortOrder:n});if(!r?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");So(),yo(null,r.chapterId,"Manual chapter link");if(!await Ec("Chapter created and linked successfully."))return;await Nc("Chapter created and linked successfully.")}catch(e){xo("Unable to create chapter."),Vo({lastError:Ko(e)})}finally{Ze&&(Ze.disabled=!Po(),Ze.textContent="Create Chapter in PlotDirector")}}}),et?.addEventListener("click",async()=>{const e=ta();if(e&&gn&&!Sn){et&&(et.disabled=!0,et.textContent="Loading...");try{Nn=await Oo(e.bookId),Ln=null,It&&(It.value=""),Fo(vt,""),qc(),bt?.showModal?bt.showModal():bt&&(bt.hidden=!1)}catch(e){xo("Unable to load chapters."),Vo({lastError:Ko(e)})}finally{et&&(et.disabled=!Po(),et.textContent="Link to Existing Chapter")}}else No("Chapter not found in PlotDirector.")}),It?.addEventListener("input",qc),St?.addEventListener("click",async()=>{const e=Nn.find(e=>e.chapterId===Ln);if(e){St&&(St.disabled=!0,St.textContent="Linking...");try{yo(null,e.chapterId,"Manual chapter link");if(!await Ec("Chapter linked successfully."))return;Ac(),await Nc("Chapter linked successfully.")}catch(e){Fo(vt,"Unable to link chapter."),xo("Unable to link chapter."),Vo({lastError:Ko(e)})}finally{St&&(St.disabled=!Ln,St.textContent="Link Chapter")}}else Fo(vt,"Select a chapter.")}),kt?.addEventListener("click",Ac),Et?.addEventListener("click",()=>Lc(!0)),Nt?.addEventListener("click",()=>Lc(!1)),xt?.addEventListener("cancel",e=>{e.preventDefault(),Lc(!1)}),at?.addEventListener("click",async()=>{const e=ta();if(!e||!yn)return void qo("Scene not found in PlotDirector.");const t=Ro(yn,"scene"),n=Ro(gn,"chapter"),r=await((e,t)=>(Fo(gt,`"${e}"`),Fo(yt,`"${t}"`),mt?new Promise(e=>{En=e,mt.showModal?mt.showModal():mt.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector scene:\n\n"${e}"\n\nwithin chapter:\n\n"${t}"\n\n?`))))(t,n);if(r){at&&(at.disabled=!0,at.textContent="Creating...");try{const n=await Ho();if(!n)return void qo("This chapter does not exist in PlotDirector. Create or link the chapter first.");const r=await bc(`/api/word-companion/books/${e.bookId}/chapters/${n.chapterId}/scenes`,{sceneTitle:t});if(!r?.sceneId||!r?.chapterId)throw new Error("Scene creation did not return a scene ID.");So(),await $c(r.sceneId,r.chapterId,"Scene created and linked successfully.")}catch(e){vo("Unable to create scene."),Vo({lastError:Ko(e)})}finally{at&&(at.disabled=!Do(),at.textContent="Create Scene in PlotDirector")}}}),ct?.addEventListener("click",async()=>{const e=ta();if(e&&yn){ct&&(ct.disabled=!0,ct.textContent="Loading...");try{const t=await Mo(e.bookId),n=Bo(t);if(!n)return void qo("This chapter does not exist in PlotDirector. Create or link the chapter first.");Pn=Array.isArray(n.scenes)?n.scenes:[],Dn=null,dt&&(dt.value=""),Fo(ht,""),Wc(),st?.showModal?st.showModal():st&&(st.hidden=!1)}catch(e){vo("Unable to load scenes."),Vo({lastError:Ko(e)})}finally{ct&&(ct.disabled=!Do(),ct.textContent="Link to Existing Scene")}}else qo("Scene not found in PlotDirector.")}),dt?.addEventListener("input",Wc),ut?.addEventListener("click",async()=>{const e=ta(),t=Pn.find(e=>e.sceneId===Dn);if(e&&t){ut&&(ut.disabled=!0,ut.textContent="Linking...");try{const e=await Ho();if(!e)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");jc(),await $c(t.sceneId,e.chapterId,"Scene linked successfully.")}catch(e){Fo(ht,"Unable to link scene."),vo("Unable to link scene."),Vo({lastError:Ko(e)})}finally{ut&&(ut.disabled=!Dn,ut.textContent="Link Scene")}}else Fo(ht,"Select a scene.")}),pt?.addEventListener("click",jc),wt?.addEventListener("click",()=>Tc(!0)),ft?.addEventListener("click",()=>Tc(!1)),mt?.addEventListener("cancel",e=>{e.preventDefault(),Tc(!1)}),Vt?.addEventListener("click",async()=>{Vt&&(Vt.disabled=!0,Vt.textContent="Running...");try{if(await Yo(),!un||!pn||!window.Word||"function"!=typeof window.Word.run)return void Vo({lastScan:"Failure",lastError:"Word document access is unavailable.",paragraphs:"-",heading1:"-",heading2:"-"});const e=await window.Word.run(async e=>{const t=e.document.body.paragraphs;return t.load("items"),await e.sync(),t.items.length});Vo({lastScan:"Success",lastError:"-",paragraphs:String(e)})}catch(e){console.error("Word Companion diagnostics failed.",e);const t=Ko(e);Vo({lastScan:"Failure",lastError:t}),_r(`Unable to scan the Word document: ${t}`)}finally{Vt&&(Vt.disabled=!1,Vt.textContent="Run Diagnostics")}});const ai=an?(async()=>{zo(V,"Loading projects..."),zo(K,"Select a project first"),zo(h,"Loading projects..."),zo(m,"Select a project first"),Yr(""),Jr("");try{const n=await fc("/api/word-companion/projects");if(dn=Array.isArray(n.projects)?n.projects:[],0===dn.length)return zo(V,"No projects available."),zo(h,"No projects available."),Yr("No projects available."),_o(e,null),_o(t,null),Sa(),void ma("No projects available.");Qo(V,"Choose a project",dn,"projectId","title"),ha();const r=Jo(e),o=dn.find(e=>e.projectId===r);o&&V?(V.value=String(o.projectId),h&&(h.value=String(o.projectId)),_o(e,o.projectId),await oi(o.projectId,Jo(t))):(_o(e,null),_o(t,null),Sa(),ma("Select a Project and Book to begin."))}catch{dn=[],ln=[],zo(V,"Unable to connect to PlotDirector."),zo(K,"Select a project first"),zo(h,"Unable to connect to PlotDirector."),zo(m,"Select a project first"),Kr("Unable to connect to PlotDirector."),Yr("Unable to connect to PlotDirector."),_o(e,null),_o(t,null),Sa(),ma("Unable to connect to PlotDirector.")}})():Promise.resolve();if(an||(zo(V,"Please sign in to PlotDirector."),zo(K,"Please sign in to PlotDirector."),zo(h,"Please sign in to PlotDirector."),zo(m,"Please sign in to PlotDirector."),Sa()),!window.Office||"function"!=typeof window.Office.onReady)return Hr("Word Companion ready"),_r("Word document access is unavailable."),mo("Manual"),Vo({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"}),void da().catch(e=>{console.debug("Word Companion presence unavailable.",e)});Yo().then(async()=>{Hr("Word Companion ready"),await ai,await(async()=>{if(!an||!pn)return void pa(!1);const n=wa();if(n)try{const r=await fc(`/api/word-companion/runtime/book/${n.bookId}?documentGuid=${encodeURIComponent(n.documentGuid)}`),o=r?.manuscriptDocument;if(r?.bookId===n.bookId&&r?.projectId===n.projectId&&o&&String(o.documentGuid).toLowerCase()===n.documentGuid.toLowerCase())return $n=n,Io(r),_o(e,r.projectId),_o(t,r.bookId),V&&(V.value=String(r.projectId)),await oi(r.projectId,r.bookId),pa(!1),Kr("Connected"),Jr("Bound manuscript detected."),void await Sc()}catch{}$n=null,Co(),ha(),na()?await oi(na().projectId,null):zo(m,"Select a project first"),ma("Select a Project and Book to begin."),pa(!0)})(),await da(),pn?(await oo().catch(()=>null),(()=>{if(an){if(!window.Office?.context?.document||"function"!=typeof window.Office.context.document.addHandlerAsync||!window.Office?.EventType?.DocumentSelectionChanged)return mo("Manual"),void _r("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,ni,e=>{e?.status===window.Office.AsyncResultStatus.Succeeded?(or=!0,mo("Live")):(mo("Manual"),_r("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))}),window.addEventListener("beforeunload",ri)}catch(e){console.warn("Unable to register Word selection tracking handler.",e),mo("Manual"),_r("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}})()):(_r("Word document access is unavailable."),mo("Manual"))}).catch(e=>{console.error("Office readiness check failed.",e),Kr("Unable to connect to PlotDirector."),Hr("Word Companion unavailable"),_r("Word document access is unavailable."),Vo({ready:"No",wordApi:"No",lastScan:"Failure"})})})();
\ No newline at end of file