diff --git a/PlotLine/Controllers/BooksController.cs b/PlotLine/Controllers/BooksController.cs index eda932a..5a6d3c8 100644 --- a/PlotLine/Controllers/BooksController.cs +++ b/PlotLine/Controllers/BooksController.cs @@ -91,4 +91,15 @@ public sealed class BooksController(IBookService books) : Controller TempData["ArchiveMessage"] = "Book archived. You can restore it from Archived Items."; return RedirectToAction("Details", "Projects", new { id = projectId }); } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UnlinkManuscript(int id) + { + var result = await books.UnlinkManuscriptAsync(id); + TempData["ManuscriptMessage"] = result is null + ? "Unable to unlink manuscript. It may already be unlinked, or you may not have access." + : result.Message; + return RedirectToAction(nameof(Details), new { id }); + } } diff --git a/PlotLine/Controllers/WordCompanionController.cs b/PlotLine/Controllers/WordCompanionController.cs index 15f911f..1c159dc 100644 --- a/PlotLine/Controllers/WordCompanionController.cs +++ b/PlotLine/Controllers/WordCompanionController.cs @@ -198,6 +198,13 @@ public sealed class WordCompanionController( return response is null ? BadRequest() : Ok(response); } + [HttpPost("manuscript/unlink")] + public async Task UnlinkManuscript(WordCompanionManuscriptUnlinkRequest request) + { + var response = await wordCompanion.UnlinkManuscriptAsync(request); + return response is null ? BadRequest() : Ok(response); + } + [HttpPost("manuscript/analyse")] public async Task AnalyseManuscript(WordCompanionManuscriptAnalyseRequest request) { diff --git a/PlotLine/Data/Repositories.cs b/PlotLine/Data/Repositories.cs index b982d1c..41c939b 100644 --- a/PlotLine/Data/Repositories.cs +++ b/PlotLine/Data/Repositories.cs @@ -65,6 +65,7 @@ public interface IManuscriptDocumentRepository Task GetByBookAsync(int bookId, int userId); Task GetByGuidAsync(Guid documentGuid, int userId); Task SaveAsync(int bookId, Guid documentGuid, int userId); + Task UnlinkBookAsync(int bookId, Guid? documentGuid, int userId); Task UpdateLastSyncAsync(int manuscriptDocumentId, int userId); Task UpdateLastOpenedAsync(int manuscriptDocumentId, int userId); } @@ -2347,6 +2348,15 @@ public sealed class ManuscriptDocumentRepository(ISqlConnectionFactory connectio } } + public async Task UnlinkBookAsync(int bookId, Guid? documentGuid, int userId) + { + using var connection = connectionFactory.CreateConnection(); + return await connection.QuerySingleOrDefaultAsync( + "dbo.ManuscriptDocument_UnlinkBook", + new { BookID = bookId, DocumentGuid = documentGuid, UserID = userId }, + commandType: CommandType.StoredProcedure); + } + public async Task UpdateLastSyncAsync(int manuscriptDocumentId, int userId) { using var connection = connectionFactory.CreateConnection(); diff --git a/PlotLine/Models/CoreModels.cs b/PlotLine/Models/CoreModels.cs index 37be60f..bf22e85 100644 --- a/PlotLine/Models/CoreModels.cs +++ b/PlotLine/Models/CoreModels.cs @@ -269,6 +269,15 @@ public sealed class ManuscriptDocumentModel public int? CreatedByUserID { get; set; } } +public sealed class ManuscriptDocumentUnlinkResult +{ + public int BookID { get; set; } + public int ManuscriptDocumentID { get; set; } + public int ChaptersUnlinked { get; set; } + public int ScenesUnlinked { get; set; } + public string Message { get; set; } = string.Empty; +} + public sealed class CharacterAlias { public int CharacterAliasID { get; set; } diff --git a/PlotLine/Models/WordCompanionApiModels.cs b/PlotLine/Models/WordCompanionApiModels.cs index 895a123..99884c5 100644 --- a/PlotLine/Models/WordCompanionApiModels.cs +++ b/PlotLine/Models/WordCompanionApiModels.cs @@ -381,6 +381,21 @@ public sealed class WordCompanionManuscriptLinkResponse public string Message { get; init; } = "Manuscript linked."; } +public sealed class WordCompanionManuscriptUnlinkRequest +{ + public int BookId { get; set; } + public Guid? DocumentGuid { get; set; } +} + +public sealed class WordCompanionManuscriptUnlinkResponse +{ + public int BookId { get; init; } + public int ManuscriptDocumentId { get; init; } + public int ChaptersUnlinked { get; init; } + public int ScenesUnlinked { get; init; } + public string Message { get; init; } = "Manuscript unlinked."; +} + public sealed class WordCompanionCreateBookRequest { public string? Title { get; set; } diff --git a/PlotLine/Services/CoreServices.cs b/PlotLine/Services/CoreServices.cs index 1b104fe..243116b 100644 --- a/PlotLine/Services/CoreServices.cs +++ b/PlotLine/Services/CoreServices.cs @@ -101,6 +101,7 @@ public interface IBookService Task GetEditAsync(int bookId); Task PopulateEditContextAsync(BookEditViewModel model); Task SaveAsync(BookEditViewModel model); + Task UnlinkManuscriptAsync(int bookId); Task ArchiveAsync(int bookId); } @@ -1272,6 +1273,13 @@ public sealed class BookService( return new(bookId, true); } + public Task UnlinkManuscriptAsync(int bookId) + { + return currentUser.UserId is int userId + ? manuscriptDocuments.UnlinkBookAsync(bookId, null, userId) + : Task.FromResult(null); + } + private static IReadOnlyList BuildStatusOptions(string? selectedStatus) => BookStatuses.All .Select(status => new SelectListItem(status, status, string.Equals(status, selectedStatus, StringComparison.OrdinalIgnoreCase))) diff --git a/PlotLine/Services/WordCompanionService.cs b/PlotLine/Services/WordCompanionService.cs index b315107..a9ec136 100644 --- a/PlotLine/Services/WordCompanionService.cs +++ b/PlotLine/Services/WordCompanionService.cs @@ -30,6 +30,7 @@ public interface IWordCompanionService Task GetRuntimeBookAsync(int bookId, Guid documentGuid); Task GetManuscriptForBookAsync(int bookId); Task LinkManuscriptAsync(WordCompanionManuscriptLinkRequest request); + Task UnlinkManuscriptAsync(WordCompanionManuscriptUnlinkRequest request); Task AnalyseManuscriptAsync(WordCompanionManuscriptAnalyseRequest request); Task ImportManuscriptAsync(WordCompanionManuscriptImportRequest request); Task DiscoverCharacterCandidatesAsync(WordCompanionDiscoverCharactersRequest request); @@ -434,6 +435,26 @@ public sealed class WordCompanionService( }; } + public async Task UnlinkManuscriptAsync(WordCompanionManuscriptUnlinkRequest request) + { + if (request.BookId <= 0) + { + return null; + } + + var result = await manuscriptDocuments.UnlinkBookAsync(request.BookId, request.DocumentGuid, RequireUserId()); + return result is null + ? null + : new WordCompanionManuscriptUnlinkResponse + { + BookId = result.BookID, + ManuscriptDocumentId = result.ManuscriptDocumentID, + ChaptersUnlinked = result.ChaptersUnlinked, + ScenesUnlinked = result.ScenesUnlinked, + Message = result.Message + }; + } + public Task AnalyseManuscriptAsync(WordCompanionManuscriptAnalyseRequest request) { if (request.ProjectId <= 0 diff --git a/PlotLine/Sql/108_Phase16Q_ManuscriptUnlink.sql b/PlotLine/Sql/108_Phase16Q_ManuscriptUnlink.sql new file mode 100644 index 0000000..e1de991 --- /dev/null +++ b/PlotLine/Sql/108_Phase16Q_ManuscriptUnlink.sql @@ -0,0 +1,68 @@ +SET ANSI_NULLS ON; +GO +SET QUOTED_IDENTIFIER ON; +GO + +CREATE OR ALTER PROCEDURE dbo.ManuscriptDocument_UnlinkBook + @BookID int, + @DocumentGuid uniqueidentifier = NULL, + @UserID int +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @ManuscriptDocumentID int; + DECLARE @ChaptersUnlinked int = 0; + DECLARE @ScenesUnlinked int = 0; + + SELECT @ManuscriptDocumentID = md.ManuscriptDocumentID + FROM dbo.ManuscriptDocuments md + INNER JOIN dbo.Books b ON b.BookID = md.BookID + INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID + INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID + WHERE md.BookID = @BookID + AND md.IsActive = 1 + AND b.IsArchived = 0 + AND p.IsArchived = 0 + AND pua.UserID = @UserID + AND pua.IsActive = 1 + AND (@DocumentGuid IS NULL OR @DocumentGuid = '00000000-0000-0000-0000-000000000000' OR md.DocumentGuid = @DocumentGuid); + + IF @ManuscriptDocumentID IS NULL + RETURN; + + UPDATE dbo.Chapters + SET IsLinkedToManuscript = 0, + ManuscriptDocumentID = NULL, + ExternalReference = NULL, + LinkedUtc = NULL, + UpdatedDate = SYSUTCDATETIME() + WHERE BookID = @BookID + AND ManuscriptDocumentID = @ManuscriptDocumentID; + + SET @ChaptersUnlinked = @@ROWCOUNT; + + UPDATE s + SET IsLinkedToManuscript = 0, + ManuscriptDocumentID = NULL, + ExternalReference = NULL, + LinkedUtc = NULL, + UpdatedDate = SYSUTCDATETIME() + FROM dbo.Scenes s + INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID + WHERE c.BookID = @BookID + AND s.ManuscriptDocumentID = @ManuscriptDocumentID; + + SET @ScenesUnlinked = @@ROWCOUNT; + + UPDATE dbo.ManuscriptDocuments + SET IsActive = 0 + WHERE ManuscriptDocumentID = @ManuscriptDocumentID; + + SELECT @BookID AS BookID, + @ManuscriptDocumentID AS ManuscriptDocumentID, + @ChaptersUnlinked AS ChaptersUnlinked, + @ScenesUnlinked AS ScenesUnlinked, + N'Manuscript unlinked. Chapters, scenes, and story data were kept.' AS Message; +END; +GO diff --git a/PlotLine/Views/Books/Details.cshtml b/PlotLine/Views/Books/Details.cshtml index 8777ff2..8799fc8 100644 --- a/PlotLine/Views/Books/Details.cshtml +++ b/PlotLine/Views/Books/Details.cshtml @@ -16,6 +16,10 @@ {
@archiveMessage
} +@if (TempData["ManuscriptMessage"] is string manuscriptMessage) +{ +
@manuscriptMessage
+}
@@ -101,6 +105,10 @@ { Manuscript linked Last synced: @(Model.ManuscriptDocument.LastSyncUtc?.ToString("dd MMM yyyy HH:mm") ?? "Never") +
+ + +
} Manuscript Status
diff --git a/PlotLine/Views/WordCompanionHost/Index.cshtml b/PlotLine/Views/WordCompanionHost/Index.cshtml index 449c3f1..78803f8 100644 --- a/PlotLine/Views/WordCompanionHost/Index.cshtml +++ b/PlotLine/Views/WordCompanionHost/Index.cshtml @@ -170,6 +170,7 @@
+

diff --git a/PlotLine/wwwroot/css/word-companion.css b/PlotLine/wwwroot/css/word-companion.css index 7d4a802..5512e6a 100644 --- a/PlotLine/wwwroot/css/word-companion.css +++ b/PlotLine/wwwroot/css/word-companion.css @@ -558,6 +558,16 @@ body { 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-message:empty { display: none; } diff --git a/PlotLine/wwwroot/css/word-companion.min.css b/PlotLine/wwwroot/css/word-companion.min.css index 66d1831..085aa84 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(4,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-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-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-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:4px}.word-companion-check-item{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:7px;min-height:29px;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-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-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(4,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-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-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-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:4px}.word-companion-check-item{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:7px;min-height:29px;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-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-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 3438418..d0d857d 100644 --- a/PlotLine/wwwroot/js/word-companion-host.js +++ b/PlotLine/wwwroot/js/word-companion-host.js @@ -67,6 +67,7 @@ const anchorChapterId = document.querySelector("[data-anchor-chapter-id]"); 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 plotDirectorSceneDetails = document.querySelector("[data-plotdirector-scene-details]"); const plotDirectorSceneTitle = document.querySelector("[data-plotdirector-scene-title]"); const plotDirectorRevisionStatus = document.querySelector("[data-plotdirector-revision-status]"); @@ -426,6 +427,10 @@ } }; + const updateUnlinkWordDocumentButton = () => { + setHidden(unlinkWordDocumentButton, !firstRunDocumentBinding); + }; + const setSyncStatus = (message) => { setText(syncStatus, message); }; @@ -1152,6 +1157,7 @@ const setFirstRunMode = (visible) => { setHidden(firstRunWizard, !visible); setHidden(tabsNav, visible); + updateUnlinkWordDocumentButton(); for (const panel of tabPanels) { setHidden(panel, visible ? true : panel.dataset.tabPanel !== "scene" && !panel.classList.contains("is-active")); } @@ -1357,6 +1363,30 @@ }); }); + const removeDocumentBinding = () => new Promise((resolve, reject) => { + const settings = window.Office?.context?.document?.settings; + if (!settings) { + reject(new Error("Word document settings are unavailable.")); + return; + } + + for (const key of Object.values(documentMetadataKeys)) { + if (typeof settings.remove === "function") { + settings.remove(key); + } else { + settings.set(key, ""); + } + } + + settings.saveAsync((result) => { + if (result.status === window.Office.AsyncResultStatus.Succeeded) { + resolve(); + } else { + reject(result.error || new Error("Unable to remove Word document metadata.")); + } + }); + }); + const ensureDocumentGuid = () => { if (firstRunDocumentBinding?.documentGuid) { return firstRunDocumentBinding.documentGuid; @@ -3143,6 +3173,70 @@ setFirstRunMode(true); }; + const returnToUnboundOnboarding = async (message) => { + firstRunDocumentBinding = null; + clearRuntimeCaches(); + resetPlotDirectorScene("Not detected"); + setSceneTrackingState("Manual"); + setConnectionStatus("Connected"); + syncFirstRunProjectOptions(); + if (selectedFirstRunProject()) { + await loadBooks(selectedFirstRunProject().projectId, null); + } else { + resetSelect(firstRunBookSelect, "Select a project first"); + } + resetFirstRunPreview(message || "Select a Project and Book to begin."); + setFirstRunMode(true); + updateUnlinkWordDocumentButton(); + }; + + const unlinkThisWordDocument = async () => { + const binding = firstRunDocumentBinding || readDocumentBinding(); + if (!binding) { + setDocumentMessage("This Word document is not linked."); + return; + } + + const confirmed = 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?"); + if (!confirmed) { + return; + } + + if (unlinkWordDocumentButton) { + unlinkWordDocumentButton.disabled = true; + unlinkWordDocumentButton.textContent = "Unlinking..."; + } + + try { + await postJson("/api/word-companion/manuscript/unlink", { + documentGuid: binding.documentGuid, + bookId: binding.bookId + }); + await removeDocumentBinding(); + await returnToUnboundOnboarding("Word document unlinked. Select a Project and Book to begin."); + } catch (error) { + console.error("Unable to unlink manuscript binding.", error); + const removeLocalOnly = 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 Word metadata only?"); + if (removeLocalOnly) { + try { + await removeDocumentBinding(); + 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); + setDocumentMessage(`Unable to remove Word metadata: ${errorText(metadataError)}`); + } + } else { + setDocumentMessage(`Unable to unlink manuscript: ${errorText(error)}`); + } + } finally { + if (unlinkWordDocumentButton) { + unlinkWordDocumentButton.disabled = false; + unlinkWordDocumentButton.textContent = "Unlink this Word document"; + } + updateUnlinkWordDocumentButton(); + } + }; + const patchJson = (url, body) => fetchJson(url, { method: "PATCH", headers: { "Content-Type": "application/json" }, @@ -5056,6 +5150,7 @@ syncSceneProgressButton?.addEventListener("click", () => syncSceneProgress({ source: "manual" })); saveSceneLinksButton?.addEventListener("click", saveSceneLinks); attachPlotDirectorIdsButton?.addEventListener("click", attachPlotDirectorIds); + unlinkWordDocumentButton?.addEventListener("click", unlinkThisWordDocument); createPlotDirectorChapterButton?.addEventListener("click", createPlotDirectorChapter); linkExistingChapterButton?.addEventListener("click", openLinkExistingChapterDialog); linkChapterSearch?.addEventListener("input", renderLinkChapterOptions); diff --git a/PlotLine/wwwroot/js/word-companion-host.min.js b/PlotLine/wwwroot/js/word-companion-host.min.js index 6267666..f9aac88 100644 --- a/PlotLine/wwwroot/js/word-companion-host.min.js +++ b/PlotLine/wwwroot/js/word-companion-host.min.js @@ -1 +1 @@ -(()=>{const e="plotdirector.word.projectId",t="plotdirector.word.bookId",n="plotdirector.word.activeTab",r="plotdirector.word.documentGuid",o="plotdirector.word.boundBookId",a="plotdirector.word.boundProjectId",c="plotdirector.word.bindingVersion",i=new Set(["scene","links","structure","diagnostics"]),s=document.querySelector(".word-companion-shell"),d=document.querySelector(".word-companion-tabs"),l=[...document.querySelectorAll("[data-tab-button]")],u=[...document.querySelectorAll("[data-tab-panel]")],p=document.querySelector("[data-first-run-wizard]"),h=document.querySelector("[data-first-run-project-select]"),m=document.querySelector("[data-first-run-book-select]"),y=document.querySelector("[data-first-run-new-book-title]"),g=document.querySelector("[data-first-run-create-book]"),f=document.querySelector("[data-first-run-scan]"),w=document.querySelector("[data-first-run-cancel]"),S=document.querySelector("[data-first-run-status]"),I=document.querySelector("[data-first-run-summary]"),b=document.querySelector("[data-first-run-character-section]"),C=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]"),N=document.querySelector("[data-first-run-skip-characters]"),E=document.querySelector("[data-first-run-continue]"),L=document.querySelector("[data-first-run-import-actions]"),P=document.querySelector("[data-first-run-import]"),q=document.querySelector("[data-first-run-import-cancel]"),D=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-office-status]"),j=document.querySelector("[data-connection-status]"),R=document.querySelector("[data-summary-connection]"),W=document.querySelector("[data-summary-project]"),U=document.querySelector("[data-summary-book]"),M=document.querySelector("[data-project-select]"),O=document.querySelector("[data-book-select]"),H=document.querySelector("[data-project-message]"),B=document.querySelector("[data-book-message]"),G=document.querySelector("[data-refresh-current-scene]"),F=document.querySelector("[data-refresh-document]"),V=document.querySelector("[data-current-chapter]"),J=document.querySelector("[data-current-scene]"),Y=document.querySelector("[data-current-word-count]"),_=document.querySelector("[data-scene-tracking-status]"),z=document.querySelector("[data-document-message]"),K=document.querySelector("[data-sync-note]"),Q=document.querySelector("[data-document-outline]"),X=document.querySelector("[data-analyse-manuscript-structure]"),Z=document.querySelector("[data-apply-structure-sync]"),ee=document.querySelector("[data-structure-preview-status]"),te=document.querySelector("[data-structure-preview-results]"),ne=document.querySelector("[data-refresh-plotdirector-scene]"),re=document.querySelector("[data-plotdirector-scene-status]"),oe=document.querySelector("[data-anchor-status]"),ae=document.querySelector("[data-anchor-book-id]"),ce=document.querySelector("[data-anchor-chapter-id]"),ie=document.querySelector("[data-anchor-scene-id]"),se=document.querySelector("[data-attach-plotdirector-ids]"),de=document.querySelector("[data-plotdirector-scene-details]"),le=document.querySelector("[data-plotdirector-scene-title]"),ue=document.querySelector("[data-plotdirector-revision-status]"),pe=document.querySelector("[data-plotdirector-estimated-words]"),he=document.querySelector("[data-plotdirector-actual-words]"),me=document.querySelector("[data-plotdirector-blocked-status]"),ye=document.querySelector("[data-plotdirector-blocked-reason-row]"),ge=document.querySelector("[data-plotdirector-blocked-reason]"),fe=document.querySelector("[data-runtime-last-sync]"),we=document.querySelector("[data-sync-scene-progress]"),Se=document.querySelector("[data-sync-word-count]"),Ie=document.querySelector("[data-sync-plotdirector-count]"),be=document.querySelector("[data-sync-last-synced]"),Ce=document.querySelector("[data-sync-status]"),ke=document.querySelector("[data-writing-brief-block]"),ve=document.querySelector("[data-writing-brief]"),xe=document.querySelector("[data-plotdirector-link-groups]"),Ne=document.querySelector("[data-character-chips]"),Ee=document.querySelector("[data-asset-chips]"),Le=(document.querySelector("[data-location-chips]"),document.querySelector("[data-primary-location-select]")),Pe=document.querySelector("[data-save-scene-links]"),qe=document.querySelector("[data-scene-links-status]"),De=document.querySelector("[data-links-editing-scene]"),Ae=document.querySelector("[data-chapter-create-link]"),$e=document.querySelector("[data-chapter-create-link-chapter]"),Te=document.querySelector("[data-create-plotdirector-chapter]"),je=document.querySelector("[data-link-existing-chapter]"),Re=document.querySelector("[data-chapter-create-link-status]"),We=document.querySelector("[data-scene-create-link]"),Ue=document.querySelector("[data-create-link-chapter]"),Me=document.querySelector("[data-create-link-scene]"),Oe=document.querySelector("[data-create-plotdirector-scene]"),He=document.querySelector("[data-link-existing-scene]"),Be=document.querySelector("[data-create-link-status]"),Ge=document.querySelector("[data-link-existing-dialog]"),Fe=document.querySelector("[data-link-scene-search]"),Ve=document.querySelector("[data-link-scene-options]"),Je=document.querySelector("[data-link-selected-scene]"),Ye=document.querySelector("[data-link-dialog-cancel]"),_e=document.querySelector("[data-link-dialog-status]"),ze=document.querySelector("[data-create-scene-dialog]"),Ke=document.querySelector("[data-create-dialog-scene]"),Qe=document.querySelector("[data-create-dialog-chapter]"),Xe=document.querySelector("[data-create-dialog-confirm]"),Ze=document.querySelector("[data-create-dialog-cancel]"),et=document.querySelector("[data-link-existing-chapter-dialog]"),tt=document.querySelector("[data-link-chapter-search]"),nt=document.querySelector("[data-link-chapter-options]"),rt=document.querySelector("[data-link-selected-chapter]"),ot=document.querySelector("[data-link-chapter-dialog-cancel]"),at=document.querySelector("[data-link-chapter-dialog-status]"),ct=document.querySelector("[data-create-chapter-dialog]"),it=document.querySelector("[data-create-chapter-dialog-chapter]"),st=document.querySelector("[data-create-chapter-dialog-book]"),dt=document.querySelector("[data-create-chapter-dialog-confirm]"),lt=document.querySelector("[data-create-chapter-dialog-cancel]"),ut=document.querySelector("[data-apply-structure-sync-dialog]"),pt=document.querySelector("[data-apply-structure-sync-summary]"),ht=document.querySelector("[data-apply-structure-sync-confirm]"),mt=document.querySelector("[data-apply-structure-sync-cancel]"),yt=document.querySelector("[data-resolve-project-id]"),gt=document.querySelector("[data-resolve-project-title]"),ft=document.querySelector("[data-resolve-book-id]"),wt=document.querySelector("[data-resolve-book-title]"),St=document.querySelector("[data-resolve-detected-chapter]"),It=document.querySelector("[data-resolve-detected-scene]"),bt=document.querySelector("[data-resolve-request-chapter]"),Ct=document.querySelector("[data-resolve-request-scene]"),kt=document.querySelector("[data-resolve-result]"),vt=document.querySelector("[data-resolve-chapter-id]"),xt=document.querySelector("[data-resolve-scene-id]"),Nt=document.querySelector("[data-run-diagnostics]"),Et=document.querySelector("[data-diagnostic-host]"),Lt=document.querySelector("[data-diagnostic-platform]"),Pt=document.querySelector("[data-diagnostic-ready]"),qt=document.querySelector("[data-diagnostic-word-api]"),Dt=document.querySelector("[data-diagnostic-last-scan]"),At=document.querySelector("[data-diagnostic-last-error]"),$t=document.querySelector("[data-diagnostic-anchor-type]"),Tt=document.querySelector("[data-diagnostic-stored-scene-id]"),jt=document.querySelector("[data-diagnostic-stored-chapter-id]"),Rt=document.querySelector("[data-diagnostic-resolution-method]"),Wt=document.querySelector("[data-diagnostic-paragraphs]"),Ut=document.querySelector("[data-diagnostic-heading1]"),Mt=document.querySelector("[data-diagnostic-heading2]"),Ot="true"===s?.dataset.authenticated;let Ht=[],Bt=[],Gt=!1,Ft=!1,Vt="Unknown",Jt="Unknown",Yt="",_t="",zt=null,Kt=null,Qt=null,Xt=null,Zt=null,en=null,tn="",nn="Title Match",rn=!1,on=[],an=null,cn=null,sn=[],dn=null,ln=null,un=null,pn=null,hn=null,mn=null,yn=null,gn=null,fn=null,wn=null,Sn=[],In=!1,bn=!1,Cn=0,kn=!1,vn=!1,xn=!1,Nn=null,En="Manual",Ln=!1,Pn=null,qn=!1,Dn=0,An=!1,$n=0,Tn=null;const jn=1200;let Rn=!1,Wn=!1,Un=null,Mn=!1,On=!1,Hn=null,Bn=null,Gn=null,Fn=!1,Vn=!1,Jn=null,Yn="",_n=[],zn=null,Kn="",Qn=null,Xn="",Zn=[],er=null,tr="",nr=null,rr="",or=[],ar=null,cr="",ir="",sr="",dr="",lr=0,ur={characters:[],assets:[],locations:[],primaryLocationId:null};const pr=e=>{const t=Date.now();t-lr<1e3||(lr=t,console.debug(`[Word Companion Runtime] ${e}`))},hr=e=>{console.debug(`[Word Companion Timing] ${e}`)},mr=e=>{T&&(T.textContent=e)},yr=(e,t=!0)=>{const r=i.has(e)&&l.some(t=>t.dataset.tabButton===e)?e:"scene";for(const e of l){const t=e.dataset.tabButton===r;e.classList.toggle("is-active",t),e.setAttribute("aria-selected",t?"true":"false")}for(const e of u){const t=e.dataset.tabPanel===r;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,r)},gr=()=>{const e=(e=>{try{return window.localStorage.getItem(e)||""}catch{return""}})(n);yr(i.has(e)?e:"scene",!1)},fr=e=>{j&&(j.textContent=e),R&&(R.textContent=e)},wr=e=>{H&&(H.textContent=e)},Sr=e=>{B&&(B.textContent=e)},Ir=e=>{z&&(z.textContent=e)},br=e=>{re&&(re.textContent=e)},Cr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("anchorType")&&po($t,Mr(e.anchorType)),t("storedSceneId")&&po(Tt,Mr(e.storedSceneId)),t("storedChapterId")&&po(jt,Mr(e.storedChapterId)),t("resolutionMethod")&&po(Rt,Mr(e.resolutionMethod))},kr=()=>{const e=Co(),t=Number.isInteger(Zt)&&Zt>0&&Xt===Zt,n=!Number.isInteger(en)||en<=0||Qt===en,r=t&&n;po(oe,r?"Attached to PlotDirector":"Not attached"),po(ae,e?.bookId?String(e.bookId):"-"),po(ce,Number.isInteger(en)&&en>0?String(en):"-"),po(ie,Number.isInteger(Zt)&&Zt>0?String(Zt):"-"),se&&(se.disabled=!Zt||r&&!rn,se.textContent=Xt&&!r?"Reattach PlotDirector IDs":"Attach PlotDirector IDs"),Cr({anchorType:nn||"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:tn})},vr=(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=Yt===c&&_t===i&&zt===s&&Kt===d&&Qt===l&&Xt===u;Yt=e||"",_t=t||"",zt=Number.isInteger(n)?n:null,Kt=Number.isInteger(a)&&a>0?a:null,Qt=Number.isInteger(r)&&r>0?r:null,Xt=Number.isInteger(o)&&o>0?o:null,p||(V&&(V.textContent=e||"Not detected"),J&&(J.textContent=t||"Not detected"),Y&&(Y.textContent=Number.isInteger(n)?String(n):"-"),po(Se,Number.isInteger(n)?String(n):"-"),kr())},xr=()=>{Un&&(window.clearTimeout(Un),Un=null)},Nr=(e,t)=>{e&&(e.hidden=t)},Er=e=>{po(Ce,e)},Lr=e=>{po(ee,e)},Pr=(e="Select a project and book to analyse manuscript structure.")=>{if(un=null,te){te.innerHTML="";const e=document.createElement("p");e.textContent="No preview generated.",te.append(e)}Lr(e),Dr()},qr=(e=un)=>((e=un)=>Ko.flatMap(t=>Array.isArray(e?.[t.key])?e[t.key]:[]))(e).filter(e=>"couldLink"===e.category||"wouldCreateChapters"===e.category||"wouldCreateScenes"===e.category),Dr=()=>{Z&&(Z.disabled=xn||0===qr().length)},Ar=()=>{X&&(X.disabled=xn||!bo()||!Co()),Dr()},$r=()=>{De&&(De.textContent=Zt?`Editing links for: ${sr||_t||"Current scene"}`:"Link a PlotDirector scene first.")},Tr=()=>{const e=Ln||!Zt,t=e||!en||Mn;we&&(we.disabled=t),Pe&&(Pe.disabled=e),Le&&(Le.disabled=e);for(const t of[Ne,Ee])for(const n of t?[...t.querySelectorAll("input[type='checkbox']")]:[])n.disabled=e},jr=e=>{"Live"!==e&&"Manual"!==e||(En=e),po(_,e||En||"Manual")},Rr=(e,t="")=>{Ln=!!e,Ln&&(xr(),Ga()),po(_,Ln?"Stale":En),Tr(),t&&(Ir(t),Fr(t))},Wr=(e,t=null,n="")=>{Zt=Number.isInteger(e)&&e>0?e:null,en=Number.isInteger(t)&&t>0?t:null,tn=n||"",Zt!==Hn&&(Bn=null),Zt||(xr(),Ga()),Tr(),Er(Ln?"Refresh Current Scene before syncing.":Zt?"Ready to sync.":"No resolved PlotDirector scene."),Fr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"Link a PlotDirector scene first."),$r(),kr()},Ur=e=>{G&&(G.disabled=e,G.textContent=e?"Refreshing...":"Refresh Current Scene")},Mr=e=>null==e||""===e?"-":String(e),Or=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"})}`},Hr=e=>{hn=e||null;const t=hn?.lastSyncUtc||hn?.manuscriptDocument?.lastSyncUtc;po(fe,Or(t)),po(be,Or(t))},Br=()=>{mn=null,yn=null,gn=null,$n+=1,Tn=null,Fa(),Va(),Ja(),Hr(null)},Gr=()=>{yn=null,gn=null},Fr=e=>{po(qe,e)},Vr=e=>{po(Be,e)},Jr=e=>{po(Re,e)},Yr=()=>!!Co()&&!!Yt&&!en,_r=()=>!!Co()&&!!_t&&Number.isInteger(en)&&en>0,zr=()=>{Nr(Ae,!0),Jr(""),Te&&(Te.disabled=!0,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!0,je.textContent="Link to Existing Chapter")},Kr=(e="")=>{po($e,Mr(Yt)),Nr(Ae,!1),Jr(e);const t=Yr();Te&&(Te.disabled=!t,Te.textContent="Create Chapter in PlotDirector"),je&&(je.disabled=!t,je.textContent="Link to Existing Chapter")},Qr=()=>{Nr(We,!0),Vr(""),Oe&&(Oe.disabled=!0,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!0,He.textContent="Link to Existing Scene")},Xr=(e="")=>{po(Ue,Mr(Yt)),po(Me,Mr(_t)),Nr(We,!1),Vr(e);const t=_r();Oe&&(Oe.disabled=!t,Oe.textContent="Create Scene in PlotDirector"),He&&(He.disabled=!t,He.textContent="Link to Existing Scene")},Zr=e=>{br(e),Nr(de,!0),Nr(ke,!0),Nr(xe,!1),zr(),Qr(),tn="",sr="",dr="",nn=Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",rn=!1,ur={characters:[],assets:[],locations:[],primaryLocationId:null},to(Ne,[],"character"),to(Ee,[],"asset"),no([],null,!1),Wr(null),po(Ie,"-"),po(le,"-"),po(ue,"-"),po(pe,"-"),po(he,"-"),po(me,"-"),po(ge,"-"),Nr(ye,!0),kr(),$r()},eo=(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(eo(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)}},no=(e,t,n=!1)=>{if(!Le)return;Le.innerHTML="";const r=document.createElement("option");r.value="",r.textContent="None",Le.append(r);const o=Number.parseInt(t||"",10);for(const t of Array.isArray(e)?e:[]){const e=Number.parseInt(eo(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,Le.append(n)}Le.disabled=!n},ro=e=>String(e||"").trim().replace(/\s+/g," "),oo=(e,t)=>{const n=ro(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 ro(n.replace(r,""))||n},ao=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("projectId")&&po(yt,Mr(e.projectId)),t("projectTitle")&&po(gt,Mr(e.projectTitle)),t("bookId")&&po(ft,Mr(e.bookId)),t("bookTitle")&&po(wt,Mr(e.bookTitle)),t("detectedChapter")&&po(St,Mr(e.detectedChapter)),t("detectedScene")&&po(It,Mr(e.detectedScene)),t("requestChapter")&&po(bt,Mr(e.requestChapter)),t("requestScene")&&po(Ct,Mr(e.requestScene)),t("result")&&po(kt,Mr(e.result)),t("chapterId")&&po(vt,Mr(e.chapterId)),t("sceneId")&&po(xt,Mr(e.sceneId))},co=async e=>{if(gn===e&&Array.isArray(yn?.chapters))return yn.chapters;const t=await Ca(`/api/word-companion/books/${e}/structure`);return gn=e,yn=t||null,Array.isArray(t?.chapters)?t.chapters:[]},io=async e=>{const t=await Ca(`/api/word-companion/books/${e}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},so=e=>{if(Number.isInteger(en)&&en>0){const t=e.find(e=>e.chapterId===en);if(t)return t}const t=oo(Yt,"chapter").toLocaleLowerCase();return t&&e.find(e=>oo(e.title,"chapter").toLocaleLowerCase()===t)||null},lo=async()=>{const e=Co();return e?so(await co(e.bookId)):null},uo=async(e,t,n,r,o)=>{const a=await Ca(`/api/word-companion/scenes/${t}/companion`);try{a.revisionStatus=await(async(e,t)=>{const n=await Ca(`/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;nn=o||"Title Match",rn=!1,Rr(!1),br("Linked to PlotDirector"),Ir(""),zr(),Qr(),Wr(t,n,r),c=a,sr=c?.sceneTitle||_t||"",dr=c?.chapterTitle||Yt||"",po(le,Mr(c?.sceneTitle)),po(ue,Mr(c?.revisionStatus||c?.revisionStatusName||"Not provided")),po(pe,Mr(c?.estimatedWords)),po(he,Mr(c?.actualWords)),po(Ie,Mr(c?.actualWords)),po(me,c?.blocked?"Blocked":"Not blocked"),c?.blockedReason?(po(ge,c.blockedReason),Nr(ye,!1)):(po(ge,"-"),Nr(ye,!0)),ve&&(ve.textContent=c?.writingBrief||"No writing brief has been added for this scene."),ur={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(Ne,ur.characters,"character",!!Zt&&!Ln),to(Ee,ur.assets,"asset",!!Zt&&!Ln),no(ur.locations,ur.primaryLocationId,!!Zt&&!Ln),$r(),Fr(Ln?"Refresh Current Scene before saving.":Zt?"Ready to save.":"No resolved PlotDirector scene."),Nr(de,!1),Nr(ke,!1),Nr(xe,!1),xa(t,n),Ba(),Za()},po=(e,t)=>{if(e){const n=null==t?"":String(t);e.textContent!==n&&(e.textContent=n)}},ho=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("host")&&po(Et,e.host),t("platform")&&po(Lt,e.platform),t("ready")&&po(Pt,e.ready),t("wordApi")&&po(qt,e.wordApi),t("lastScan")&&po(Dt,e.lastScan),t("lastError")&&po(At,e.lastError),t("paragraphs")&&po(Wt,e.paragraphs),t("heading1")&&po(Ut,e.heading1),t("heading2")&&po(Mt,e.heading2)},mo=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 Gt=!1,Ft=!1,Vt="Unavailable",Jt="Unavailable",ho({host:Vt,platform:Jt,ready:"No",wordApi:"No"}),null;const e=await window.Office.onReady();return Gt=!0,Vt=e?.host||"Unknown",Jt=e?.platform||"Unknown",Ft=!!window.Word&&!!window.Office.HostType&&e?.host===window.Office.HostType.Word,ho({host:Vt,platform:Jt,ready:"Yes",wordApi:Ft?"Yes":"No"}),e},go=e=>{try{const t=window.localStorage.getItem(e),n=Number.parseInt(t||"",10);return Number.isInteger(n)&&n>0?n:null}catch{return null}},fo=(e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}},wo=(e,t)=>{if(!e)return;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent=t,e.append(n),e.disabled=!0},So=(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},Io=e=>{const t=String(e?.title||"").trim(),n=String(e?.subtitle||"").trim();return n?`${t}: ${n}`:t},bo=()=>{const e=Number.parseInt(M?.value||"",10);return Ht.find(t=>t.projectId===e)||null},Co=()=>{const e=Number.parseInt(O?.value||"",10);return Bt.find(t=>t.bookId===e)||null},ko=()=>{const e=Number.parseInt(h?.value||"",10);return Ht.find(t=>t.projectId===e)||null},vo=()=>{const e=Number.parseInt(m?.value||"",10);return Bt.find(t=>t.bookId===e)||null},xo=e=>po(S,e),No=()=>{const e=ko(),t=vo(),n=bn&&Date.now()-Cn>=750;f&&(f.disabled=!e||!t||kn),g&&(g.disabled=!e||!String(y?.value||"").trim()||kn),P&&(P.disabled=!fn?.canImport||!wn||kn),x&&(x.disabled=!n||vn||0===qo().length)},Eo=e=>{Nr(p,!e),Nr(d,e);for(const t of u)Nr(t,!!e||"scene"!==t.dataset.tabPanel&&!t.classList.contains("is-active"));e||gr()},Lo=()=>{if(!h)return;if(0===Ht.length)return void wo(h,"No projects available.");So(h,"Choose a project",Ht,"projectId","title");const e=Number.parseInt(M?.value||"",10);Number.isInteger(e)&&e>0&&(h.value=String(e))},Po=(e="Select a Project and Book to begin.")=>{fn=null,wn=null,Sn=[],In=!1,bn=!1,Cn=0,Nr(I,!0),Nr(L,!0),Nr(b,!0),Nr(v,!0),I&&(I.innerHTML=""),k&&(k.innerHTML=""),po(C,""),xo(e),No()},qo=()=>k?[...k.querySelectorAll("input[type='checkbox']:checked")].map(e=>String(e.value||"").trim()).filter(Boolean):[],Do=e=>{if(Sn=Array.isArray(e)?e:[],b&&k){if(k.innerHTML="",Nr(b,!1),Nr(v,!In||0===Sn.length),Nr(x,!1),Nr(N,!1),Nr(E,!0),0===Sn.length)return po(C,"No likely major characters found."),void No();po(C,`${Sn.length} likely major characters found.`);for(const e of Sn){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",No);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)}No()}},Ao=()=>{const e=window.Office?.context?.document?.settings;if(!e)return null;const t=String(e.get(r)||"").trim(),n=Number.parseInt(e.get(o)||"",10),i=Number.parseInt(e.get(a)||"",10),s=Number.parseInt(e.get(c)||"",10);return!t||!Number.isInteger(n)||n<=0||!Number.isInteger(i)||i<=0?null:{documentGuid:t,bookId:n,projectId:i,bindingVersion:Number.isInteger(s)&&s>0?s:1}},$o=()=>pn?.documentGuid?pn.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)),To=()=>pn?.documentGuid||Ao()?.documentGuid||"",jo=()=>{const e=bo(),t=Co();W&&(W.textContent=e?.title||"(Not connected)"),U&&(U.textContent=t?Io(t):"(Not connected)"),K&&(K.textContent=t?"":"Select a PlotDirector book before refreshing."),Ar()},Ro=e=>String(e?.styleBuiltIn||e?.style||"").replace(/\s+/g,"").toLowerCase(),Wo=(e,t)=>{const n=Ro(e);return n===`heading${t}`||n.endsWith(`.heading${t}`)||n.includes(`heading${t}`)},Uo=e=>String(e||"").trim().split(/\s+/).filter(Boolean).length,Mo=(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},Oo=e=>{try{return Array.isArray(e?.contentControls?.items)?e.contentControls.items:[]}catch(e){return console.warn("Word paragraph content controls were not available.",e),[]}},Ho=(e,t)=>{const n=Oo(e);for(const e of n){const n=Mo(e.tag,t);if(n)return n}return null},Bo=(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(Wo(e,1))return r+=1,a={index:n.length+1,paragraphIndex:t,title:i,anchorId:Ho(e,"PD-CHAPTER"),scenes:[]},n.push(a),void(c=null);if(Wo(e,2)){if(o+=1,!a)return;return c={index:a.scenes.length+1,paragraphIndex:t,title:i,anchorId:Ho(e,"PD-SCENE"),wordCount:0},void a.scenes.push(c)}c&&(c.wordCount+=Uo(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()&&Ro(t)===Ro(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}},Go=new Set(["***","###"]),Fo=(e,t)=>{const n=String(e?.text||"").trim();return{index:t,text:n,styleBuiltIn:e?.styleBuiltIn||"",style:e?.style||"",wordCount:Uo(n),chapterAnchorId:null,sceneAnchorId:null}},Vo=(e,t)=>{e&&(e.endParagraphIndex=t)},Jo=(e,t)=>{e&&(e.endParagraphIndex=t,Vo(e.scenes.at(-1),t))},Yo=(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()&&Ro(e)===Ro(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(!mn)return!1;const t=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.chapters.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(mn,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!==mn.currentChapter?.startParagraphIndex||n?.startParagraphIndex!==mn.currentScene?.startParagraphIndex||t?.anchorId!==mn.currentChapter?.anchorId||n?.anchorId!==mn.currentScene?.anchorId;return mn.currentParagraphIndex=e,mn.currentChapter=t,mn.currentScene=n,!!r&&(vr(t?.title,n?.title,n?.wordCount,t?.anchorId,n?.anchorId,t?.index),r)},zo=e=>{if(!Q)return;if(Q.innerHTML="",0===e.chapters.length){const e=document.createElement("p");return e.textContent="No chapters detected. Use Heading 1 for chapter titles.",void Q.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.",Q.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)}Q.append(e)}},Ko=[{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"}],Qo={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},Xo={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},Zo=(e,t)=>oo(e,t).toLocaleLowerCase(),ea=({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:""}),ta=(e,t)=>{Array.isArray(e[t.category])&&e[t.category].push(t)},na=e=>Array.isArray(e?.scenes)?e.scenes:[],ra=(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=ea({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:e.title,match:`Chapter ${o.chapterId}: ${o.title}`,anchorStatus:r,pdChapter:o,wordChapter:e});return ta(n,t),t}const a=ea({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:`${r} not found`,matches:[],pdChapter:null,wordChapter:e});return ta(n,a),a}const o=t.filter(t=>Zo(t.title,"chapter")===Zo(e.title,"chapter"));if(1===o.length){const t=ea({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 ta(n,t),t}if(o.length>1){const t=ea({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 ta(n,t),t}const a=ea({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:e.title,anchorStatus:r,pdChapter:null,wordChapter:e});return ta(n,a),a},oa=(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=na(n).find(e=>e.sceneId===t);if(e)return{chapter:n,scene:e}}return null})(n,e.anchorId);return a?void ta(r,ea({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 ta(r,ea({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 ta(r,ea({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 ta(r,ea({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));const a=na(t.pdChapter).filter(t=>Zo(t.title,"scene")===Zo(e.title,"scene"));1!==a.length?a.length>1?ta(r,ea({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})):ta(r,ea({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:e,parentItem:t})):ta(r,ea({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}))},aa=e=>{const t=document.createElement("article");t.className="word-companion-preview-item";const n=document.createElement("strong");n.textContent=`${Xo[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: ${Qo[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},ca=e=>{if(te){te.innerHTML="";for(const t of Ko){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(aa(e));te.append(n)}Dr()}},ia=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)(Wo(e,1)||Wo(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=Bo(t.items,n.items);return r.bodyParagraphs=t.items,r},sa=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(Fo),r=[];let o=0,a=0,c=null,i=null,s=0;const d=(e,t=null,n=null)=>c?(Vo(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&&(Wo(e,1)?(Jo(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&&Go.has(e.text)?(a+=1,d(e)):(c.wordCount+=e.wordCount,i&&(i.wordCount+=e.wordCount),s+=e.wordCount)));return Jo(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=Yo(o,r.items);return mn=o,_o(a),pr("Cache rebuilt."),o},da=()=>window.performance&&"function"==typeof window.performance.now?window.performance.now():Date.now(),la=e=>!!e&&!e.stale&&e.generation===$n&&e.documentGuid===To()&&e.sceneId===Zt,ua=async(e={})=>{const t=!!e.includeSelection,n=!1!==e.updateDisplay,r=$n,o=da(),a=bo(),c=Co(),i=mn?.currentScene;if(!i||!Number.isInteger(i.startParagraphIndex)||!Number.isInteger(i.endParagraphIndex))return null;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return null;const s=da(),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(da()-s);if(r!==$n)return hr(`Office snapshot: ${l}ms stale`),{stale:!0,generation:r};let u=!1;if(t){const e=Yo(mn,d.selectionParagraphs);u=_o(e)}const p=mn?.currentScene;if(!p||!Number.isInteger(p.startParagraphIndex)||!Number.isInteger(p.endParagraphIndex))return null;const h=[];let m=0;const y=Math.min(p.endParagraphIndex,d.bodyTexts.length-1),g=mn.currentChapter?.startParagraphIndex;for(let e=p.startParagraphIndex;e<=y;e+=1){const t=String(d.bodyTexts[e]||"").trim();t&&!Go.has(t)&&e!==g&&(h.push(t),m+=Uo(t))}p.wordCount=m,n&&vr(mn.currentChapter?.title,p.title,m,mn.currentChapter?.anchorId,p.anchorId,mn.currentChapter?.index);const f={documentGuid:To(),projectId:a?.projectId||null,bookId:c?.bookId||null,chapterId:en,sceneId:Zt,chapterTitle:mn.currentChapter?.title||"",sceneTitle:p.title||"",sceneText:h.join("\n"),wordCount:m,selectionSignature:`${mn.currentParagraphIndex??-1}:${p.startParagraphIndex}:${p.endParagraphIndex}`,selectionChanged:u,generation:r};return Tn=f,hr(`Office snapshot: ${l}ms; scene words: ${m}; total snapshot: ${Math.round(da()-o)}ms`),f},pa=async()=>la(Tn)?Tn:await ua(),ha=async()=>{if(Ir(""),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return vr(null,null,null),Ir("Word document access is unavailable."),ho({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;F&&(F.disabled=!0,F.textContent="Scanning..."),Ir("Scanning document structure...");try{const e=await window.Word.run(async e=>{const t=Co();return t?await sa(e,!!t.usesExplicitScenes):(mn=null,await ia(e))});return mn||vr(e.currentChapter?.title,e.currentScene?.title,e.currentScene?.wordCount,e.currentChapter?.anchorId,e.currentScene?.anchorId,e.currentChapter?.index),Zr("Not detected"),zo(e),Ir(""),ho({lastScan:"Success",lastError:"-",paragraphs:String(e.paragraphCount),heading1:String(e.heading1Count),heading2:String(e.heading2Count)}),!0}catch(e){const t=mo(e);return console.error("Unable to scan the Word document.",e),vr(null,null,null),Ir(`Unable to scan the Word document: ${t}`),ho({lastScan:"Failure",lastError:t}),!1}finally{F&&(F.disabled=!1,F.textContent="Refresh Document Structure")}},ma=async()=>{const e=Co();if(!bo()||!e)return Lr("Select a project and book to analyse manuscript structure."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Lr("Word document access is unavailable."),ho({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;X&&(X.disabled=!0,X.textContent="Analysing..."),Lr("Analysing manuscript structure...");try{const t=await window.Word.run(async e=>await ia(e)),n=await Ca(`/api/word-companion/books/${e.bookId}/structure`);return vr(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),zo(t),un=((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=ra(t,r,n);for(const o of na(t))oa(o,e,r,n)}return n})(t,n),ca(un),Lr("Preview generated. No changes have been applied."),ho({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),Lr("Unable to analyse manuscript structure."),ho({lastScan:"Failure",lastError:mo(e)}),!1}finally{X&&(X.textContent="Analyse Manuscript Structure",Ar())}},ya=e=>{Nn&&(Nn(e),Nn=null),ut?.close?ut.close():ut&&(ut.hidden=!0)},ga=()=>{const e=((e=un)=>{const t=qr(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(!pt)return;pt.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)}pt.append(n)})(e),ut?new Promise(e=>{Nn=e,ut.showModal?ut.showModal():ut.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.`))},fa=(e,t,n="")=>{e.result=t,e.error=n},wa=e=>Number.isInteger(e?.wordChapter?.index)&&e.wordChapter.index>0?10*e.wordChapter.index:null,Sa=e=>Number.isInteger(e?.wordScene?.index)&&e.wordScene.index>0?10*e.wordScene.index:null,Ia=async(e,t)=>{const n=await ka(`/api/word-companion/books/${e}/chapters`,{title:ro(t.wordTitle),sortOrder:wa(t)});if(!n?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");Gr(),t.pdChapter={chapterId:n.chapterId,title:n.title||t.wordTitle,sortOrder:n.sortOrder||wa(t)||0,scenes:[]},t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},ba=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 ka(`/api/word-companion/books/${e}/chapters/${n.chapterId}/scenes`,{sceneTitle:ro(t.wordTitle),sortOrder:Sa(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");Gr(),t.pdChapter=n,t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:Sa(t)||0},t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},Ca=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()},ka=(e,t)=>Ca(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),va=async(e="")=>{bn=!1,Cn=0,Sn=[],k&&(k.innerHTML=""),Nr(b,!0),Eo(!1),xo(""),Nr(v,!0),e&&Ir(e);const t=await Na();e&&t&&Yt&&Ir(e)},xa=async(e=Zt,t=en)=>{const n=bo(),r=Co(),o=To(),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(ir!==i){ir=i;try{await ka("/api/word-companion/runtime/current-scene",{documentGuid:o,projectId:n.projectId,bookId:r.bookId,chapterId:c,sceneId:a}),pr("Current scene follow event sent.")}catch(e){ir="",console.debug("Unable to notify PlotDirector of current scene.",e)}}},Na=async()=>{const e=Co();if(!(e&&Gt&&Ft&&window.Word&&"function"==typeof window.Word.run))return!1;Ir("Reading manuscript position...");try{Gr(),await Promise.all([Ya(!0),_a(!0),za(!0)]),await co(e.bookId);const t=await window.Word.run(async t=>await sa(t,!!e.usesExplicitScenes));return zo(t),ho({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),Yt?(_t?await tc():await ec(),Rr(!1),jr("Live"),Ir(""),!0):(Zr("Not detected"),Rr(!1),jr("Live"),Ir("Manuscript linked. Click inside a chapter to show the current scene."),!0)}catch(e){return console.error("Unable to initialise bound manuscript runtime.",e),mn=null,jr("Manual"),Ir(`Unable to read manuscript position: ${mo(e)}`),ho({lastScan:"Failure",lastError:mo(e)}),!1}},Ea=e=>e?[...e.querySelectorAll("input[type='checkbox']:checked")].map(e=>Number.parseInt(e.value||"",10)).filter(e=>Number.isInteger(e)&&e>0):[],La=()=>{const e=Number.parseInt(Le?.value||"",10);return Number.isInteger(e)&&e>0?e:null},Pa=(e,t,n,r)=>{const o=((e,t)=>Oo(e).find(e=>Mo(e.tag,t))||null)(e,r),a=o||e.getRange().insertContentControl();return a.title=t,a.tag=n,a.appearance="Hidden",a},qa=async(e="PlotDirector IDs attached successfully.")=>{if(!Zt||!en)return Ir("No resolved PlotDirector scene."),!1;if((Xt&&Xt!==Zt||Qt&&Qt!==en)&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Ir("Word document access is unavailable."),!1;se&&(se.disabled=!0,se.textContent="Attaching...");try{return await window.Word.run(async e=>{const t=await ia(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.");Pa(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),Pa(r,"PlotDirector Scene",`PD-SCENE-${Zt}`,"PD-SCENE"),await e.sync()}),Qt=en,Xt=Zt,rn=!1,nn="SceneID Anchor",tn="Anchor",Ir(e),ho({lastError:"-"}),kr(),!0}catch(e){return console.error("Unable to attach PlotDirector IDs.",e),Ir("Unable to attach PlotDirector IDs."),ho({lastError:mo(e)}),kr(),!1}finally{se&&(se.textContent=Xt===Zt?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",kr())}},Da=async e=>{if(!en)return Jr("No resolved PlotDirector chapter."),!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Jr("Word document access is unavailable."),!1;try{return await window.Word.run(async e=>{const t=await ia(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.");Pa(n,"PlotDirector Chapter",`PD-CHAPTER-${en}`,"PD-CHAPTER"),await e.sync()}),Qt=en,rn=!1,nn="ChapterID Anchor",tn="Chapter anchor",Jr(e),Ir(e),ho({lastError:"-"}),kr(),!0}catch(e){return console.error("Unable to attach PlotDirector chapter ID.",e),Jr("Unable to attach PlotDirector chapter ID."),ho({lastError:mo(e)}),kr(),!1}},Aa=async e=>{zr(),await tc(),Ir(e),Jr(e)},$a=e=>{ln&&(ln(e),ln=null),ct?.close?ct.close():ct&&(ct.hidden=!0)},Ta=()=>{if(!nt)return;const e=ro(tt?.value||"").toLocaleLowerCase(),t=sn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(nt.innerHTML="",dn=null,rt&&(rt.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No chapters found.",void nt.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",()=>{dn=t,rt&&(rt.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled chapter",n.append(r,o),nt.append(n)}},ja=()=>{et?.close?et.close():et&&(et.hidden=!0)},Ra=async(e,t,n)=>{const r=Co();if(!r)return Vr("Select a PlotDirector book first."),!1;await uo(r.bookId,e,t,"Manual link","Title Match");return!!await qa(n)&&(Vr(n),Qr(),!0)},Wa=e=>{cn&&(cn(e),cn=null),ze?.close?ze.close():ze&&(ze.hidden=!0)},Ua=()=>{if(!Ve)return;const e=ro(Fe?.value||"").toLocaleLowerCase(),t=on.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(Ve.innerHTML="",an=null,Je&&(Je.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No scenes found.",void Ve.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",()=>{an=t,Je&&(Je.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled scene",n.append(r,o),Ve.append(n)}},Ma=()=>{Ge?.close?Ge.close():Ge&&(Ge.hidden=!0)},Oa=()=>{Mn=!1,Tr(),On&&(On=!1,Ba(1e3))},Ha=async(e={})=>{const t=e.source||"manual",n=da();if(!Zt)return void Er("No resolved PlotDirector scene.");if(!en)return void Er("No resolved PlotDirector chapter.");if(Ln)return void Er("Refresh Current Scene before syncing.");const r=Co(),o=To();if(!r||!o)return void Er("Bound manuscript metadata is unavailable.");if(Mn)return On=!0,void pr("Scene sync deferred; sync already running.");xr(),Mn=!0,On=!1;let a=e.snapshot||null;try{a=la(a)?a:await pa()}catch(e){return Er("Sync failed"),ho({lastError:mo(e)}),pr("Scene sync failed."),void Oa()}if(!la(a))return Er("Waiting for typing to pause"),pr("Scene sync skipped (stale snapshot)."),void Oa();const c=a.wordCount;if(!Number.isInteger(c)||c<0)return Er("Sync failed"),pr("Scene sync failed."),void Oa();if(Hn===a.sceneId&&Bn===c)return Er("Synced"),pr("Sync skipped (count unchanged)."),void Oa();pr("Scene word count changed."),we&&(we.disabled=!0,we.textContent="Syncing..."),Er("Syncing..."),pr(`Scene sync started (${t}).`);try{const e=da(),t=await ka("/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(hr(`Word count sync API: ${Math.round(da()-e)}ms`),!la(a))return void pr("Scene sync result ignored (stale snapshot).");const i=t?.actualWords??c,s=new Date;Hn=a.sceneId,Bn=i,po(Ie,Mr(i)),po(he,Mr(i)),po(be,Or(s)),po(fe,Or(s)),Er("Synced"),pr("Scene sync succeeded."),hr(`Total word count sync: ${Math.round(da()-n)}ms`)}catch(e){Er("Sync failed"),ho({lastError:mo(e)}),pr("Scene sync failed.")}finally{we&&(we.textContent="Sync Current Scene"),Oa()}},Ba=(e=4e3)=>{xr(),Zt&&en&&!Ln&&!Mn&&(Un=window.setTimeout(()=>{Un=null,Ha({source:"automatic"})},e))},Ga=()=>{Gn&&(window.clearTimeout(Gn),Gn=null)},Fa=()=>{Jn=null,Yn="",_n=[],zn=null,Kn="",Ga()},Va=()=>{Qn=null,Xn="",Zn=[],er=null,tr=""},Ja=()=>{nr=null,rr="",or=[],ar=null,cr=""},Ya=async(e=!1)=>{const t=bo(),n=To();if(!t||!n)return _n=[],[];if(!e&&Jn===t.projectId&&Yn===n&&_n.length>0)return _n;const r=await Ca(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return Jn=t.projectId,Yn=n,_n=Array.isArray(r?.characters)?r.characters:[],pr("Character alias cache refreshed."),_n},_a=async(e=!1)=>{const t=bo(),n=To();if(!t||!n)return Zn=[],[];if(!e&&Qn===t.projectId&&Xn===n&&Zn.length>0)return Zn;const r=await Ca(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return Qn=t.projectId,Xn=n,Zn=Array.isArray(r?.assets)?r.assets:[],pr(`Asset cache loaded: ${Zn.length} aliases.`),Zn},za=async(e=!1)=>{const t=bo(),n=To();if(!t||!n)return or=[],[];if(!e&&nr===t.projectId&&rr===n&&or.length>0)return or;const r=await Ca(`/api/word-companion/runtime/locations?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return nr=t.projectId,rr=n,or=Array.isArray(r?.locations)?r.locations:[],pr(`Location cache loaded: ${or.length} aliases.`),or},Ka=(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)},Qa=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},Xa=async()=>{if(Gn=null,!Zt||Ln||!To())return;if(Fn)return Vn=!0,void pr("Character suggestion detection deferred; detection already running.");Fn=!0,Vn=!1;const e=da();try{const t=await pa();if(!la(t))return void pr("Runtime suggestions skipped (stale snapshot).");const[n,r,o]=await Promise.all([Ya(),_a(),za()]);if(!la(t))return void pr("Runtime suggestions skipped after cache load (stale snapshot).");const a=t.sceneText||"",c=da(),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)||Ka(e,r.matchText)&&n.set(t,r.name||r.matchText||"Character")}return[...n.entries()].map(([e,t])=>({characterId:e,name:t}))})(a,n);hr(`Character detection: ${Math.round(da()-c)}ms`);const s=i.map(e=>e.characterId),d=s.slice().sort((e,t)=>e-t).join(","),l=da(),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)||Ka(e,r.matchText)&&n.set(t,r.name||r.matchText||"Asset")}return[...n.entries()].map(([e,t])=>({assetId:e,name:t}))})(a,r);hr(`Asset detection: ${Math.round(da()-l)}ms`);const p=u.map(e=>e.assetId),h=p.slice().sort((e,t)=>e-t).join(","),m=da(),y=((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)||!Qa(r)||Ka(e,r.matchText)&&n.set(t,r.name||r.matchText||"Location")}return[...n.entries()].map(([e,t])=>({locationId:e,name:t}))})(a,o);hr(`Location detection: ${Math.round(da()-m)}ms`);const g=y.map(e=>e.locationId),f=g.slice().sort((e,t)=>e-t).join(",");if(!d||zn===Zt&&Kn===d)pr("Character suggestions skipped.");else{if(!la(t))return void pr("Character suggestions skipped before submit (stale snapshot).");const e=da(),n=await ka("/api/word-companion/runtime/character-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,characterIds:s});if(hr(`Character suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void pr("Character suggestion result ignored (stale snapshot).");if(zn=t.sceneId,Kn=d,(n?.createdCount||0)>0){const e=i.slice(0,3).map(e=>e.name).join(", "),t=i.length>3?" +"+(i.length-3):"";Ir(e?`Characters detected: ${e}${t}`:n.message)}pr(n?.message||"Character suggestions submitted.")}if(!h||er===Zt&&tr===h)pr("Asset suggestions skipped.");else{if(!la(t))return void pr("Asset suggestions skipped before submit (stale snapshot).");pr(`Asset matches found: ${u.map(e=>e.name).join(", ")}`);const e=da(),n=await ka("/api/word-companion/runtime/asset-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,assetIds:p});if(hr(`Asset suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void pr("Asset suggestion result ignored (stale snapshot).");if(er=t.sceneId,tr=h,(n?.createdCount||0)>0){const e=u.slice(0,3).map(e=>e.name).join(", "),t=u.length>3?" +"+(u.length-3):"";Ir(e?`Assets detected: ${e}${t}`:n.message)}pr(n?.message||"Asset suggestions submitted.")}if(!f||ar===Zt&&cr===f)pr("Location suggestions skipped.");else{if(!la(t))return void pr("Location suggestions skipped before submit (stale snapshot).");pr(`Location matches found: ${y.map(e=>e.name).join(", ")}`);const e=da(),n=await ka("/api/word-companion/runtime/location-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,locationIds:g});if(hr(`Location suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void pr("Location suggestion result ignored (stale snapshot).");if(ar=t.sceneId,cr=f,(n?.createdCount||0)>0){const e=y.slice(0,3).map(e=>e.name).join(", "),t=y.length>3?" +"+(y.length-3):"";Ir(e?`Locations detected: ${e}${t}`:n.message)}pr(n?.message||"Location suggestions submitted.")}hr(`Total suggestion pass: ${Math.round(da()-e)}ms`)}catch(e){console.error("Unable to detect runtime suggestions.",e),ho({lastError:mo(e)})}finally{Fn=!1,Vn&&(Vn=!1,Za(1500))}},Za=(e=2500)=>{Ga(),!Zt||Ln||Fn?Fn&&(Vn=!0):Gn=window.setTimeout(()=>{Xa()},e)},ec=async()=>{const e=bo(),t=Co(),n=oo(Yt,"chapter");if(ao({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Io(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!t)return Zr("Not detected"),Ir("Select a PlotDirector book first."),!1;if(!Yt)return Zr("Not detected"),Ir("No chapter detected in Word. Use Heading 1 for chapters."),!1;Zr("Not detected");try{const e=await io(t.bookId),r=Qt?e.find(e=>e.chapterId===Qt):null,o=n.toLocaleLowerCase(),a=o?e.find(e=>oo(e.title,"chapter").toLocaleLowerCase()===o):null,c=r||a;return c?(zr(),Wr(null,c.chapterId,r?"Chapter anchor":"Chapter title"),nn=r?"ChapterID Anchor":"Title Match",br("Chapter linked to PlotDirector"),Ir("No scene detected in Word. Use Heading 2 for scenes."),ao({result:"Chapter matched",chapterId:c.chapterId,sceneId:null}),!0):(Wr(null),br("Chapter not found in PlotDirector."),Ir("Chapter not found in PlotDirector."),ao({result:"Chapter not matched",chapterId:null,sceneId:null}),Kr("Chapter not found in PlotDirector."),!1)}catch(e){return Zr("Not found in PlotDirector"),ho({lastError:mo(e)}),Ir("Unable to load PlotDirector chapter data."),!1}},tc=async()=>{const e=bo(),t=Co(),n=oo(Yt,"chapter"),r=oo(_t,"scene");if(ao({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Io(t):void 0,detectedChapter:Yt,detectedScene:_t,requestChapter:n,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),Cr({anchorType:Xt?"SceneID Anchor":Qt?"ChapterID Anchor":"Title Match",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"-"}),!t)return Zr("Not detected"),Ir("Select a PlotDirector book first."),ao({result:"Error"}),!1;if(!Yt||!_t)return Zr("Not detected"),Ir("No scene detected in Word. Use Heading 2 for scenes."),ao({result:"Error"}),!1;ne&&(ne.disabled=!0,ne.textContent="Refreshing...");const o=()=>{ne&&(ne.disabled=!1,ne.textContent="Refresh PlotDirector Scene")};Zr("Not detected"),Ir("Resolving PlotDirector scene...");try{if(Xt){const e=await(async(e,t)=>{const n=await Ca(`/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===Xt);if(e)return ao({result:"Matched",chapterId:e.chapter.chapterId,sceneId:e.scene.sceneId}),await uo(t.bookId,e.scene.sceneId,e.chapter.chapterId,"Anchor","SceneID Anchor"),!0;rn=!0,nn="SceneID Anchor",br("Not found in PlotDirector"),Ir("Stored PlotDirector ID is invalid."),ao({result:"Error",chapterId:Qt,sceneId:Xt}),Cr({anchorType:"SceneID Anchor",storedSceneId:Xt,storedChapterId:Qt,resolutionMethod:"Anchor"})}if(Qt){const e=(await co(t.bookId)).find(e=>e.chapterId===Qt),n=e?(Array.isArray(e.scenes)?e.scenes:[]).find(e=>oo(e.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(n)return ao({result:"Matched",chapterId:e.chapterId,sceneId:n.sceneId}),await uo(t.bookId,n.sceneId,e.chapterId,"Anchor","ChapterID Anchor"),!0;e&&!Xt?(nn="ChapterID Anchor",Wr(null,Qt,"Chapter anchor"),ao({result:"Chapter matched",chapterId:Qt,sceneId:null})):Xt||(nn="ChapterID Anchor",ao({result:"Chapter anchor not found",chapterId:Qt,sceneId:null}))}const e=await ka(`/api/word-companion/books/${t.bookId}/resolve-scene`,{chapterTitle:n,sceneTitle:r});if(!e?.matched||!e.sceneId){const t=rn,n=Number.parseInt(e?.chapterId||"",10),r=Number.isInteger(en)&&en>0?en:null,a=Number.isInteger(n)&&n>0?n:r,c=!!e?.chapterMatched||!!a;return Zr("Not found in PlotDirector"),rn=t,c&&(Wr(null,a,a===r?"Chapter anchor":"Chapter title"),br("Scene not found in PlotDirector.")),Ir(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."),ao({result:"Not matched",chapterId:c?a:e?.chapterId,sceneId:e?.sceneId}),t||(c?(zr(),Xr("Scene not found in PlotDirector.")):(Qr(),Kr("Chapter not found in PlotDirector."))),o(),!1}const a=rn;return ao({result:a?"Matched by title fallback":"Matched",chapterId:e.chapterId,sceneId:e.sceneId}),await uo(t.bookId,e.sceneId,e.chapterId,a?"Title fallback":"Title","Title Match"),a&&(rn=!0,Ir("Stored PlotDirector ID is invalid."),kr()),!0}catch(e){const t=rn;return ho({lastError:mo(e)}),Zr("Not found in PlotDirector"),rn=t,Ir(t?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),ao({result:"Error"}),!1}finally{o()}},nc=async()=>{if(Pn=null,Wn)return An=!0,void pr("Runtime update deferred; update already running.");if(!Ot||!Co())return qn=!1,void pr("Runtime update skipped.");if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return qn=!1,jr("Manual"),void Ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");if(!mn)return qn=!1,jr("Manual"),void Ir("Document structure is not cached yet. Use Refresh Current Scene.");const e=Date.now()-Dn;if(qn&&e{Pn&&window.clearTimeout(Pn),Pn=window.setTimeout(nc,Math.max(0,e)),jr("Waiting for typing to pause"),pr("Runtime update scheduled.")},oc=()=>{((e="selection",t=1200)=>{if(qn=!0,Dn=Date.now(),$n+=1,Tn=null,xr(),Ga(),Mn&&(On=!0),Fn&&(Vn=!0),pr(`${e} changed.`),Wn)return An=!0,void jr("Waiting for typing to pause");rc(t)})("Selection")},ac=()=>{if(Rn&&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:oc}),Rn=!1}catch(e){console.warn("Unable to remove Word selection tracking handler.",e)}},cc=async(e,n)=>{if(mn=null,Gr(),!e)return Bt=[],wo(O,"Select a project first"),wo(m,"Select a project first"),Sr(""),fo(t,null),jo(),Zr("Not detected"),void Pr();wo(O,"Loading books..."),Sr(""),Zr("Not detected"),Pr("Select a book to analyse manuscript structure.");try{const r=await Ca(`/api/word-companion/projects/${e}/books`);if(Bt=Array.isArray(r.books)?r.books:[],0===Bt.length)return wo(O,"No books available."),wo(m,"No books available."),Sr("No books available."),fo(t,null),jo(),void Po("No books available.");So(O,"Choose a book",Bt.map(e=>({...e,displayTitle:Io(e)})),"bookId","displayTitle");const o=Bt.find(e=>e.bookId===n);o&&O?(O.value=String(o.bookId),fo(t,o.bookId)):fo(t,null),((e=null)=>{if(!m)return;if(0===Bt.length)return void wo(m,"No books available.");So(m,"Choose a book",Bt.map(e=>({...e,displayTitle:Io(e)})),"bookId","displayTitle");const t=e||Number.parseInt(O?.value||"",10),n=Bt.find(e=>e.bookId===t);n&&(m.value=String(n.bookId)),No()})(o?.bookId||n),jo(),Zr((Co(),"Not detected")),Pr(Co()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Po(vo()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{Bt=[],wo(O,"Unable to load books."),wo(m,"Unable to load books."),Sr("Unable to load books."),fo(t,null),jo(),Zr("Not detected"),Pr("Unable to load books."),Po("Unable to load books.")}};for(const e of l)e.addEventListener("click",()=>yr(e.dataset.tabButton));gr(),M?.addEventListener("change",async()=>{const n=Number.parseInt(M.value||"",10);Br(),h&&Number.isInteger(n)&&n>0&&(h.value=String(n)),fo(e,Number.isInteger(n)&&n>0?n:null),fo(t,null),Zr("Not detected"),Pr(),Po("Select a Book to begin."),await cc(n,null)}),O?.addEventListener("change",()=>{const e=Number.parseInt(O.value||"",10);Br(),fo(t,Number.isInteger(e)&&e>0?e:null),m&&Number.isInteger(e)&&e>0&&(m.value=String(e)),jo(),Zr("Not detected"),Pr(Co()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Po(vo()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),h?.addEventListener("change",async()=>{const n=Number.parseInt(h.value||"",10);Br(),M&&Number.isInteger(n)&&n>0&&(M.value=String(n)),fo(e,Number.isInteger(n)&&n>0?n:null),fo(t,null),Po("Select a Book to begin."),await cc(n,null)}),m?.addEventListener("change",()=>{const e=Number.parseInt(m.value||"",10);Br(),O&&Number.isInteger(e)&&e>0&&(O.value=String(e)),fo(t,Number.isInteger(e)&&e>0?e:null),jo(),Po(vo()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),y?.addEventListener("input",No),g?.addEventListener("click",async()=>{const e=ko(),t=String(y?.value||"").trim();if(e&&t){g.disabled=!0,xo("Creating Book...");try{const n=await ka(`/api/word-companion/projects/${e.projectId}/books`,{title:t});y&&(y.value=""),M&&(M.value=String(e.projectId)),await cc(e.projectId,n.bookId),m&&(m.value=String(n.bookId)),xo("Ready to scan manuscript structure.")}catch(e){console.error("Unable to create Book from Word Companion.",e),xo(`Unable to create Book: ${mo(e)}`)}finally{No()}}else No()}),f?.addEventListener("click",async()=>{const e=ko(),t=vo();if(e&&t)if(Gt&&Ft&&window.Word&&"function"==typeof window.Word.run){f&&(f.disabled=!0,f.textContent="Scanning..."),xo("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),Wo(e,1))return r={title:d,sortOrder:10*(n.length+1),wordCount:0,scenes:[]},n.push(r),o=s(),void(a+=Uo(d));if(!r||!o)return;if(t&&i.has(d))return void(o=s());const l=Uo(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)});wn=n,In=!1;const r=await ka("/api/word-companion/manuscript/analyse",{projectId:e.projectId,bookId:t.bookId,documentGuid:$o(),chapterCount:n.chapterCount,sceneCount:n.sceneCount,wordCount:n.wordCount});fn=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",Io({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),Nr(I,!1),Nr(L,!1),xo(e.message||"Preview generated."),No()})(r);try{const t=await ka("/api/word-companion/manuscript/discover-characters",{projectId:e.projectId,documentText:n.documentText||""});Sn=Array.isArray(t?.candidates)?t.candidates:[],Nr(b,!0),Nr(v,!0)}catch(e){console.error("Unable to discover character candidates.",e),Sn=[],Nr(b,!0),Nr(v,!0)}ho({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(n.chapterCount),heading2:"-"})}catch(e){console.error("Unable to scan manuscript for first-run import.",e),Po(`Unable to scan manuscript: ${mo(e)}`),ho({lastScan:"Failure",lastError:mo(e)})}finally{f&&(f.textContent="Scan Manuscript"),No()}}else Po("Word document access is unavailable.");else Po("Select a Project and Book to begin.")}),P?.addEventListener("click",async()=>{const n=ko(),i=vo();if(!(n&&i&&wn&&fn?.canImport))return void No();let s=!1;if(!fn.requiresReplaceConfirmation||(s=await new Promise(e=>{if(!D||"function"!=typeof D.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),D?.removeEventListener("cancel",o),D?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),o=e=>{e.preventDefault(),t(!1)};A?.addEventListener("click",n),$?.addEventListener("click",r),D?.addEventListener("cancel",o),D.showModal()}),s)){kn=!0,No(),xo("Importing manuscript structure...");try{const l=$o(),u=await ka("/api/word-companion/manuscript/import",{projectId:n.projectId,bookId:i.bookId,documentGuid:l,bindingVersion:1,replacePlanned:s,chapters:wn.chapters});if(!u.imported)return fn={...fn,canImport:!u.requiresReplaceConfirmation,requiresReplaceConfirmation:!!u.requiresReplaceConfirmation,message:u.message||fn.message},xo(u.message||"Import was not completed."),void No();const p=u.manuscriptDocument;await(d={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},new Promise((e,t)=>{const n=window.Office?.context?.document?.settings;n?(n.set(r,d.documentGuid),n.set(o,String(d.bookId)),n.set(a,String(d.projectId)),n.set(c,String(d.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."))})),pn={documentGuid:p?.documentGuid||l,bookId:u.bookId,projectId:u.projectId,bindingVersion:p?.bindingVersion||1},fo(e,u.projectId),fo(t,u.bookId),M&&(M.value=String(u.projectId));const h=Sn;await cc(u.projectId,u.bookId),fr("Connected"),In=!0,bn=h.length>0,Cn=bn?Date.now():0,Sn=h,h.length>0?(Eo(!0),Do(h),Nr(L,!0),Nr(v,!1),xo(u.message||"Manuscript structure imported."),Ir(u.message||"Manuscript structure imported."),window.setTimeout(No,750)):await va(u.message||"Manuscript structure imported.")}catch(e){console.error("Unable to import manuscript structure.",e),xo(`Unable to import manuscript: ${mo(e)}`)}finally{kn=!1,No()}var d}else xo("Import cancelled.")}),x?.addEventListener("click",async()=>{const e=ko()||bo(),t=qo();if(!bn||Date.now()-Cn<750||!e||0===t.length)No();else{vn=!0,No(),po(C,"Creating selected characters...");try{const n=await ka("/api/word-companion/manuscript/create-discovered-characters",{projectId:e.projectId,candidateNames:t});Ir(n.message||"Characters created."),po(C,`${n.createdCount||0} created, ${n.skippedCount||0} already existed.`),await va(n.message||"Characters created.")}catch(e){console.error("Unable to create discovered characters.",e),po(C,`Unable to create characters: ${mo(e)}`)}finally{vn=!1,No()}}}),N?.addEventListener("click",()=>va("Character creation skipped.")),E?.addEventListener("click",()=>va()),w?.addEventListener("click",()=>Eo(!1)),q?.addEventListener("click",()=>Po("Import cancelled.")),F?.addEventListener("click",ha),X?.addEventListener("click",ma),Z?.addEventListener("click",async()=>{const e=Co();if(!e||0===qr().length||xn)return void Dr();if(!await ga())return;xn=!0,Ar(),Lr("Applying structure sync...");const t={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(un?.manualReview)?un.manualReview.length:0,failed:0},n=qr().filter(e=>"couldLink"===e.category&&"Chapter"===e.type),r=qr().filter(e=>"wouldCreateChapters"===e.category),o=qr().filter(e=>"couldLink"===e.category&&"Scene"===e.type),a=qr().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(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const n=await ia(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.");Pa(o,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=e.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");Pa(o,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})})(e),fa(e,"Success"),t[n]+=1}catch(n){fa(e,"Failed",mo(n)),t.failed+=1}};try{for(const e of n)s(e,"linkedChapters");for(const n of r)try{await Ia(e.bookId,n),s(n,"createdChapters")}catch(e){fa(n,"Failed",mo(e)),t.failed+=1}for(const e of o)s(e,"linkedScenes");for(const n of a)try{await ba(e.bookId,n),s(n,"createdScenes")}catch(e){fa(n,"Failed",mo(e)),t.failed+=1}for(const e of c)await d(e.item,e.counterName);for(const e of un.manualReview||[])fa(e,"Skipped");ca(un),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),Lr(i)}finally{xn=!1,Ar(),i&&(Gr(),await ma(),Lr(`${i} Preview refreshed.`))}}),ht?.addEventListener("click",()=>ya(!0)),mt?.addEventListener("click",()=>ya(!1)),ut?.addEventListener("cancel",e=>{e.preventDefault(),ya(!1)}),ne?.addEventListener("click",tc),G?.addEventListener("click",async()=>{if(!Co())return Ir("Select a PlotDirector book first."),void Zr("Not detected");Pn&&(window.clearTimeout(Pn),Pn=null),qn=!1,An=!1,Ur(!0),jr("Updating...");try{await Promise.all([Ya(!0),_a(!0),za(!0)]);if(!await ha())return;if(Rr(!1),!_t)return await ec(),void jr("Current scene updated");await tc(),jr("Current scene updated")}finally{Ur(!1)}}),we?.addEventListener("click",()=>Ha({source:"manual"})),Pe?.addEventListener("click",async()=>{if(Zt)if(!Ln&&await(async()=>{if(!Zt)return!1;if(!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return Rr(!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 ia(e)),t=e.currentChapter?.title||"",n=e.currentScene?.title||"",r=e.currentScene?.anchorId||null,o=e.currentChapter?.anchorId||null,a=Number.isInteger(r)&&r===Zt,c=Number.isInteger(o)&&o===en,i=oo(n,"scene").toLocaleLowerCase()===oo(sr||_t,"scene").toLocaleLowerCase(),s=oo(t,"chapter").toLocaleLowerCase()===oo(dr||Yt,"chapter").toLocaleLowerCase();return a||i&&(c||s)?(Rr(!1),!0):(Rr(!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),ho({lastError:mo(e)}),Rr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}})()){Pe&&(Pe.disabled=!0,Pe.textContent="Saving...");try{await(e=`/api/word-companion/scenes/${Zt}/links`,t={characterIds:Ea(Ne),assetIds:Ea(Ee),locationIds:[],primaryLocationId:La()},Ca(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})),(()=>{const e=new Set(Ea(Ne)),t=new Set(Ea(Ee));ur={characters:ur.characters.map(t=>({...t,linked:e.has(Number.parseInt(eo(t,"character"),10))})),assets:ur.assets.map(e=>({...e,linked:t.has(Number.parseInt(eo(e,"asset"),10))})),locations:ur.locations,primaryLocationId:La()}})(),Fr("Scene links saved successfully."),ho({lastError:"-"})}catch(e){Fr("Unable to save scene links."),ho({lastError:mo(e)})}finally{Pe&&(Pe.disabled=!Zt||Ln,Pe.textContent="Save Scene Links")}var e,t}else Fr("The Word cursor is now in a different scene. Refresh Current Scene before saving.");else Fr("Link a PlotDirector scene first.")}),se?.addEventListener("click",async()=>{await qa()}),Te?.addEventListener("click",async()=>{const e=Co();if(!e||!Yt||en)return void Kr("Chapter not found in PlotDirector.");const t=ro(Yt),n=await((e,t)=>(po(it,`"${e}"`),po(st,`"${t}"`),ct?new Promise(e=>{ln=e,ct.showModal?ct.showModal():ct.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector chapter:\n\n"${e}"\n\nin book:\n\n"${t}"\n\n?`))))(t,Io(e)||"selected book");if(n){Te&&(Te.disabled=!0,Te.textContent="Creating...");try{const n=Number.isInteger(Kt)&&Kt>0?10*Kt:null,r=await ka(`/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.");Gr(),Wr(null,r.chapterId,"Manual chapter link");if(!await Da("Chapter created and linked successfully."))return;await Aa("Chapter created and linked successfully.")}catch(e){Jr("Unable to create chapter."),ho({lastError:mo(e)})}finally{Te&&(Te.disabled=!Yr(),Te.textContent="Create Chapter in PlotDirector")}}}),je?.addEventListener("click",async()=>{const e=Co();if(e&&Yt&&!en){je&&(je.disabled=!0,je.textContent="Loading...");try{sn=await io(e.bookId),dn=null,tt&&(tt.value=""),po(at,""),Ta(),et?.showModal?et.showModal():et&&(et.hidden=!1)}catch(e){Jr("Unable to load chapters."),ho({lastError:mo(e)})}finally{je&&(je.disabled=!Yr(),je.textContent="Link to Existing Chapter")}}else Kr("Chapter not found in PlotDirector.")}),tt?.addEventListener("input",Ta),rt?.addEventListener("click",async()=>{const e=sn.find(e=>e.chapterId===dn);if(e){rt&&(rt.disabled=!0,rt.textContent="Linking...");try{Wr(null,e.chapterId,"Manual chapter link");if(!await Da("Chapter linked successfully."))return;ja(),await Aa("Chapter linked successfully.")}catch(e){po(at,"Unable to link chapter."),Jr("Unable to link chapter."),ho({lastError:mo(e)})}finally{rt&&(rt.disabled=!dn,rt.textContent="Link Chapter")}}else po(at,"Select a chapter.")}),ot?.addEventListener("click",ja),dt?.addEventListener("click",()=>$a(!0)),lt?.addEventListener("click",()=>$a(!1)),ct?.addEventListener("cancel",e=>{e.preventDefault(),$a(!1)}),Oe?.addEventListener("click",async()=>{const e=Co();if(!e||!_t)return void Xr("Scene not found in PlotDirector.");const t=oo(_t,"scene"),n=oo(Yt,"chapter"),r=await((e,t)=>(po(Ke,`"${e}"`),po(Qe,`"${t}"`),ze?new Promise(e=>{cn=e,ze.showModal?ze.showModal():ze.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector scene:\n\n"${e}"\n\nwithin chapter:\n\n"${t}"\n\n?`))))(t,n);if(r){Oe&&(Oe.disabled=!0,Oe.textContent="Creating...");try{const n=await lo();if(!n)return void Xr("This chapter does not exist in PlotDirector. Create or link the chapter first.");const r=await ka(`/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.");Gr(),await Ra(r.sceneId,r.chapterId,"Scene created and linked successfully.")}catch(e){Vr("Unable to create scene."),ho({lastError:mo(e)})}finally{Oe&&(Oe.disabled=!_r(),Oe.textContent="Create Scene in PlotDirector")}}}),He?.addEventListener("click",async()=>{const e=Co();if(e&&_t){He&&(He.disabled=!0,He.textContent="Loading...");try{const t=await co(e.bookId),n=so(t);if(!n)return void Xr("This chapter does not exist in PlotDirector. Create or link the chapter first.");on=Array.isArray(n.scenes)?n.scenes:[],an=null,Fe&&(Fe.value=""),po(_e,""),Ua(),Ge?.showModal?Ge.showModal():Ge&&(Ge.hidden=!1)}catch(e){Vr("Unable to load scenes."),ho({lastError:mo(e)})}finally{He&&(He.disabled=!_r(),He.textContent="Link to Existing Scene")}}else Xr("Scene not found in PlotDirector.")}),Fe?.addEventListener("input",Ua),Je?.addEventListener("click",async()=>{const e=Co(),t=on.find(e=>e.sceneId===an);if(e&&t){Je&&(Je.disabled=!0,Je.textContent="Linking...");try{const e=await lo();if(!e)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");Ma(),await Ra(t.sceneId,e.chapterId,"Scene linked successfully.")}catch(e){po(_e,"Unable to link scene."),Vr("Unable to link scene."),ho({lastError:mo(e)})}finally{Je&&(Je.disabled=!an,Je.textContent="Link Scene")}}else po(_e,"Select a scene.")}),Ye?.addEventListener("click",Ma),Xe?.addEventListener("click",()=>Wa(!0)),Ze?.addEventListener("click",()=>Wa(!1)),ze?.addEventListener("cancel",e=>{e.preventDefault(),Wa(!1)}),Nt?.addEventListener("click",async()=>{Nt&&(Nt.disabled=!0,Nt.textContent="Running...");try{if(await yo(),!Gt||!Ft||!window.Word||"function"!=typeof window.Word.run)return void ho({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});ho({lastScan:"Success",lastError:"-",paragraphs:String(e)})}catch(e){console.error("Word Companion diagnostics failed.",e);const t=mo(e);ho({lastScan:"Failure",lastError:t}),Ir(`Unable to scan the Word document: ${t}`)}finally{Nt&&(Nt.disabled=!1,Nt.textContent="Run Diagnostics")}});const ic=Ot?(async()=>{wo(M,"Loading projects..."),wo(O,"Select a project first"),wo(h,"Loading projects..."),wo(m,"Select a project first"),wr(""),Sr("");try{const n=await Ca("/api/word-companion/projects");if(Ht=Array.isArray(n.projects)?n.projects:[],0===Ht.length)return wo(M,"No projects available."),wo(h,"No projects available."),wr("No projects available."),fo(e,null),fo(t,null),jo(),void Po("No projects available.");So(M,"Choose a project",Ht,"projectId","title"),Lo();const r=go(e),o=Ht.find(e=>e.projectId===r);o&&M?(M.value=String(o.projectId),h&&(h.value=String(o.projectId)),fo(e,o.projectId),await cc(o.projectId,go(t))):(fo(e,null),fo(t,null),jo(),Po("Select a Project and Book to begin."))}catch{Ht=[],Bt=[],wo(M,"Unable to connect to PlotDirector."),wo(O,"Select a project first"),wo(h,"Unable to connect to PlotDirector."),wo(m,"Select a project first"),fr("Unable to connect to PlotDirector."),wr("Unable to connect to PlotDirector."),fo(e,null),fo(t,null),jo(),Po("Unable to connect to PlotDirector.")}})():Promise.resolve();if(Ot||(wo(M,"Please sign in to PlotDirector."),wo(O,"Please sign in to PlotDirector."),wo(h,"Please sign in to PlotDirector."),wo(m,"Please sign in to PlotDirector."),jo()),!window.Office||"function"!=typeof window.Office.onReady)return mr("Word Companion ready"),Ir("Word document access is unavailable."),jr("Manual"),void ho({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});yo().then(async()=>{mr("Word Companion ready"),await ic,await(async()=>{if(!Ot||!Ft)return void Eo(!1);const n=Ao();if(n)try{const r=await Ca(`/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 pn=n,Hr(r),fo(e,r.projectId),fo(t,r.bookId),M&&(M.value=String(r.projectId)),await cc(r.projectId,r.bookId),Eo(!1),fr("Connected"),Sr("Bound manuscript detected."),void await Na()}catch{}pn=null,Br(),Lo(),ko()?await cc(ko().projectId,null):wo(m,"Select a project first"),Po("Select a Project and Book to begin."),Eo(!0)})(),Ft?(()=>{if(Ot){if(!window.Office?.context?.document||"function"!=typeof window.Office.context.document.addHandlerAsync||!window.Office?.EventType?.DocumentSelectionChanged)return jr("Manual"),void Ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,oc,e=>{e?.status===window.Office.AsyncResultStatus.Succeeded?(Rn=!0,jr("Live")):(jr("Manual"),Ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))}),window.addEventListener("beforeunload",ac)}catch(e){console.warn("Unable to register Word selection tracking handler.",e),jr("Manual"),Ir("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}})():(Ir("Word document access is unavailable."),jr("Manual"))}).catch(e=>{console.error("Office readiness check failed.",e),fr("Unable to connect to PlotDirector."),mr("Word Companion unavailable"),Ir("Word document access is unavailable."),ho({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","links","structure","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-first-run-wizard]"),l=document.querySelector("[data-first-run-project-select]"),u=document.querySelector("[data-first-run-book-select]"),p=document.querySelector("[data-first-run-new-book-title]"),h=document.querySelector("[data-first-run-create-book]"),m=document.querySelector("[data-first-run-scan]"),y=document.querySelector("[data-first-run-cancel]"),g=document.querySelector("[data-first-run-status]"),f=document.querySelector("[data-first-run-summary]"),w=document.querySelector("[data-first-run-character-section]"),I=document.querySelector("[data-first-run-character-status]"),S=document.querySelector("[data-first-run-character-candidates]"),b=document.querySelector("[data-first-run-character-actions]"),C=document.querySelector("[data-first-run-create-characters]"),k=document.querySelector("[data-first-run-skip-characters]"),v=document.querySelector("[data-first-run-continue]"),x=document.querySelector("[data-first-run-import-actions]"),N=document.querySelector("[data-first-run-import]"),E=document.querySelector("[data-first-run-import-cancel]"),L=document.querySelector("[data-first-run-replace-dialog]"),P=document.querySelector("[data-first-run-replace-confirm]"),q=document.querySelector("[data-first-run-replace-cancel]"),D=document.querySelector("[data-office-status]"),A=document.querySelector("[data-connection-status]"),$=document.querySelector("[data-summary-connection]"),T=document.querySelector("[data-summary-project]"),j=document.querySelector("[data-summary-book]"),W=document.querySelector("[data-project-select]"),R=document.querySelector("[data-book-select]"),U=document.querySelector("[data-project-message]"),M=document.querySelector("[data-book-message]"),O=document.querySelector("[data-refresh-current-scene]"),B=document.querySelector("[data-refresh-document]"),H=document.querySelector("[data-current-chapter]"),G=document.querySelector("[data-current-scene]"),F=document.querySelector("[data-current-word-count]"),V=document.querySelector("[data-scene-tracking-status]"),Y=document.querySelector("[data-document-message]"),J=document.querySelector("[data-sync-note]"),_=document.querySelector("[data-document-outline]"),z=document.querySelector("[data-analyse-manuscript-structure]"),K=document.querySelector("[data-apply-structure-sync]"),Q=document.querySelector("[data-structure-preview-status]"),X=document.querySelector("[data-structure-preview-results]"),Z=document.querySelector("[data-refresh-plotdirector-scene]"),ee=document.querySelector("[data-plotdirector-scene-status]"),te=document.querySelector("[data-anchor-status]"),ne=document.querySelector("[data-anchor-book-id]"),re=document.querySelector("[data-anchor-chapter-id]"),oe=document.querySelector("[data-anchor-scene-id]"),ae=document.querySelector("[data-attach-plotdirector-ids]"),ce=document.querySelector("[data-unlink-word-document]"),ie=document.querySelector("[data-plotdirector-scene-details]"),se=document.querySelector("[data-plotdirector-scene-title]"),de=document.querySelector("[data-plotdirector-revision-status]"),le=document.querySelector("[data-plotdirector-estimated-words]"),ue=document.querySelector("[data-plotdirector-actual-words]"),pe=document.querySelector("[data-plotdirector-blocked-status]"),he=document.querySelector("[data-plotdirector-blocked-reason-row]"),me=document.querySelector("[data-plotdirector-blocked-reason]"),ye=document.querySelector("[data-runtime-last-sync]"),ge=document.querySelector("[data-sync-scene-progress]"),fe=document.querySelector("[data-sync-word-count]"),we=document.querySelector("[data-sync-plotdirector-count]"),Ie=document.querySelector("[data-sync-last-synced]"),Se=document.querySelector("[data-sync-status]"),be=document.querySelector("[data-writing-brief-block]"),Ce=document.querySelector("[data-writing-brief]"),ke=document.querySelector("[data-plotdirector-link-groups]"),ve=document.querySelector("[data-character-chips]"),xe=document.querySelector("[data-asset-chips]"),Ne=(document.querySelector("[data-location-chips]"),document.querySelector("[data-primary-location-select]")),Ee=document.querySelector("[data-save-scene-links]"),Le=document.querySelector("[data-scene-links-status]"),Pe=document.querySelector("[data-links-editing-scene]"),qe=document.querySelector("[data-chapter-create-link]"),De=document.querySelector("[data-chapter-create-link-chapter]"),Ae=document.querySelector("[data-create-plotdirector-chapter]"),$e=document.querySelector("[data-link-existing-chapter]"),Te=document.querySelector("[data-chapter-create-link-status]"),je=document.querySelector("[data-scene-create-link]"),We=document.querySelector("[data-create-link-chapter]"),Re=document.querySelector("[data-create-link-scene]"),Ue=document.querySelector("[data-create-plotdirector-scene]"),Me=document.querySelector("[data-link-existing-scene]"),Oe=document.querySelector("[data-create-link-status]"),Be=document.querySelector("[data-link-existing-dialog]"),He=document.querySelector("[data-link-scene-search]"),Ge=document.querySelector("[data-link-scene-options]"),Fe=document.querySelector("[data-link-selected-scene]"),Ve=document.querySelector("[data-link-dialog-cancel]"),Ye=document.querySelector("[data-link-dialog-status]"),Je=document.querySelector("[data-create-scene-dialog]"),_e=document.querySelector("[data-create-dialog-scene]"),ze=document.querySelector("[data-create-dialog-chapter]"),Ke=document.querySelector("[data-create-dialog-confirm]"),Qe=document.querySelector("[data-create-dialog-cancel]"),Xe=document.querySelector("[data-link-existing-chapter-dialog]"),Ze=document.querySelector("[data-link-chapter-search]"),et=document.querySelector("[data-link-chapter-options]"),tt=document.querySelector("[data-link-selected-chapter]"),nt=document.querySelector("[data-link-chapter-dialog-cancel]"),rt=document.querySelector("[data-link-chapter-dialog-status]"),ot=document.querySelector("[data-create-chapter-dialog]"),at=document.querySelector("[data-create-chapter-dialog-chapter]"),ct=document.querySelector("[data-create-chapter-dialog-book]"),it=document.querySelector("[data-create-chapter-dialog-confirm]"),st=document.querySelector("[data-create-chapter-dialog-cancel]"),dt=document.querySelector("[data-apply-structure-sync-dialog]"),lt=document.querySelector("[data-apply-structure-sync-summary]"),ut=document.querySelector("[data-apply-structure-sync-confirm]"),pt=document.querySelector("[data-apply-structure-sync-cancel]"),ht=document.querySelector("[data-resolve-project-id]"),mt=document.querySelector("[data-resolve-project-title]"),yt=document.querySelector("[data-resolve-book-id]"),gt=document.querySelector("[data-resolve-book-title]"),ft=document.querySelector("[data-resolve-detected-chapter]"),wt=document.querySelector("[data-resolve-detected-scene]"),It=document.querySelector("[data-resolve-request-chapter]"),St=document.querySelector("[data-resolve-request-scene]"),bt=document.querySelector("[data-resolve-result]"),Ct=document.querySelector("[data-resolve-chapter-id]"),kt=document.querySelector("[data-resolve-scene-id]"),vt=document.querySelector("[data-run-diagnostics]"),xt=document.querySelector("[data-diagnostic-host]"),Nt=document.querySelector("[data-diagnostic-platform]"),Et=document.querySelector("[data-diagnostic-ready]"),Lt=document.querySelector("[data-diagnostic-word-api]"),Pt=document.querySelector("[data-diagnostic-last-scan]"),qt=document.querySelector("[data-diagnostic-last-error]"),Dt=document.querySelector("[data-diagnostic-anchor-type]"),At=document.querySelector("[data-diagnostic-stored-scene-id]"),$t=document.querySelector("[data-diagnostic-stored-chapter-id]"),Tt=document.querySelector("[data-diagnostic-resolution-method]"),jt=document.querySelector("[data-diagnostic-paragraphs]"),Wt=document.querySelector("[data-diagnostic-heading1]"),Rt=document.querySelector("[data-diagnostic-heading2]"),Ut="true"===a?.dataset.authenticated;let Mt=[],Ot=[],Bt=!1,Ht=!1,Gt="Unknown",Ft="Unknown",Vt="",Yt="",Jt=null,_t=null,zt=null,Kt=null,Qt=null,Xt=null,Zt="",en="Title Match",tn=!1,nn=[],rn=null,on=null,an=[],cn=null,sn=null,dn=null,ln=null,un=null,pn=null,hn=null,mn=null,yn=null,gn=null,fn=[],wn=!1,In=!1,Sn=0,bn=!1,Cn=!1,kn=!1,vn=null,xn="Manual",Nn=!1,En=null,Ln=!1,Pn=0,qn=!1,Dn=0,An=null;const $n=1200;let Tn=!1,jn=!1,Wn=null,Rn=!1,Un=!1,Mn=null,On=null,Bn=null,Hn=!1,Gn=!1,Fn=null,Vn="",Yn=[],Jn=null,_n="",zn=null,Kn="",Qn=[],Xn=null,Zn="",er=null,tr="",nr=[],rr=null,or="",ar="",cr="",ir="",sr=0,dr={characters:[],assets:[],locations:[],primaryLocationId:null};const lr=e=>{const t=Date.now();t-sr<1e3||(sr=t,console.debug(`[Word Companion Runtime] ${e}`))},ur=e=>{console.debug(`[Word Companion Timing] ${e}`)},pr=e=>{D&&(D.textContent=e)},hr=(e,t=!0)=>{const r=o.has(e)&&i.some(t=>t.dataset.tabButton===e)?e:"scene";for(const e of i){const t=e.dataset.tabButton===r;e.classList.toggle("is-active",t),e.setAttribute("aria-selected",t?"true":"false")}for(const e of s){const t=e.dataset.tabPanel===r;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,r)},mr=()=>{const e=(e=>{try{return window.localStorage.getItem(e)||""}catch{return""}})(n);hr(o.has(e)?e:"scene",!1)},yr=e=>{A&&(A.textContent=e),$&&($.textContent=e)},gr=e=>{U&&(U.textContent=e)},fr=e=>{M&&(M.textContent=e)},wr=e=>{Y&&(Y.textContent=e)},Ir=e=>{ee&&(ee.textContent=e)},Sr=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("anchorType")&&uo(Dt,Ur(e.anchorType)),t("storedSceneId")&&uo(At,Ur(e.storedSceneId)),t("storedChapterId")&&uo($t,Ur(e.storedChapterId)),t("resolutionMethod")&&uo(Tt,Ur(e.resolutionMethod))},br=()=>{const e=bo(),t=Number.isInteger(Qt)&&Qt>0&&Kt===Qt,n=!Number.isInteger(Xt)||Xt<=0||zt===Xt,r=t&&n;uo(te,r?"Attached to PlotDirector":"Not attached"),uo(ne,e?.bookId?String(e.bookId):"-"),uo(re,Number.isInteger(Xt)&&Xt>0?String(Xt):"-"),uo(oe,Number.isInteger(Qt)&&Qt>0?String(Qt):"-"),ae&&(ae.disabled=!Qt||r&&!tn,ae.textContent=Kt&&!r?"Reattach PlotDirector IDs":"Attach PlotDirector IDs"),Sr({anchorType:en||"Title Match",storedSceneId:Kt,storedChapterId:zt,resolutionMethod:Zt})},Cr=(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=Vt===c&&Yt===i&&Jt===s&&_t===d&&zt===l&&Kt===u;Vt=e||"",Yt=t||"",Jt=Number.isInteger(n)?n:null,_t=Number.isInteger(a)&&a>0?a:null,zt=Number.isInteger(r)&&r>0?r:null,Kt=Number.isInteger(o)&&o>0?o:null,p||(H&&(H.textContent=e||"Not detected"),G&&(G.textContent=t||"Not detected"),F&&(F.textContent=Number.isInteger(n)?String(n):"-"),uo(fe,Number.isInteger(n)?String(n):"-"),br())},kr=()=>{Wn&&(window.clearTimeout(Wn),Wn=null)},vr=(e,t)=>{e&&(e.hidden=t)},xr=()=>{vr(ce,!ln)},Nr=e=>{uo(Se,e)},Er=e=>{uo(Q,e)},Lr=(e="Select a project and book to analyse manuscript structure.")=>{if(dn=null,X){X.innerHTML="";const e=document.createElement("p");e.textContent="No preview generated.",X.append(e)}Er(e),qr()},Pr=(e=dn)=>((e=dn)=>Ko.flatMap(t=>Array.isArray(e?.[t.key])?e[t.key]:[]))(e).filter(e=>"couldLink"===e.category||"wouldCreateChapters"===e.category||"wouldCreateScenes"===e.category),qr=()=>{K&&(K.disabled=kn||0===Pr().length)},Dr=()=>{z&&(z.disabled=kn||!So()||!bo()),qr()},Ar=()=>{Pe&&(Pe.textContent=Qt?`Editing links for: ${cr||Yt||"Current scene"}`:"Link a PlotDirector scene first.")},$r=()=>{const e=Nn||!Qt,t=e||!Xt||Rn;ge&&(ge.disabled=t),Ee&&(Ee.disabled=e),Ne&&(Ne.disabled=e);for(const t of[ve,xe])for(const n of t?[...t.querySelectorAll("input[type='checkbox']")]:[])n.disabled=e},Tr=e=>{"Live"!==e&&"Manual"!==e||(xn=e),uo(V,e||xn||"Manual")},jr=(e,t="")=>{Nn=!!e,Nn&&(kr(),Fa()),uo(V,Nn?"Stale":xn),$r(),t&&(wr(t),Gr(t))},Wr=(e,t=null,n="")=>{Qt=Number.isInteger(e)&&e>0?e:null,Xt=Number.isInteger(t)&&t>0?t:null,Zt=n||"",Qt!==Mn&&(On=null),Qt||(kr(),Fa()),$r(),Nr(Nn?"Refresh Current Scene before syncing.":Qt?"Ready to sync.":"No resolved PlotDirector scene."),Gr(Nn?"Refresh Current Scene before saving.":Qt?"Ready to save.":"Link a PlotDirector scene first."),Ar(),br()},Rr=e=>{O&&(O.disabled=e,O.textContent=e?"Refreshing...":"Refresh Current Scene")},Ur=e=>null==e||""===e?"-":String(e),Mr=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"})}`},Or=e=>{un=e||null;const t=un?.lastSyncUtc||un?.manuscriptDocument?.lastSyncUtc;uo(ye,Mr(t)),uo(Ie,Mr(t))},Br=()=>{pn=null,hn=null,mn=null,Dn+=1,An=null,Va(),Ya(),Ja(),Or(null)},Hr=()=>{hn=null,mn=null},Gr=e=>{uo(Le,e)},Fr=e=>{uo(Oe,e)},Vr=e=>{uo(Te,e)},Yr=()=>!!bo()&&!!Vt&&!Xt,Jr=()=>!!bo()&&!!Yt&&Number.isInteger(Xt)&&Xt>0,_r=()=>{vr(qe,!0),Vr(""),Ae&&(Ae.disabled=!0,Ae.textContent="Create Chapter in PlotDirector"),$e&&($e.disabled=!0,$e.textContent="Link to Existing Chapter")},zr=(e="")=>{uo(De,Ur(Vt)),vr(qe,!1),Vr(e);const t=Yr();Ae&&(Ae.disabled=!t,Ae.textContent="Create Chapter in PlotDirector"),$e&&($e.disabled=!t,$e.textContent="Link to Existing Chapter")},Kr=()=>{vr(je,!0),Fr(""),Ue&&(Ue.disabled=!0,Ue.textContent="Create Scene in PlotDirector"),Me&&(Me.disabled=!0,Me.textContent="Link to Existing Scene")},Qr=(e="")=>{uo(We,Ur(Vt)),uo(Re,Ur(Yt)),vr(je,!1),Fr(e);const t=Jr();Ue&&(Ue.disabled=!t,Ue.textContent="Create Scene in PlotDirector"),Me&&(Me.disabled=!t,Me.textContent="Link to Existing Scene")},Xr=e=>{Ir(e),vr(ie,!0),vr(be,!0),vr(ke,!1),_r(),Kr(),Zt="",cr="",ir="",en=Kt?"SceneID Anchor":zt?"ChapterID Anchor":"Title Match",tn=!1,dr={characters:[],assets:[],locations:[],primaryLocationId:null},eo(ve,[],"character"),eo(xe,[],"asset"),to([],null,!1),Wr(null),uo(we,"-"),uo(se,"-"),uo(de,"-"),uo(le,"-"),uo(ue,"-"),uo(pe,"-"),uo(me,"-"),vr(he,!0),br(),Ar()},Zr=(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,eo=(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(Zr(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)}},to=(e,t,n=!1)=>{if(!Ne)return;Ne.innerHTML="";const r=document.createElement("option");r.value="",r.textContent="None",Ne.append(r);const o=Number.parseInt(t||"",10);for(const t of Array.isArray(e)?e:[]){const e=Number.parseInt(Zr(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,Ne.append(n)}Ne.disabled=!n},no=e=>String(e||"").trim().replace(/\s+/g," "),ro=(e,t)=>{const n=no(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 no(n.replace(r,""))||n},oo=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("projectId")&&uo(ht,Ur(e.projectId)),t("projectTitle")&&uo(mt,Ur(e.projectTitle)),t("bookId")&&uo(yt,Ur(e.bookId)),t("bookTitle")&&uo(gt,Ur(e.bookTitle)),t("detectedChapter")&&uo(ft,Ur(e.detectedChapter)),t("detectedScene")&&uo(wt,Ur(e.detectedScene)),t("requestChapter")&&uo(It,Ur(e.requestChapter)),t("requestScene")&&uo(St,Ur(e.requestScene)),t("result")&&uo(bt,Ur(e.result)),t("chapterId")&&uo(Ct,Ur(e.chapterId)),t("sceneId")&&uo(kt,Ur(e.sceneId))},ao=async e=>{if(mn===e&&Array.isArray(hn?.chapters))return hn.chapters;const t=await Ca(`/api/word-companion/books/${e}/structure`);return mn=e,hn=t||null,Array.isArray(t?.chapters)?t.chapters:[]},co=async e=>{const t=await Ca(`/api/word-companion/books/${e}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},io=e=>{if(Number.isInteger(Xt)&&Xt>0){const t=e.find(e=>e.chapterId===Xt);if(t)return t}const t=ro(Vt,"chapter").toLocaleLowerCase();return t&&e.find(e=>ro(e.title,"chapter").toLocaleLowerCase()===t)||null},so=async()=>{const e=bo();return e?io(await ao(e.bookId)):null},lo=async(e,t,n,r,o)=>{const a=await Ca(`/api/word-companion/scenes/${t}/companion`);try{a.revisionStatus=await(async(e,t)=>{const n=await Ca(`/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;en=o||"Title Match",tn=!1,jr(!1),Ir("Linked to PlotDirector"),wr(""),_r(),Kr(),Wr(t,n,r),c=a,cr=c?.sceneTitle||Yt||"",ir=c?.chapterTitle||Vt||"",uo(se,Ur(c?.sceneTitle)),uo(de,Ur(c?.revisionStatus||c?.revisionStatusName||"Not provided")),uo(le,Ur(c?.estimatedWords)),uo(ue,Ur(c?.actualWords)),uo(we,Ur(c?.actualWords)),uo(pe,c?.blocked?"Blocked":"Not blocked"),c?.blockedReason?(uo(me,c.blockedReason),vr(he,!1)):(uo(me,"-"),vr(he,!0)),Ce&&(Ce.textContent=c?.writingBrief||"No writing brief has been added for this scene."),dr={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},eo(ve,dr.characters,"character",!!Qt&&!Nn),eo(xe,dr.assets,"asset",!!Qt&&!Nn),to(dr.locations,dr.primaryLocationId,!!Qt&&!Nn),Ar(),Gr(Nn?"Refresh Current Scene before saving.":Qt?"Ready to save.":"No resolved PlotDirector scene."),vr(ie,!1),vr(be,!1),vr(ke,!1),xa(t,n),Ga(),ec()},uo=(e,t)=>{if(e){const n=null==t?"":String(t);e.textContent!==n&&(e.textContent=n)}},po=e=>{const t=t=>Object.prototype.hasOwnProperty.call(e,t);t("host")&&uo(xt,e.host),t("platform")&&uo(Nt,e.platform),t("ready")&&uo(Et,e.ready),t("wordApi")&&uo(Lt,e.wordApi),t("lastScan")&&uo(Pt,e.lastScan),t("lastError")&&uo(qt,e.lastError),t("paragraphs")&&uo(jt,e.paragraphs),t("heading1")&&uo(Wt,e.heading1),t("heading2")&&uo(Rt,e.heading2)},ho=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)},mo=async()=>{if(!window.Office||"function"!=typeof window.Office.onReady)return Bt=!1,Ht=!1,Gt="Unavailable",Ft="Unavailable",po({host:Gt,platform:Ft,ready:"No",wordApi:"No"}),null;const e=await window.Office.onReady();return Bt=!0,Gt=e?.host||"Unknown",Ft=e?.platform||"Unknown",Ht=!!window.Word&&!!window.Office.HostType&&e?.host===window.Office.HostType.Word,po({host:Gt,platform:Ft,ready:"Yes",wordApi:Ht?"Yes":"No"}),e},yo=e=>{try{const t=window.localStorage.getItem(e),n=Number.parseInt(t||"",10);return Number.isInteger(n)&&n>0?n:null}catch{return null}},go=(e,t)=>{try{t?window.localStorage.setItem(e,String(t)):window.localStorage.removeItem(e)}catch{}},fo=(e,t)=>{if(!e)return;e.innerHTML="";const n=document.createElement("option");n.value="",n.textContent=t,e.append(n),e.disabled=!0},wo=(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},Io=e=>{const t=String(e?.title||"").trim(),n=String(e?.subtitle||"").trim();return n?`${t}: ${n}`:t},So=()=>{const e=Number.parseInt(W?.value||"",10);return Mt.find(t=>t.projectId===e)||null},bo=()=>{const e=Number.parseInt(R?.value||"",10);return Ot.find(t=>t.bookId===e)||null},Co=()=>{const e=Number.parseInt(l?.value||"",10);return Mt.find(t=>t.projectId===e)||null},ko=()=>{const e=Number.parseInt(u?.value||"",10);return Ot.find(t=>t.bookId===e)||null},vo=e=>uo(g,e),xo=()=>{const e=Co(),t=ko(),n=In&&Date.now()-Sn>=750;m&&(m.disabled=!e||!t||bn),h&&(h.disabled=!e||!String(p?.value||"").trim()||bn),N&&(N.disabled=!yn?.canImport||!gn||bn),C&&(C.disabled=!n||Cn||0===Po().length)},No=e=>{vr(d,!e),vr(c,e),xr();for(const t of s)vr(t,!!e||"scene"!==t.dataset.tabPanel&&!t.classList.contains("is-active"));e||mr()},Eo=()=>{if(!l)return;if(0===Mt.length)return void fo(l,"No projects available.");wo(l,"Choose a project",Mt,"projectId","title");const e=Number.parseInt(W?.value||"",10);Number.isInteger(e)&&e>0&&(l.value=String(e))},Lo=(e="Select a Project and Book to begin.")=>{yn=null,gn=null,fn=[],wn=!1,In=!1,Sn=0,vr(f,!0),vr(x,!0),vr(w,!0),vr(b,!0),f&&(f.innerHTML=""),S&&(S.innerHTML=""),uo(I,""),vo(e),xo()},Po=()=>S?[...S.querySelectorAll("input[type='checkbox']:checked")].map(e=>String(e.value||"").trim()).filter(Boolean):[],qo=e=>{if(fn=Array.isArray(e)?e:[],w&&S){if(S.innerHTML="",vr(w,!1),vr(b,!wn||0===fn.length),vr(C,!1),vr(k,!1),vr(v,!0),0===fn.length)return uo(I,"No likely major characters found."),void xo();uo(I,`${fn.length} likely major characters found.`);for(const e of fn){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",xo);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),S.append(t)}xo()}},Do=()=>{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}},Ao=()=>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."))}),$o=()=>ln?.documentGuid?ln.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)),To=()=>ln?.documentGuid||Do()?.documentGuid||"",jo=()=>{const e=So(),t=bo();T&&(T.textContent=e?.title||"(Not connected)"),j&&(j.textContent=t?Io(t):"(Not connected)"),J&&(J.textContent=t?"":"Select a PlotDirector book before refreshing."),Dr()},Wo=e=>String(e?.styleBuiltIn||e?.style||"").replace(/\s+/g,"").toLowerCase(),Ro=(e,t)=>{const n=Wo(e);return n===`heading${t}`||n.endsWith(`.heading${t}`)||n.includes(`heading${t}`)},Uo=e=>String(e||"").trim().split(/\s+/).filter(Boolean).length,Mo=(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},Oo=e=>{try{return Array.isArray(e?.contentControls?.items)?e.contentControls.items:[]}catch(e){return console.warn("Word paragraph content controls were not available.",e),[]}},Bo=(e,t)=>{const n=Oo(e);for(const e of n){const n=Mo(e.tag,t);if(n)return n}return null},Ho=(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(Ro(e,1))return r+=1,a={index:n.length+1,paragraphIndex:t,title:i,anchorId:Bo(e,"PD-CHAPTER"),scenes:[]},n.push(a),void(c=null);if(Ro(e,2)){if(o+=1,!a)return;return c={index:a.scenes.length+1,paragraphIndex:t,title:i,anchorId:Bo(e,"PD-SCENE"),wordCount:0},void a.scenes.push(c)}c&&(c.wordCount+=Uo(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()&&Wo(t)===Wo(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}},Go=new Set(["***","###"]),Fo=(e,t)=>{const n=String(e?.text||"").trim();return{index:t,text:n,styleBuiltIn:e?.styleBuiltIn||"",style:e?.style||"",wordCount:Uo(n),chapterAnchorId:null,sceneAnchorId:null}},Vo=(e,t)=>{e&&(e.endParagraphIndex=t)},Yo=(e,t)=>{e&&(e.endParagraphIndex=t,Vo(e.scenes.at(-1),t))},Jo=(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()&&Wo(e)===Wo(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(!pn)return!1;const t=((e,t)=>!e||!Number.isInteger(t)||t<0?null:e.chapters.filter(e=>e.startParagraphIndex<=t).at(-1)||null)(pn,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!==pn.currentChapter?.startParagraphIndex||n?.startParagraphIndex!==pn.currentScene?.startParagraphIndex||t?.anchorId!==pn.currentChapter?.anchorId||n?.anchorId!==pn.currentScene?.anchorId;return pn.currentParagraphIndex=e,pn.currentChapter=t,pn.currentScene=n,!!r&&(Cr(t?.title,n?.title,n?.wordCount,t?.anchorId,n?.anchorId,t?.index),r)},zo=e=>{if(!_)return;if(_.innerHTML="",0===e.chapters.length){const e=document.createElement("p");return e.textContent="No chapters detected. Use Heading 1 for chapter titles.",void _.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.",_.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)}_.append(e)}},Ko=[{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"}],Qo={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},Xo={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},Zo=(e,t)=>ro(e,t).toLocaleLowerCase(),ea=({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:""}),ta=(e,t)=>{Array.isArray(e[t.category])&&e[t.category].push(t)},na=e=>Array.isArray(e?.scenes)?e.scenes:[],ra=(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=ea({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:e.title,match:`Chapter ${o.chapterId}: ${o.title}`,anchorStatus:r,pdChapter:o,wordChapter:e});return ta(n,t),t}const a=ea({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:e.title,anchorStatus:`${r} not found`,matches:[],pdChapter:null,wordChapter:e});return ta(n,a),a}const o=t.filter(t=>Zo(t.title,"chapter")===Zo(e.title,"chapter"));if(1===o.length){const t=ea({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 ta(n,t),t}if(o.length>1){const t=ea({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 ta(n,t),t}const a=ea({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:e.title,anchorStatus:r,pdChapter:null,wordChapter:e});return ta(n,a),a},oa=(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=na(n).find(e=>e.sceneId===t);if(e)return{chapter:n,scene:e}}return null})(n,e.anchorId);return a?void ta(r,ea({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 ta(r,ea({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 ta(r,ea({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 ta(r,ea({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,wordChapter:t?.wordChapter,wordScene:e,parentItem:t}));const a=na(t.pdChapter).filter(t=>Zo(t.title,"scene")===Zo(e.title,"scene"));1!==a.length?a.length>1?ta(r,ea({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})):ta(r,ea({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:e.title,anchorStatus:o,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:e,parentItem:t})):ta(r,ea({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}))},aa=e=>{const t=document.createElement("article");t.className="word-companion-preview-item";const n=document.createElement("strong");n.textContent=`${Xo[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: ${Qo[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},ca=e=>{if(X){X.innerHTML="";for(const t of Ko){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(aa(e));X.append(n)}qr()}},ia=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)(Ro(e,1)||Ro(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=Ho(t.items,n.items);return r.bodyParagraphs=t.items,r},sa=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(Fo),r=[];let o=0,a=0,c=null,i=null,s=0;const d=(e,t=null,n=null)=>c?(Vo(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&&(Ro(e,1)?(Yo(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&&Go.has(e.text)?(a+=1,d(e)):(c.wordCount+=e.wordCount,i&&(i.wordCount+=e.wordCount),s+=e.wordCount)));return Yo(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=Jo(o,r.items);return pn=o,_o(a),lr("Cache rebuilt."),o},da=()=>window.performance&&"function"==typeof window.performance.now?window.performance.now():Date.now(),la=e=>!!e&&!e.stale&&e.generation===Dn&&e.documentGuid===To()&&e.sceneId===Qt,ua=async(e={})=>{const t=!!e.includeSelection,n=!1!==e.updateDisplay,r=Dn,o=da(),a=So(),c=bo(),i=pn?.currentScene;if(!i||!Number.isInteger(i.startParagraphIndex)||!Number.isInteger(i.endParagraphIndex))return null;if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return null;const s=da(),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(da()-s);if(r!==Dn)return ur(`Office snapshot: ${l}ms stale`),{stale:!0,generation:r};let u=!1;if(t){const e=Jo(pn,d.selectionParagraphs);u=_o(e)}const p=pn?.currentScene;if(!p||!Number.isInteger(p.startParagraphIndex)||!Number.isInteger(p.endParagraphIndex))return null;const h=[];let m=0;const y=Math.min(p.endParagraphIndex,d.bodyTexts.length-1),g=pn.currentChapter?.startParagraphIndex;for(let e=p.startParagraphIndex;e<=y;e+=1){const t=String(d.bodyTexts[e]||"").trim();t&&!Go.has(t)&&e!==g&&(h.push(t),m+=Uo(t))}p.wordCount=m,n&&Cr(pn.currentChapter?.title,p.title,m,pn.currentChapter?.anchorId,p.anchorId,pn.currentChapter?.index);const f={documentGuid:To(),projectId:a?.projectId||null,bookId:c?.bookId||null,chapterId:Xt,sceneId:Qt,chapterTitle:pn.currentChapter?.title||"",sceneTitle:p.title||"",sceneText:h.join("\n"),wordCount:m,selectionSignature:`${pn.currentParagraphIndex??-1}:${p.startParagraphIndex}:${p.endParagraphIndex}`,selectionChanged:u,generation:r};return An=f,ur(`Office snapshot: ${l}ms; scene words: ${m}; total snapshot: ${Math.round(da()-o)}ms`),f},pa=async()=>la(An)?An:await ua(),ha=async()=>{if(wr(""),!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return Cr(null,null,null),wr("Word document access is unavailable."),po({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;B&&(B.disabled=!0,B.textContent="Scanning..."),wr("Scanning document structure...");try{const e=await window.Word.run(async e=>{const t=bo();return t?await sa(e,!!t.usesExplicitScenes):(pn=null,await ia(e))});return pn||Cr(e.currentChapter?.title,e.currentScene?.title,e.currentScene?.wordCount,e.currentChapter?.anchorId,e.currentScene?.anchorId,e.currentChapter?.index),Xr("Not detected"),zo(e),wr(""),po({lastScan:"Success",lastError:"-",paragraphs:String(e.paragraphCount),heading1:String(e.heading1Count),heading2:String(e.heading2Count)}),!0}catch(e){const t=ho(e);return console.error("Unable to scan the Word document.",e),Cr(null,null,null),wr(`Unable to scan the Word document: ${t}`),po({lastScan:"Failure",lastError:t}),!1}finally{B&&(B.disabled=!1,B.textContent="Refresh Document Structure")}},ma=async()=>{const e=bo();if(!So()||!e)return Er("Select a project and book to analyse manuscript structure."),!1;if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return Er("Word document access is unavailable."),po({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;z&&(z.disabled=!0,z.textContent="Analysing..."),Er("Analysing manuscript structure...");try{const t=await window.Word.run(async e=>await ia(e)),n=await Ca(`/api/word-companion/books/${e.bookId}/structure`);return Cr(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),zo(t),dn=((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=ra(t,r,n);for(const o of na(t))oa(o,e,r,n)}return n})(t,n),ca(dn),Er("Preview generated. No changes have been applied."),po({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),Er("Unable to analyse manuscript structure."),po({lastScan:"Failure",lastError:ho(e)}),!1}finally{z&&(z.textContent="Analyse Manuscript Structure",Dr())}},ya=e=>{vn&&(vn(e),vn=null),dt?.close?dt.close():dt&&(dt.hidden=!0)},ga=()=>{const e=((e=dn)=>{const t=Pr(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(!lt)return;lt.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)}lt.append(n)})(e),dt?new Promise(e=>{vn=e,dt.showModal?dt.showModal():dt.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.`))},fa=(e,t,n="")=>{e.result=t,e.error=n},wa=e=>Number.isInteger(e?.wordChapter?.index)&&e.wordChapter.index>0?10*e.wordChapter.index:null,Ia=e=>Number.isInteger(e?.wordScene?.index)&&e.wordScene.index>0?10*e.wordScene.index:null,Sa=async(e,t)=>{const n=await ka(`/api/word-companion/books/${e}/chapters`,{title:no(t.wordTitle),sortOrder:wa(t)});if(!n?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");Hr(),t.pdChapter={chapterId:n.chapterId,title:n.title||t.wordTitle,sortOrder:n.sortOrder||wa(t)||0,scenes:[]},t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},ba=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 ka(`/api/word-companion/books/${e}/chapters/${n.chapterId}/scenes`,{sceneTitle:no(t.wordTitle),sortOrder:Ia(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");Hr(),t.pdChapter=n,t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:Ia(t)||0},t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},Ca=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()},ka=(e,t)=>Ca(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),va=async(e="")=>{In=!1,Sn=0,fn=[],S&&(S.innerHTML=""),vr(w,!0),No(!1),vo(""),vr(b,!0),e&&wr(e);const t=await Na();e&&t&&Vt&&wr(e)},xa=async(e=Qt,t=Xt)=>{const n=So(),r=bo(),o=To(),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(ar!==i){ar=i;try{await ka("/api/word-companion/runtime/current-scene",{documentGuid:o,projectId:n.projectId,bookId:r.bookId,chapterId:c,sceneId:a}),lr("Current scene follow event sent.")}catch(e){ar="",console.debug("Unable to notify PlotDirector of current scene.",e)}}},Na=async()=>{const e=bo();if(!(e&&Bt&&Ht&&window.Word&&"function"==typeof window.Word.run))return!1;wr("Reading manuscript position...");try{Hr(),await Promise.all([_a(!0),za(!0),Ka(!0)]),await ao(e.bookId);const t=await window.Word.run(async t=>await sa(t,!!e.usesExplicitScenes));return zo(t),po({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),Vt?(Yt?await nc():await tc(),jr(!1),Tr("Live"),wr(""),!0):(Xr("Not detected"),jr(!1),Tr("Live"),wr("Manuscript linked. Click inside a chapter to show the current scene."),!0)}catch(e){return console.error("Unable to initialise bound manuscript runtime.",e),pn=null,Tr("Manual"),wr(`Unable to read manuscript position: ${ho(e)}`),po({lastScan:"Failure",lastError:ho(e)}),!1}},Ea=async e=>{ln=null,Br(),Xr("Not detected"),Tr("Manual"),yr("Connected"),Eo(),Co()?await ic(Co().projectId,null):fo(u,"Select a project first"),Lo(e||"Select a Project and Book to begin."),No(!0),xr()},La=e=>e?[...e.querySelectorAll("input[type='checkbox']:checked")].map(e=>Number.parseInt(e.value||"",10)).filter(e=>Number.isInteger(e)&&e>0):[],Pa=()=>{const e=Number.parseInt(Ne?.value||"",10);return Number.isInteger(e)&&e>0?e:null},qa=(e,t,n,r)=>{const o=((e,t)=>Oo(e).find(e=>Mo(e.tag,t))||null)(e,r),a=o||e.getRange().insertContentControl();return a.title=t,a.tag=n,a.appearance="Hidden",a},Da=async(e="PlotDirector IDs attached successfully.")=>{if(!Qt||!Xt)return wr("No resolved PlotDirector scene."),!1;if((Kt&&Kt!==Qt||zt&&zt!==Xt)&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return wr("Word document access is unavailable."),!1;ae&&(ae.disabled=!0,ae.textContent="Attaching...");try{return await window.Word.run(async e=>{const t=await ia(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.");qa(n,"PlotDirector Chapter",`PD-CHAPTER-${Xt}`,"PD-CHAPTER"),qa(r,"PlotDirector Scene",`PD-SCENE-${Qt}`,"PD-SCENE"),await e.sync()}),zt=Xt,Kt=Qt,tn=!1,en="SceneID Anchor",Zt="Anchor",wr(e),po({lastError:"-"}),br(),!0}catch(e){return console.error("Unable to attach PlotDirector IDs.",e),wr("Unable to attach PlotDirector IDs."),po({lastError:ho(e)}),br(),!1}finally{ae&&(ae.textContent=Kt===Qt?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",br())}},Aa=async e=>{if(!Xt)return Vr("No resolved PlotDirector chapter."),!1;if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return Vr("Word document access is unavailable."),!1;try{return await window.Word.run(async e=>{const t=await ia(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.");qa(n,"PlotDirector Chapter",`PD-CHAPTER-${Xt}`,"PD-CHAPTER"),await e.sync()}),zt=Xt,tn=!1,en="ChapterID Anchor",Zt="Chapter anchor",Vr(e),wr(e),po({lastError:"-"}),br(),!0}catch(e){return console.error("Unable to attach PlotDirector chapter ID.",e),Vr("Unable to attach PlotDirector chapter ID."),po({lastError:ho(e)}),br(),!1}},$a=async e=>{_r(),await nc(),wr(e),Vr(e)},Ta=e=>{sn&&(sn(e),sn=null),ot?.close?ot.close():ot&&(ot.hidden=!0)},ja=()=>{if(!et)return;const e=no(Ze?.value||"").toLocaleLowerCase(),t=an.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(et.innerHTML="",cn=null,tt&&(tt.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No chapters found.",void et.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",()=>{cn=t,tt&&(tt.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled chapter",n.append(r,o),et.append(n)}},Wa=()=>{Xe?.close?Xe.close():Xe&&(Xe.hidden=!0)},Ra=async(e,t,n)=>{const r=bo();if(!r)return Fr("Select a PlotDirector book first."),!1;await lo(r.bookId,e,t,"Manual link","Title Match");return!!await Da(n)&&(Fr(n),Kr(),!0)},Ua=e=>{on&&(on(e),on=null),Je?.close?Je.close():Je&&(Je.hidden=!0)},Ma=()=>{if(!Ge)return;const e=no(He?.value||"").toLocaleLowerCase(),t=nn.filter(t=>!e||String(t.title||"").toLocaleLowerCase().includes(e));if(Ge.innerHTML="",rn=null,Fe&&(Fe.disabled=!0),0===t.length){const e=document.createElement("p");return e.className="word-companion-empty-list",e.textContent="No scenes found.",void Ge.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",()=>{rn=t,Fe&&(Fe.disabled=!1)});const o=document.createElement("span");o.textContent=e.title||"Untitled scene",n.append(r,o),Ge.append(n)}},Oa=()=>{Be?.close?Be.close():Be&&(Be.hidden=!0)},Ba=()=>{Rn=!1,$r(),Un&&(Un=!1,Ga(1e3))},Ha=async(e={})=>{const t=e.source||"manual",n=da();if(!Qt)return void Nr("No resolved PlotDirector scene.");if(!Xt)return void Nr("No resolved PlotDirector chapter.");if(Nn)return void Nr("Refresh Current Scene before syncing.");const r=bo(),o=To();if(!r||!o)return void Nr("Bound manuscript metadata is unavailable.");if(Rn)return Un=!0,void lr("Scene sync deferred; sync already running.");kr(),Rn=!0,Un=!1;let a=e.snapshot||null;try{a=la(a)?a:await pa()}catch(e){return Nr("Sync failed"),po({lastError:ho(e)}),lr("Scene sync failed."),void Ba()}if(!la(a))return Nr("Waiting for typing to pause"),lr("Scene sync skipped (stale snapshot)."),void Ba();const c=a.wordCount;if(!Number.isInteger(c)||c<0)return Nr("Sync failed"),lr("Scene sync failed."),void Ba();if(Mn===a.sceneId&&On===c)return Nr("Synced"),lr("Sync skipped (count unchanged)."),void Ba();lr("Scene word count changed."),ge&&(ge.disabled=!0,ge.textContent="Syncing..."),Nr("Syncing..."),lr(`Scene sync started (${t}).`);try{const e=da(),t=await ka("/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(ur(`Word count sync API: ${Math.round(da()-e)}ms`),!la(a))return void lr("Scene sync result ignored (stale snapshot).");const i=t?.actualWords??c,s=new Date;Mn=a.sceneId,On=i,uo(we,Ur(i)),uo(ue,Ur(i)),uo(Ie,Mr(s)),uo(ye,Mr(s)),Nr("Synced"),lr("Scene sync succeeded."),ur(`Total word count sync: ${Math.round(da()-n)}ms`)}catch(e){Nr("Sync failed"),po({lastError:ho(e)}),lr("Scene sync failed.")}finally{ge&&(ge.textContent="Sync Current Scene"),Ba()}},Ga=(e=4e3)=>{kr(),Qt&&Xt&&!Nn&&!Rn&&(Wn=window.setTimeout(()=>{Wn=null,Ha({source:"automatic"})},e))},Fa=()=>{Bn&&(window.clearTimeout(Bn),Bn=null)},Va=()=>{Fn=null,Vn="",Yn=[],Jn=null,_n="",Fa()},Ya=()=>{zn=null,Kn="",Qn=[],Xn=null,Zn=""},Ja=()=>{er=null,tr="",nr=[],rr=null,or=""},_a=async(e=!1)=>{const t=So(),n=To();if(!t||!n)return Yn=[],[];if(!e&&Fn===t.projectId&&Vn===n&&Yn.length>0)return Yn;const r=await Ca(`/api/word-companion/runtime/characters?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return Fn=t.projectId,Vn=n,Yn=Array.isArray(r?.characters)?r.characters:[],lr("Character alias cache refreshed."),Yn},za=async(e=!1)=>{const t=So(),n=To();if(!t||!n)return Qn=[],[];if(!e&&zn===t.projectId&&Kn===n&&Qn.length>0)return Qn;const r=await Ca(`/api/word-companion/runtime/assets?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return zn=t.projectId,Kn=n,Qn=Array.isArray(r?.assets)?r.assets:[],lr(`Asset cache loaded: ${Qn.length} aliases.`),Qn},Ka=async(e=!1)=>{const t=So(),n=To();if(!t||!n)return nr=[],[];if(!e&&er===t.projectId&&tr===n&&nr.length>0)return nr;const r=await Ca(`/api/word-companion/runtime/locations?projectId=${encodeURIComponent(t.projectId)}&documentGuid=${encodeURIComponent(n)}`);return er=t.projectId,tr=n,nr=Array.isArray(r?.locations)?r.locations:[],lr(`Location cache loaded: ${nr.length} aliases.`),nr},Qa=(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)},Xa=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},Za=async()=>{if(Bn=null,!Qt||Nn||!To())return;if(Hn)return Gn=!0,void lr("Character suggestion detection deferred; detection already running.");Hn=!0,Gn=!1;const e=da();try{const t=await pa();if(!la(t))return void lr("Runtime suggestions skipped (stale snapshot).");const[n,r,o]=await Promise.all([_a(),za(),Ka()]);if(!la(t))return void lr("Runtime suggestions skipped after cache load (stale snapshot).");const a=t.sceneText||"",c=da(),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)||Qa(e,r.matchText)&&n.set(t,r.name||r.matchText||"Character")}return[...n.entries()].map(([e,t])=>({characterId:e,name:t}))})(a,n);ur(`Character detection: ${Math.round(da()-c)}ms`);const s=i.map(e=>e.characterId),d=s.slice().sort((e,t)=>e-t).join(","),l=da(),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)||Qa(e,r.matchText)&&n.set(t,r.name||r.matchText||"Asset")}return[...n.entries()].map(([e,t])=>({assetId:e,name:t}))})(a,r);ur(`Asset detection: ${Math.round(da()-l)}ms`);const p=u.map(e=>e.assetId),h=p.slice().sort((e,t)=>e-t).join(","),m=da(),y=((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)||!Xa(r)||Qa(e,r.matchText)&&n.set(t,r.name||r.matchText||"Location")}return[...n.entries()].map(([e,t])=>({locationId:e,name:t}))})(a,o);ur(`Location detection: ${Math.round(da()-m)}ms`);const g=y.map(e=>e.locationId),f=g.slice().sort((e,t)=>e-t).join(",");if(!d||Jn===Qt&&_n===d)lr("Character suggestions skipped.");else{if(!la(t))return void lr("Character suggestions skipped before submit (stale snapshot).");const e=da(),n=await ka("/api/word-companion/runtime/character-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,characterIds:s});if(ur(`Character suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void lr("Character suggestion result ignored (stale snapshot).");if(Jn=t.sceneId,_n=d,(n?.createdCount||0)>0){const e=i.slice(0,3).map(e=>e.name).join(", "),t=i.length>3?" +"+(i.length-3):"";wr(e?`Characters detected: ${e}${t}`:n.message)}lr(n?.message||"Character suggestions submitted.")}if(!h||Xn===Qt&&Zn===h)lr("Asset suggestions skipped.");else{if(!la(t))return void lr("Asset suggestions skipped before submit (stale snapshot).");lr(`Asset matches found: ${u.map(e=>e.name).join(", ")}`);const e=da(),n=await ka("/api/word-companion/runtime/asset-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,assetIds:p});if(ur(`Asset suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void lr("Asset suggestion result ignored (stale snapshot).");if(Xn=t.sceneId,Zn=h,(n?.createdCount||0)>0){const e=u.slice(0,3).map(e=>e.name).join(", "),t=u.length>3?" +"+(u.length-3):"";wr(e?`Assets detected: ${e}${t}`:n.message)}lr(n?.message||"Asset suggestions submitted.")}if(!f||rr===Qt&&or===f)lr("Location suggestions skipped.");else{if(!la(t))return void lr("Location suggestions skipped before submit (stale snapshot).");lr(`Location matches found: ${y.map(e=>e.name).join(", ")}`);const e=da(),n=await ka("/api/word-companion/runtime/location-suggestions",{documentGuid:t.documentGuid,sceneId:t.sceneId,locationIds:g});if(ur(`Location suggestion API: ${Math.round(da()-e)}ms`),!la(t))return void lr("Location suggestion result ignored (stale snapshot).");if(rr=t.sceneId,or=f,(n?.createdCount||0)>0){const e=y.slice(0,3).map(e=>e.name).join(", "),t=y.length>3?" +"+(y.length-3):"";wr(e?`Locations detected: ${e}${t}`:n.message)}lr(n?.message||"Location suggestions submitted.")}ur(`Total suggestion pass: ${Math.round(da()-e)}ms`)}catch(e){console.error("Unable to detect runtime suggestions.",e),po({lastError:ho(e)})}finally{Hn=!1,Gn&&(Gn=!1,ec(1500))}},ec=(e=2500)=>{Fa(),!Qt||Nn||Hn?Hn&&(Gn=!0):Bn=window.setTimeout(()=>{Za()},e)},tc=async()=>{const e=So(),t=bo(),n=ro(Vt,"chapter");if(oo({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Io(t):void 0,detectedChapter:Vt,detectedScene:Yt,requestChapter:n,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!t)return Xr("Not detected"),wr("Select a PlotDirector book first."),!1;if(!Vt)return Xr("Not detected"),wr("No chapter detected in Word. Use Heading 1 for chapters."),!1;Xr("Not detected");try{const e=await co(t.bookId),r=zt?e.find(e=>e.chapterId===zt):null,o=n.toLocaleLowerCase(),a=o?e.find(e=>ro(e.title,"chapter").toLocaleLowerCase()===o):null,c=r||a;return c?(_r(),Wr(null,c.chapterId,r?"Chapter anchor":"Chapter title"),en=r?"ChapterID Anchor":"Title Match",Ir("Chapter linked to PlotDirector"),wr("No scene detected in Word. Use Heading 2 for scenes."),oo({result:"Chapter matched",chapterId:c.chapterId,sceneId:null}),!0):(Wr(null),Ir("Chapter not found in PlotDirector."),wr("Chapter not found in PlotDirector."),oo({result:"Chapter not matched",chapterId:null,sceneId:null}),zr("Chapter not found in PlotDirector."),!1)}catch(e){return Xr("Not found in PlotDirector"),po({lastError:ho(e)}),wr("Unable to load PlotDirector chapter data."),!1}},nc=async()=>{const e=So(),t=bo(),n=ro(Vt,"chapter"),r=ro(Yt,"scene");if(oo({projectId:e?.projectId,projectTitle:e?.title,bookId:t?.bookId,bookTitle:t?Io(t):void 0,detectedChapter:Vt,detectedScene:Yt,requestChapter:n,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),Sr({anchorType:Kt?"SceneID Anchor":zt?"ChapterID Anchor":"Title Match",storedSceneId:Kt,storedChapterId:zt,resolutionMethod:"-"}),!t)return Xr("Not detected"),wr("Select a PlotDirector book first."),oo({result:"Error"}),!1;if(!Vt||!Yt)return Xr("Not detected"),wr("No scene detected in Word. Use Heading 2 for scenes."),oo({result:"Error"}),!1;Z&&(Z.disabled=!0,Z.textContent="Refreshing...");const o=()=>{Z&&(Z.disabled=!1,Z.textContent="Refresh PlotDirector Scene")};Xr("Not detected"),wr("Resolving PlotDirector scene...");try{if(Kt){const e=await(async(e,t)=>{const n=await Ca(`/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===Kt);if(e)return oo({result:"Matched",chapterId:e.chapter.chapterId,sceneId:e.scene.sceneId}),await lo(t.bookId,e.scene.sceneId,e.chapter.chapterId,"Anchor","SceneID Anchor"),!0;tn=!0,en="SceneID Anchor",Ir("Not found in PlotDirector"),wr("Stored PlotDirector ID is invalid."),oo({result:"Error",chapterId:zt,sceneId:Kt}),Sr({anchorType:"SceneID Anchor",storedSceneId:Kt,storedChapterId:zt,resolutionMethod:"Anchor"})}if(zt){const e=(await ao(t.bookId)).find(e=>e.chapterId===zt),n=e?(Array.isArray(e.scenes)?e.scenes:[]).find(e=>ro(e.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(n)return oo({result:"Matched",chapterId:e.chapterId,sceneId:n.sceneId}),await lo(t.bookId,n.sceneId,e.chapterId,"Anchor","ChapterID Anchor"),!0;e&&!Kt?(en="ChapterID Anchor",Wr(null,zt,"Chapter anchor"),oo({result:"Chapter matched",chapterId:zt,sceneId:null})):Kt||(en="ChapterID Anchor",oo({result:"Chapter anchor not found",chapterId:zt,sceneId:null}))}const e=await ka(`/api/word-companion/books/${t.bookId}/resolve-scene`,{chapterTitle:n,sceneTitle:r});if(!e?.matched||!e.sceneId){const t=tn,n=Number.parseInt(e?.chapterId||"",10),r=Number.isInteger(Xt)&&Xt>0?Xt:null,a=Number.isInteger(n)&&n>0?n:r,c=!!e?.chapterMatched||!!a;return Xr("Not found in PlotDirector"),tn=t,c&&(Wr(null,a,a===r?"Chapter anchor":"Chapter title"),Ir("Scene not found in PlotDirector.")),wr(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."),oo({result:"Not matched",chapterId:c?a:e?.chapterId,sceneId:e?.sceneId}),t||(c?(_r(),Qr("Scene not found in PlotDirector.")):(Kr(),zr("Chapter not found in PlotDirector."))),o(),!1}const a=tn;return oo({result:a?"Matched by title fallback":"Matched",chapterId:e.chapterId,sceneId:e.sceneId}),await lo(t.bookId,e.sceneId,e.chapterId,a?"Title fallback":"Title","Title Match"),a&&(tn=!0,wr("Stored PlotDirector ID is invalid."),br()),!0}catch(e){const t=tn;return po({lastError:ho(e)}),Xr("Not found in PlotDirector"),tn=t,wr(t?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),oo({result:"Error"}),!1}finally{o()}},rc=async()=>{if(En=null,jn)return qn=!0,void lr("Runtime update deferred; update already running.");if(!Ut||!bo())return Ln=!1,void lr("Runtime update skipped.");if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return Ln=!1,Tr("Manual"),void wr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");if(!pn)return Ln=!1,Tr("Manual"),void wr("Document structure is not cached yet. Use Refresh Current Scene.");const e=Date.now()-Pn;if(Ln&&e<$n)return lr("Runtime update skipped (typing active)."),void oc($n-e);jn=!0,Ln=!1,qn=!1,Tr("Updating..."),lr("Runtime update executed.");try{const e=await ua({includeSelection:!0});if(!la(e))return Tr("Waiting for typing to pause"),void lr("Runtime update skipped (stale snapshot).");if(!!!e.selectionChanged)return jr(!1),Tr("Current scene updated"),Ga(),void ec();Yt?await nc():await tc(),jr(!1),Tr("Current scene updated"),wr("Current scene updated."),Ga(),ec()}catch(e){console.error("Unable to refresh current scene from Word selection.",e),po({lastError:ho(e)}),jr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving.")}finally{jn=!1,(qn||Ln)&&(qn=!1,oc($n))}},oc=(e=1200)=>{En&&window.clearTimeout(En),En=window.setTimeout(rc,Math.max(0,e)),Tr("Waiting for typing to pause"),lr("Runtime update scheduled.")},ac=()=>{((e="selection",t=1200)=>{if(Ln=!0,Pn=Date.now(),Dn+=1,An=null,kr(),Fa(),Rn&&(Un=!0),Hn&&(Gn=!0),lr(`${e} changed.`),jn)return qn=!0,void Tr("Waiting for typing to pause");oc(t)})("Selection")},cc=()=>{if(Tn&&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:ac}),Tn=!1}catch(e){console.warn("Unable to remove Word selection tracking handler.",e)}},ic=async(e,n)=>{if(pn=null,Hr(),!e)return Ot=[],fo(R,"Select a project first"),fo(u,"Select a project first"),fr(""),go(t,null),jo(),Xr("Not detected"),void Lr();fo(R,"Loading books..."),fr(""),Xr("Not detected"),Lr("Select a book to analyse manuscript structure.");try{const r=await Ca(`/api/word-companion/projects/${e}/books`);if(Ot=Array.isArray(r.books)?r.books:[],0===Ot.length)return fo(R,"No books available."),fo(u,"No books available."),fr("No books available."),go(t,null),jo(),void Lo("No books available.");wo(R,"Choose a book",Ot.map(e=>({...e,displayTitle:Io(e)})),"bookId","displayTitle");const o=Ot.find(e=>e.bookId===n);o&&R?(R.value=String(o.bookId),go(t,o.bookId)):go(t,null),((e=null)=>{if(!u)return;if(0===Ot.length)return void fo(u,"No books available.");wo(u,"Choose a book",Ot.map(e=>({...e,displayTitle:Io(e)})),"bookId","displayTitle");const t=e||Number.parseInt(R?.value||"",10),n=Ot.find(e=>e.bookId===t);n&&(u.value=String(n.bookId)),xo()})(o?.bookId||n),jo(),Xr((bo(),"Not detected")),Lr(bo()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Lo(ko()?"Ready to scan manuscript structure.":"Select a Book to begin.")}catch{Ot=[],fo(R,"Unable to load books."),fo(u,"Unable to load books."),fr("Unable to load books."),go(t,null),jo(),Xr("Not detected"),Lr("Unable to load books."),Lo("Unable to load books.")}};for(const e of i)e.addEventListener("click",()=>hr(e.dataset.tabButton));mr(),W?.addEventListener("change",async()=>{const n=Number.parseInt(W.value||"",10);Br(),l&&Number.isInteger(n)&&n>0&&(l.value=String(n)),go(e,Number.isInteger(n)&&n>0?n:null),go(t,null),Xr("Not detected"),Lr(),Lo("Select a Book to begin."),await ic(n,null)}),R?.addEventListener("change",()=>{const e=Number.parseInt(R.value||"",10);Br(),go(t,Number.isInteger(e)&&e>0?e:null),u&&Number.isInteger(e)&&e>0&&(u.value=String(e)),jo(),Xr("Not detected"),Lr(bo()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure."),Lo(ko()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),l?.addEventListener("change",async()=>{const n=Number.parseInt(l.value||"",10);Br(),W&&Number.isInteger(n)&&n>0&&(W.value=String(n)),go(e,Number.isInteger(n)&&n>0?n:null),go(t,null),Lo("Select a Book to begin."),await ic(n,null)}),u?.addEventListener("change",()=>{const e=Number.parseInt(u.value||"",10);Br(),R&&Number.isInteger(e)&&e>0&&(R.value=String(e)),go(t,Number.isInteger(e)&&e>0?e:null),jo(),Lo(ko()?"Ready to scan manuscript structure.":"Select a Book to begin.")}),p?.addEventListener("input",xo),h?.addEventListener("click",async()=>{const e=Co(),t=String(p?.value||"").trim();if(e&&t){h.disabled=!0,vo("Creating Book...");try{const n=await ka(`/api/word-companion/projects/${e.projectId}/books`,{title:t});p&&(p.value=""),W&&(W.value=String(e.projectId)),await ic(e.projectId,n.bookId),u&&(u.value=String(n.bookId)),vo("Ready to scan manuscript structure.")}catch(e){console.error("Unable to create Book from Word Companion.",e),vo(`Unable to create Book: ${ho(e)}`)}finally{xo()}}else xo()}),m?.addEventListener("click",async()=>{const e=Co(),t=ko();if(e&&t)if(Bt&&Ht&&window.Word&&"function"==typeof window.Word.run){m&&(m.disabled=!0,m.textContent="Scanning..."),vo("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),Ro(e,1))return r={title:d,sortOrder:10*(n.length+1),wordCount:0,scenes:[]},n.push(r),o=s(),void(a+=Uo(d));if(!r||!o)return;if(t&&i.has(d))return void(o=s());const l=Uo(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)});gn=n,wn=!1;const r=await ka("/api/word-companion/manuscript/analyse",{projectId:e.projectId,bookId:t.bookId,documentGuid:$o(),chapterCount:n.chapterCount,sceneCount:n.sceneCount,wordCount:n.wordCount});yn=r,(e=>{if(!f)return;f.innerHTML="";const t=document.createElement("strong");t.textContent="Manuscript Analysis",f.append(t);const n=document.createElement("dl"),r=[["Project",e.projectTitle],["Book",Io({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)}f.append(n),vr(f,!1),vr(x,!1),vo(e.message||"Preview generated."),xo()})(r);try{const t=await ka("/api/word-companion/manuscript/discover-characters",{projectId:e.projectId,documentText:n.documentText||""});fn=Array.isArray(t?.candidates)?t.candidates:[],vr(w,!0),vr(b,!0)}catch(e){console.error("Unable to discover character candidates.",e),fn=[],vr(w,!0),vr(b,!0)}po({lastScan:"Success",lastError:"-",paragraphs:"-",heading1:String(n.chapterCount),heading2:"-"})}catch(e){console.error("Unable to scan manuscript for first-run import.",e),Lo(`Unable to scan manuscript: ${ho(e)}`),po({lastScan:"Failure",lastError:ho(e)})}finally{m&&(m.textContent="Scan Manuscript"),xo()}}else Lo("Word document access is unavailable.");else Lo("Select a Project and Book to begin.")}),N?.addEventListener("click",async()=>{const n=Co(),o=ko();if(!(n&&o&&gn&&yn?.canImport))return void xo();let a=!1;if(!yn.requiresReplaceConfirmation||(a=await new Promise(e=>{if(!L||"function"!=typeof L.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=>{P?.removeEventListener("click",n),q?.removeEventListener("click",r),L?.removeEventListener("cancel",o),L?.close(),e(t)},n=()=>t(!0),r=()=>t(!1),o=e=>{e.preventDefault(),t(!1)};P?.addEventListener("click",n),q?.addEventListener("click",r),L?.addEventListener("cancel",o),L.showModal()}),a)){bn=!0,xo(),vo("Importing manuscript structure...");try{const i=$o(),s=await ka("/api/word-companion/manuscript/import",{projectId:n.projectId,bookId:o.bookId,documentGuid:i,bindingVersion:1,replacePlanned:a,chapters:gn.chapters});if(!s.imported)return yn={...yn,canImport:!s.requiresReplaceConfirmation,requiresReplaceConfirmation:!!s.requiresReplaceConfirmation,message:s.message||yn.message},vo(s.message||"Import was not completed."),void xo();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."))})),ln={documentGuid:d?.documentGuid||i,bookId:s.bookId,projectId:s.projectId,bindingVersion:d?.bindingVersion||1},go(e,s.projectId),go(t,s.bookId),W&&(W.value=String(s.projectId));const l=fn;await ic(s.projectId,s.bookId),yr("Connected"),wn=!0,In=l.length>0,Sn=In?Date.now():0,fn=l,l.length>0?(No(!0),qo(l),vr(x,!0),vr(b,!1),vo(s.message||"Manuscript structure imported."),wr(s.message||"Manuscript structure imported."),window.setTimeout(xo,750)):await va(s.message||"Manuscript structure imported.")}catch(e){console.error("Unable to import manuscript structure.",e),vo(`Unable to import manuscript: ${ho(e)}`)}finally{bn=!1,xo()}var c}else vo("Import cancelled.")}),C?.addEventListener("click",async()=>{const e=Co()||So(),t=Po();if(!In||Date.now()-Sn<750||!e||0===t.length)xo();else{Cn=!0,xo(),uo(I,"Creating selected characters...");try{const n=await ka("/api/word-companion/manuscript/create-discovered-characters",{projectId:e.projectId,candidateNames:t});wr(n.message||"Characters created."),uo(I,`${n.createdCount||0} created, ${n.skippedCount||0} already existed.`),await va(n.message||"Characters created.")}catch(e){console.error("Unable to create discovered characters.",e),uo(I,`Unable to create characters: ${ho(e)}`)}finally{Cn=!1,xo()}}}),k?.addEventListener("click",()=>va("Character creation skipped.")),v?.addEventListener("click",()=>va()),y?.addEventListener("click",()=>No(!1)),E?.addEventListener("click",()=>Lo("Import cancelled.")),B?.addEventListener("click",ha),z?.addEventListener("click",ma),K?.addEventListener("click",async()=>{const e=bo();if(!e||0===Pr().length||kn)return void qr();if(!await ga())return;kn=!0,Dr(),Er("Applying structure sync...");const t={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(dn?.manualReview)?dn.manualReview.length:0,failed:0},n=Pr().filter(e=>"couldLink"===e.category&&"Chapter"===e.type),r=Pr().filter(e=>"wouldCreateChapters"===e.category),o=Pr().filter(e=>"couldLink"===e.category&&"Scene"===e.type),a=Pr().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(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const n=await ia(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.");qa(o,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=e.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");qa(o,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})})(e),fa(e,"Success"),t[n]+=1}catch(n){fa(e,"Failed",ho(n)),t.failed+=1}};try{for(const e of n)s(e,"linkedChapters");for(const n of r)try{await Sa(e.bookId,n),s(n,"createdChapters")}catch(e){fa(n,"Failed",ho(e)),t.failed+=1}for(const e of o)s(e,"linkedScenes");for(const n of a)try{await ba(e.bookId,n),s(n,"createdScenes")}catch(e){fa(n,"Failed",ho(e)),t.failed+=1}for(const e of c)await d(e.item,e.counterName);for(const e of dn.manualReview||[])fa(e,"Skipped");ca(dn),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),Er(i)}finally{kn=!1,Dr(),i&&(Hr(),await ma(),Er(`${i} Preview refreshed.`))}}),ut?.addEventListener("click",()=>ya(!0)),pt?.addEventListener("click",()=>ya(!1)),dt?.addEventListener("cancel",e=>{e.preventDefault(),ya(!1)}),Z?.addEventListener("click",nc),O?.addEventListener("click",async()=>{if(!bo())return wr("Select a PlotDirector book first."),void Xr("Not detected");En&&(window.clearTimeout(En),En=null),Ln=!1,qn=!1,Rr(!0),Tr("Updating...");try{await Promise.all([_a(!0),za(!0),Ka(!0)]);if(!await ha())return;if(jr(!1),!Yt)return await tc(),void Tr("Current scene updated");await nc(),Tr("Current scene updated")}finally{Rr(!1)}}),ge?.addEventListener("click",()=>Ha({source:"manual"})),Ee?.addEventListener("click",async()=>{if(Qt)if(!Nn&&await(async()=>{if(!Qt)return!1;if(!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return jr(!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 ia(e)),t=e.currentChapter?.title||"",n=e.currentScene?.title||"",r=e.currentScene?.anchorId||null,o=e.currentChapter?.anchorId||null,a=Number.isInteger(r)&&r===Qt,c=Number.isInteger(o)&&o===Xt,i=ro(n,"scene").toLocaleLowerCase()===ro(cr||Yt,"scene").toLocaleLowerCase(),s=ro(t,"chapter").toLocaleLowerCase()===ro(ir||Vt,"chapter").toLocaleLowerCase();return a||i&&(c||s)?(jr(!1),!0):(jr(!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),po({lastError:ho(e)}),jr(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}})()){Ee&&(Ee.disabled=!0,Ee.textContent="Saving...");try{await(e=`/api/word-companion/scenes/${Qt}/links`,t={characterIds:La(ve),assetIds:La(xe),locationIds:[],primaryLocationId:Pa()},Ca(e,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})),(()=>{const e=new Set(La(ve)),t=new Set(La(xe));dr={characters:dr.characters.map(t=>({...t,linked:e.has(Number.parseInt(Zr(t,"character"),10))})),assets:dr.assets.map(e=>({...e,linked:t.has(Number.parseInt(Zr(e,"asset"),10))})),locations:dr.locations,primaryLocationId:Pa()}})(),Gr("Scene links saved successfully."),po({lastError:"-"})}catch(e){Gr("Unable to save scene links."),po({lastError:ho(e)})}finally{Ee&&(Ee.disabled=!Qt||Nn,Ee.textContent="Save Scene Links")}var e,t}else Gr("The Word cursor is now in a different scene. Refresh Current Scene before saving.");else Gr("Link a PlotDirector scene first.")}),ae?.addEventListener("click",async()=>{await Da()}),ce?.addEventListener("click",async()=>{const e=ln||Do();if(!e)return void wr("This Word document is not linked.");if(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?")){ce&&(ce.disabled=!0,ce.textContent="Unlinking...");try{await ka("/api/word-companion/manuscript/unlink",{documentGuid:e.documentGuid,bookId:e.bookId}),await Ao(),await Ea("Word document unlinked. Select a Project and Book to begin.")}catch(e){console.error("Unable to unlink manuscript binding.",e);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 Word metadata only?"))try{await Ao(),await Ea("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),wr(`Unable to remove Word metadata: ${ho(e)}`)}else wr(`Unable to unlink manuscript: ${ho(e)}`)}finally{ce&&(ce.disabled=!1,ce.textContent="Unlink this Word document"),xr()}}}),Ae?.addEventListener("click",async()=>{const e=bo();if(!e||!Vt||Xt)return void zr("Chapter not found in PlotDirector.");const t=no(Vt),n=await((e,t)=>(uo(at,`"${e}"`),uo(ct,`"${t}"`),ot?new Promise(e=>{sn=e,ot.showModal?ot.showModal():ot.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector chapter:\n\n"${e}"\n\nin book:\n\n"${t}"\n\n?`))))(t,Io(e)||"selected book");if(n){Ae&&(Ae.disabled=!0,Ae.textContent="Creating...");try{const n=Number.isInteger(_t)&&_t>0?10*_t:null,r=await ka(`/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.");Hr(),Wr(null,r.chapterId,"Manual chapter link");if(!await Aa("Chapter created and linked successfully."))return;await $a("Chapter created and linked successfully.")}catch(e){Vr("Unable to create chapter."),po({lastError:ho(e)})}finally{Ae&&(Ae.disabled=!Yr(),Ae.textContent="Create Chapter in PlotDirector")}}}),$e?.addEventListener("click",async()=>{const e=bo();if(e&&Vt&&!Xt){$e&&($e.disabled=!0,$e.textContent="Loading...");try{an=await co(e.bookId),cn=null,Ze&&(Ze.value=""),uo(rt,""),ja(),Xe?.showModal?Xe.showModal():Xe&&(Xe.hidden=!1)}catch(e){Vr("Unable to load chapters."),po({lastError:ho(e)})}finally{$e&&($e.disabled=!Yr(),$e.textContent="Link to Existing Chapter")}}else zr("Chapter not found in PlotDirector.")}),Ze?.addEventListener("input",ja),tt?.addEventListener("click",async()=>{const e=an.find(e=>e.chapterId===cn);if(e){tt&&(tt.disabled=!0,tt.textContent="Linking...");try{Wr(null,e.chapterId,"Manual chapter link");if(!await Aa("Chapter linked successfully."))return;Wa(),await $a("Chapter linked successfully.")}catch(e){uo(rt,"Unable to link chapter."),Vr("Unable to link chapter."),po({lastError:ho(e)})}finally{tt&&(tt.disabled=!cn,tt.textContent="Link Chapter")}}else uo(rt,"Select a chapter.")}),nt?.addEventListener("click",Wa),it?.addEventListener("click",()=>Ta(!0)),st?.addEventListener("click",()=>Ta(!1)),ot?.addEventListener("cancel",e=>{e.preventDefault(),Ta(!1)}),Ue?.addEventListener("click",async()=>{const e=bo();if(!e||!Yt)return void Qr("Scene not found in PlotDirector.");const t=ro(Yt,"scene"),n=ro(Vt,"chapter"),r=await((e,t)=>(uo(_e,`"${e}"`),uo(ze,`"${t}"`),Je?new Promise(e=>{on=e,Je.showModal?Je.showModal():Je.hidden=!1}):Promise.resolve(window.confirm(`Create PlotDirector scene:\n\n"${e}"\n\nwithin chapter:\n\n"${t}"\n\n?`))))(t,n);if(r){Ue&&(Ue.disabled=!0,Ue.textContent="Creating...");try{const n=await so();if(!n)return void Qr("This chapter does not exist in PlotDirector. Create or link the chapter first.");const r=await ka(`/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.");Hr(),await Ra(r.sceneId,r.chapterId,"Scene created and linked successfully.")}catch(e){Fr("Unable to create scene."),po({lastError:ho(e)})}finally{Ue&&(Ue.disabled=!Jr(),Ue.textContent="Create Scene in PlotDirector")}}}),Me?.addEventListener("click",async()=>{const e=bo();if(e&&Yt){Me&&(Me.disabled=!0,Me.textContent="Loading...");try{const t=await ao(e.bookId),n=io(t);if(!n)return void Qr("This chapter does not exist in PlotDirector. Create or link the chapter first.");nn=Array.isArray(n.scenes)?n.scenes:[],rn=null,He&&(He.value=""),uo(Ye,""),Ma(),Be?.showModal?Be.showModal():Be&&(Be.hidden=!1)}catch(e){Fr("Unable to load scenes."),po({lastError:ho(e)})}finally{Me&&(Me.disabled=!Jr(),Me.textContent="Link to Existing Scene")}}else Qr("Scene not found in PlotDirector.")}),He?.addEventListener("input",Ma),Fe?.addEventListener("click",async()=>{const e=bo(),t=nn.find(e=>e.sceneId===rn);if(e&&t){Fe&&(Fe.disabled=!0,Fe.textContent="Linking...");try{const e=await so();if(!e)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");Oa(),await Ra(t.sceneId,e.chapterId,"Scene linked successfully.")}catch(e){uo(Ye,"Unable to link scene."),Fr("Unable to link scene."),po({lastError:ho(e)})}finally{Fe&&(Fe.disabled=!rn,Fe.textContent="Link Scene")}}else uo(Ye,"Select a scene.")}),Ve?.addEventListener("click",Oa),Ke?.addEventListener("click",()=>Ua(!0)),Qe?.addEventListener("click",()=>Ua(!1)),Je?.addEventListener("cancel",e=>{e.preventDefault(),Ua(!1)}),vt?.addEventListener("click",async()=>{vt&&(vt.disabled=!0,vt.textContent="Running...");try{if(await mo(),!Bt||!Ht||!window.Word||"function"!=typeof window.Word.run)return void po({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});po({lastScan:"Success",lastError:"-",paragraphs:String(e)})}catch(e){console.error("Word Companion diagnostics failed.",e);const t=ho(e);po({lastScan:"Failure",lastError:t}),wr(`Unable to scan the Word document: ${t}`)}finally{vt&&(vt.disabled=!1,vt.textContent="Run Diagnostics")}});const sc=Ut?(async()=>{fo(W,"Loading projects..."),fo(R,"Select a project first"),fo(l,"Loading projects..."),fo(u,"Select a project first"),gr(""),fr("");try{const n=await Ca("/api/word-companion/projects");if(Mt=Array.isArray(n.projects)?n.projects:[],0===Mt.length)return fo(W,"No projects available."),fo(l,"No projects available."),gr("No projects available."),go(e,null),go(t,null),jo(),void Lo("No projects available.");wo(W,"Choose a project",Mt,"projectId","title"),Eo();const r=yo(e),o=Mt.find(e=>e.projectId===r);o&&W?(W.value=String(o.projectId),l&&(l.value=String(o.projectId)),go(e,o.projectId),await ic(o.projectId,yo(t))):(go(e,null),go(t,null),jo(),Lo("Select a Project and Book to begin."))}catch{Mt=[],Ot=[],fo(W,"Unable to connect to PlotDirector."),fo(R,"Select a project first"),fo(l,"Unable to connect to PlotDirector."),fo(u,"Select a project first"),yr("Unable to connect to PlotDirector."),gr("Unable to connect to PlotDirector."),go(e,null),go(t,null),jo(),Lo("Unable to connect to PlotDirector.")}})():Promise.resolve();if(Ut||(fo(W,"Please sign in to PlotDirector."),fo(R,"Please sign in to PlotDirector."),fo(l,"Please sign in to PlotDirector."),fo(u,"Please sign in to PlotDirector."),jo()),!window.Office||"function"!=typeof window.Office.onReady)return pr("Word Companion ready"),wr("Word document access is unavailable."),Tr("Manual"),void po({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});mo().then(async()=>{pr("Word Companion ready"),await sc,await(async()=>{if(!Ut||!Ht)return void No(!1);const n=Do();if(n)try{const r=await Ca(`/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 ln=n,Or(r),go(e,r.projectId),go(t,r.bookId),W&&(W.value=String(r.projectId)),await ic(r.projectId,r.bookId),No(!1),yr("Connected"),fr("Bound manuscript detected."),void await Na()}catch{}ln=null,Br(),Eo(),Co()?await ic(Co().projectId,null):fo(u,"Select a project first"),Lo("Select a Project and Book to begin."),No(!0)})(),Ht?(()=>{if(Ut){if(!window.Office?.context?.document||"function"!=typeof window.Office.context.document.addHandlerAsync||!window.Office?.EventType?.DocumentSelectionChanged)return Tr("Manual"),void wr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,ac,e=>{e?.status===window.Office.AsyncResultStatus.Succeeded?(Tn=!0,Tr("Live")):(Tr("Manual"),wr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))}),window.addEventListener("beforeunload",cc)}catch(e){console.warn("Unable to register Word selection tracking handler.",e),Tr("Manual"),wr("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}})():(wr("Word document access is unavailable."),Tr("Manual"))}).catch(e=>{console.error("Office readiness check failed.",e),yr("Unable to connect to PlotDirector."),pr("Word Companion unavailable"),wr("Word document access is unavailable."),po({ready:"No",wordApi:"No",lastScan:"Failure"})})})(); \ No newline at end of file