diff --git a/PlotLine/Views/Timeline/Index.cshtml b/PlotLine/Views/Timeline/Index.cshtml index 5647b5f..3344f19 100644 --- a/PlotLine/Views/Timeline/Index.cshtml +++ b/PlotLine/Views/Timeline/Index.cshtml @@ -151,6 +151,21 @@ } return string.Join(Environment.NewLine, lines); } + string TrimMarkerLabel(string value) + => string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().Length <= 5 ? value.Trim() : value.Trim()[..5]; + IReadOnlyList EntityWarnings(Scene scene, string entityType, int entityId) + => Model.WarningsByScene.TryGetValue(scene.SceneID, out var sceneWarnings) + ? sceneWarnings + .Where(warning => string.Equals(warning.EntityType, entityType, StringComparison.OrdinalIgnoreCase) + && warning.EntityID == entityId) + .OrderByDescending(warning => warning.SeverityName) + .ThenBy(warning => warning.WarningTypeName) + .ToList() + : []; + bool HasStoryState(SceneCharacter appearance) + => !string.IsNullOrWhiteSpace(appearance.EmotionalState) + || !string.IsNullOrWhiteSpace(appearance.PhysicalCondition) + || !string.IsNullOrWhiteSpace(appearance.KnowledgeNotes); string AssetMarkerLabel(AssetEvent assetEvent) { var typeName = assetEvent.AssetEventTypeName?.Trim() ?? string.Empty; @@ -172,7 +187,7 @@ "investigated" => "?", "resolved" => "Done", "state changed" => "State", - _ => string.IsNullOrWhiteSpace(typeName) ? "Asset" : typeName.Length <= 5 ? typeName : typeName[..5] + _ => string.IsNullOrWhiteSpace(typeName) ? "Asset" : TrimMarkerLabel(typeName) }; } string AssetMarkerMeaning(AssetEvent assetEvent) @@ -199,27 +214,96 @@ _ => string.IsNullOrWhiteSpace(typeName) ? "Asset event occurs in this scene." : $"Asset event: {typeName}." }; } - string AssetMarkerTooltip(AssetEvent assetEvent, Scene scene) + string AssetStorySentence(AssetEvent assetEvent) + { + var title = assetEvent.EventTitle?.Trim(); + if (!string.IsNullOrWhiteSpace(title) && !string.Equals(title, assetEvent.AssetEventTypeName, StringComparison.OrdinalIgnoreCase)) + { + return $"{assetEvent.AssetName}: {title}."; + } + + return AssetMarkerMeaning(assetEvent); + } + string AssetMarkerClass(AssetEvent assetEvent, StoryAsset asset, IReadOnlyList assetWarnings) + { + var classes = new List(); + var typeName = assetEvent.AssetEventTypeName?.Trim().ToLowerInvariant() ?? string.Empty; + if (assetWarnings.Any()) + { + classes.Add("timeline-marker-has-warning"); + } + if (asset.Importance >= 8) + { + classes.Add("timeline-marker-important"); + } + if (!string.IsNullOrWhiteSpace(assetEvent.ToStateName)) + { + classes.Add("timeline-marker-state-change"); + } + if (typeName is "found" or "revealed" or "destroyed" or "resolved" or "state changed") + { + classes.Add("timeline-marker-story-turn"); + } + if (typeName is "given" or "taken" or "stolen" or "moved" or "location changed") + { + classes.Add("timeline-marker-transfer"); + } + return string.Join(' ', classes); + } + string AssetMarkerTooltip(AssetEvent assetEvent, StoryAsset asset, Scene scene, IReadOnlyList assetWarnings) { var lines = new List { - AssetMarkerMeaning(assetEvent), + AssetStorySentence(assetEvent), $"Asset: {assetEvent.AssetName}", - $"Event: {assetEvent.EventTitle}", + $"Event type: {(string.IsNullOrWhiteSpace(assetEvent.AssetEventTypeName) ? "Not set" : assetEvent.AssetEventTypeName)}", $"Scene: {scene.SceneNumber:g}: {scene.SceneTitle}" }; + if (asset.Importance >= 8) + { + lines.Add("Significance: High-importance story asset."); + } + if (!string.IsNullOrWhiteSpace(assetEvent.FromStateName) || !string.IsNullOrWhiteSpace(assetEvent.ToStateName)) + { + lines.Add($"State change: {(string.IsNullOrWhiteSpace(assetEvent.FromStateName) ? "Unknown" : assetEvent.FromStateName)} -> {(string.IsNullOrWhiteSpace(assetEvent.ToStateName) ? "Unknown" : assetEvent.ToStateName)}"); + } if (!string.IsNullOrWhiteSpace(assetEvent.ToStateName)) { - lines.Add($"State changes to: {assetEvent.ToStateName}"); + lines.Add($"Current state after this event: {assetEvent.ToStateName}"); } if (!string.IsNullOrWhiteSpace(assetEvent.EventDescription)) { lines.Add($"Summary: {assetEvent.EventDescription}"); } + foreach (var warning in assetWarnings.Take(2)) + { + lines.Add($"Continuity: {warning.WarningTypeName} - {(string.IsNullOrWhiteSpace(warning.Details) ? warning.Message : warning.Details)}"); + } return string.Join(Environment.NewLine, lines); } - string CharacterMarkerLabel(SceneCharacter appearance) + string CharacterMarkerLabel(SceneCharacter appearance, SceneCharacter? firstAppearance, SceneCharacter? lastAppearance) { + if (firstAppearance?.SceneCharacterID == appearance.SceneCharacterID) + { + return "Intro"; + } + if (lastAppearance?.SceneCharacterID == appearance.SceneCharacterID + && string.Equals(appearance.PresenceTypeName, "Leaves", StringComparison.OrdinalIgnoreCase)) + { + return "Exit"; + } + if (string.Equals(appearance.RoleInSceneTypeName, "POV Character", StringComparison.OrdinalIgnoreCase)) + { + return "POV"; + } + if (!string.IsNullOrWhiteSpace(appearance.KnowledgeNotes)) + { + return "Know"; + } + if (HasStoryState(appearance)) + { + return "State"; + } var presence = appearance.PresenceTypeName?.Trim() ?? string.Empty; return presence.ToLowerInvariant() switch { @@ -235,8 +319,25 @@ _ => "Char" }; } - string CharacterMarkerMeaning(SceneCharacter appearance) + string CharacterMarkerMeaning(SceneCharacter appearance, SceneCharacter? firstAppearance, SceneCharacter? lastAppearance) { + if (firstAppearance?.SceneCharacterID == appearance.SceneCharacterID) + { + return $"{appearance.CharacterName} enters this story lane in this scene."; + } + if (lastAppearance?.SceneCharacterID == appearance.SceneCharacterID + && string.Equals(appearance.PresenceTypeName, "Leaves", StringComparison.OrdinalIgnoreCase)) + { + return $"{appearance.CharacterName} exits this story lane in this scene."; + } + if (!string.IsNullOrWhiteSpace(appearance.KnowledgeNotes)) + { + return $"{appearance.CharacterName}'s knowledge changes in this scene."; + } + if (!string.IsNullOrWhiteSpace(appearance.EmotionalState) || !string.IsNullOrWhiteSpace(appearance.PhysicalCondition)) + { + return $"{appearance.CharacterName}'s story state changes in this scene."; + } var presence = appearance.PresenceTypeName?.Trim() ?? string.Empty; return presence.ToLowerInvariant() switch { @@ -252,16 +353,75 @@ _ => "Character appears in this scene." }; } - string CharacterMarkerTooltip(SceneCharacter appearance, Scene scene) + string CharacterMarkerClass(SceneCharacter appearance, SceneCharacter? firstAppearance, SceneCharacter? lastAppearance, IReadOnlyList characterWarnings) + { + var classes = new List(); + if (characterWarnings.Any()) + { + classes.Add("timeline-marker-has-warning"); + } + if (firstAppearance?.SceneCharacterID == appearance.SceneCharacterID) + { + classes.Add("timeline-marker-story-turn"); + } + if (lastAppearance?.SceneCharacterID == appearance.SceneCharacterID + && string.Equals(appearance.PresenceTypeName, "Leaves", StringComparison.OrdinalIgnoreCase)) + { + classes.Add("timeline-marker-exit"); + } + if (string.Equals(appearance.RoleInSceneTypeName, "POV Character", StringComparison.OrdinalIgnoreCase) + || string.Equals(appearance.RoleInSceneTypeName, "Main Participant", StringComparison.OrdinalIgnoreCase)) + { + classes.Add("timeline-marker-important"); + } + if (HasStoryState(appearance)) + { + classes.Add("timeline-marker-state-change"); + } + return string.Join(' ', classes); + } + string CharacterMarkerTooltip(SceneCharacter appearance, Scene scene, SceneCharacter? firstAppearance, SceneCharacter? lastAppearance, IReadOnlyList characterWarnings) { var lines = new List { - CharacterMarkerMeaning(appearance), + CharacterMarkerMeaning(appearance, firstAppearance, lastAppearance), $"Character: {appearance.CharacterName}", $"Role: {(string.IsNullOrWhiteSpace(appearance.RoleInSceneTypeName) ? "Not set" : appearance.RoleInSceneTypeName)}", $"Presence: {(string.IsNullOrWhiteSpace(appearance.PresenceTypeName) ? "Not set" : appearance.PresenceTypeName)}", $"Scene: {scene.SceneNumber:g}: {scene.SceneTitle}" }; + if (!string.IsNullOrWhiteSpace(appearance.LocationPath) || !string.IsNullOrWhiteSpace(appearance.LocationName)) + { + lines.Add($"Location: {appearance.LocationPath ?? appearance.LocationName}"); + } + if (!string.IsNullOrWhiteSpace(appearance.EntryLocationName)) + { + lines.Add($"Entry: {appearance.EntryLocationName}"); + } + if (!string.IsNullOrWhiteSpace(appearance.ExitLocationName)) + { + lines.Add($"Exit: {appearance.ExitLocationName}"); + } + if (!string.IsNullOrWhiteSpace(appearance.EmotionalState)) + { + lines.Add($"Emotional state: {appearance.EmotionalState}"); + } + if (!string.IsNullOrWhiteSpace(appearance.PhysicalCondition)) + { + lines.Add($"Physical condition: {appearance.PhysicalCondition}"); + } + if (!string.IsNullOrWhiteSpace(appearance.KnowledgeNotes)) + { + lines.Add($"Knowledge: {appearance.KnowledgeNotes}"); + } + if (!string.IsNullOrWhiteSpace(appearance.AppearanceNotes)) + { + lines.Add($"Summary: {appearance.AppearanceNotes}"); + } + foreach (var warning in characterWarnings.Take(2)) + { + lines.Add($"Continuity: {warning.WarningTypeName} - {(string.IsNullOrWhiteSpace(warning.Details) ? warning.Message : warning.Details)}"); + } return string.Join(Environment.NewLine, lines); } bool HasLeadSceneRole(CharacterLaneViewModel lane) => lane.SceneSlots @@ -1169,8 +1329,10 @@ else
@foreach (var assetEvent in slot?.Events ?? Enumerable.Empty()) { - var assetMarkerTooltip = AssetMarkerTooltip(assetEvent, realAssetScene); - slot.Appearances) + .OrderBy(appearance => timelineColumns.FindIndex(column => column.Scene?.SceneID == appearance.SceneID)) + .ThenBy(appearance => appearance.SceneCharacterID) + .ToList(); + var firstAppearance = orderedLaneAppearances.FirstOrDefault(); + var lastAppearance = orderedLaneAppearances.LastOrDefault();
@lane.Character.CharacterName @@ -1244,8 +1413,10 @@ else diff --git a/PlotLine/bundleconfig.json b/PlotLine/bundleconfig.json index dc8235a..a7d50ab 100644 --- a/PlotLine/bundleconfig.json +++ b/PlotLine/bundleconfig.json @@ -16,5 +16,11 @@ "inputFiles": [ "wwwroot/js/site.js" ] + }, + { + "outputFileName": "wwwroot/js/word-companion-host.min.js", + "inputFiles": [ + "wwwroot/js/word-companion-host.js" + ] } ] diff --git a/PlotLine/wwwroot/css/site.css b/PlotLine/wwwroot/css/site.css index a8ab7ed..1823152 100644 --- a/PlotLine/wwwroot/css/site.css +++ b/PlotLine/wwwroot/css/site.css @@ -1454,6 +1454,35 @@ body.timeline-inspector-resizing { background: #dfd6f7; } +.asset-marker.timeline-marker-story-turn, +.character-marker.timeline-marker-story-turn { + border-width: 2px; +} + +.asset-marker.timeline-marker-important, +.character-marker.timeline-marker-important { + box-shadow: inset 0 -3px 0 rgba(197, 139, 43, 0.36); +} + +.asset-marker.timeline-marker-state-change, +.character-marker.timeline-marker-state-change { + border-style: double; +} + +.asset-marker.timeline-marker-transfer { + box-shadow: inset 3px 0 0 rgba(47, 111, 99, 0.32); +} + +.character-marker.timeline-marker-exit { + opacity: 0.86; + border-style: dashed; +} + +.asset-marker.timeline-marker-has-warning, +.character-marker.timeline-marker-has-warning { + box-shadow: 0 0 0 2px rgba(179, 95, 59, 0.22); +} + .asset-events-section { margin-top: 16px; } diff --git a/PlotLine/wwwroot/js/word-companion-host.min.js b/PlotLine/wwwroot/js/word-companion-host.min.js new file mode 100644 index 0000000..2239eb6 --- /dev/null +++ b/PlotLine/wwwroot/js/word-companion-host.min.js @@ -0,0 +1,25 @@ +(()=>{const s={projectId:"plotdirector.word.projectId",bookId:"plotdirector.word.bookId",activeTab:"plotdirector.word.activeTab"},ye=new Set(["scene","links","structure","diagnostics"]),hh=document.querySelector(".word-companion-shell"),uf=[...document.querySelectorAll("[data-tab-button]")],ch=[...document.querySelectorAll("[data-tab-panel]")],pe=document.querySelector("[data-office-status]"),we=document.querySelector("[data-connection-status]"),be=document.querySelector("[data-summary-connection]"),ke=document.querySelector("[data-summary-project]"),de=document.querySelector("[data-summary-book]"),lt=document.querySelector("[data-project-select]"),b=document.querySelector("[data-book-select]"),ge=document.querySelector("[data-project-message]"),no=document.querySelector("[data-book-message]"),tu=document.querySelector("[data-refresh-current-scene]"),vi=document.querySelector("[data-refresh-document]"),to=document.querySelector("[data-current-chapter]"),io=document.querySelector("[data-current-scene]"),ro=document.querySelector("[data-current-word-count]"),uo=document.querySelector("[data-scene-tracking-status]"),fo=document.querySelector("[data-document-message]"),eo=document.querySelector("[data-sync-note]"),fr=document.querySelector("[data-document-outline]"),oi=document.querySelector("[data-analyse-manuscript-structure]"),ff=document.querySelector("[data-apply-structure-sync]"),lh=document.querySelector("[data-structure-preview-status]"),nr=document.querySelector("[data-structure-preview-results]"),yi=document.querySelector("[data-refresh-plotdirector-scene]"),oo=document.querySelector("[data-plotdirector-scene-status]"),ah=document.querySelector("[data-anchor-status]"),vh=document.querySelector("[data-anchor-book-id]"),yh=document.querySelector("[data-anchor-chapter-id]"),ph=document.querySelector("[data-anchor-scene-id]"),bt=document.querySelector("[data-attach-plotdirector-ids]"),so=document.querySelector("[data-plotdirector-scene-details]"),ho=document.querySelector("[data-plotdirector-scene-title]"),co=document.querySelector("[data-plotdirector-revision-status]"),lo=document.querySelector("[data-plotdirector-estimated-words]"),ef=document.querySelector("[data-plotdirector-actual-words]"),ao=document.querySelector("[data-plotdirector-blocked-status]"),sf=document.querySelector("[data-plotdirector-blocked-reason-row]"),hf=document.querySelector("[data-plotdirector-blocked-reason]"),kt=document.querySelector("[data-sync-scene-progress]"),wh=document.querySelector("[data-sync-word-count]"),cf=document.querySelector("[data-sync-plotdirector-count]"),bh=document.querySelector("[data-sync-last-synced]"),kh=document.querySelector("[data-sync-status]"),vo=document.querySelector("[data-writing-brief-block]"),yo=document.querySelector("[data-writing-brief]"),po=document.querySelector("[data-plotdirector-link-groups]"),er=document.querySelector("[data-character-chips]"),or=document.querySelector("[data-asset-chips]"),fy=document.querySelector("[data-location-chips]"),si=document.querySelector("[data-primary-location-select]"),dt=document.querySelector("[data-save-scene-links]"),dh=document.querySelector("[data-scene-links-status]"),wo=document.querySelector("[data-links-editing-scene]"),bo=document.querySelector("[data-chapter-create-link]"),gh=document.querySelector("[data-chapter-create-link-chapter]"),k=document.querySelector("[data-create-plotdirector-chapter]"),d=document.querySelector("[data-link-existing-chapter]"),nc=document.querySelector("[data-chapter-create-link-status]"),ko=document.querySelector("[data-scene-create-link]"),tc=document.querySelector("[data-create-link-chapter]"),ic=document.querySelector("[data-create-link-scene]"),g=document.querySelector("[data-create-plotdirector-scene]"),nt=document.querySelector("[data-link-existing-scene]"),rc=document.querySelector("[data-create-link-status]"),hi=document.querySelector("[data-link-existing-dialog]"),iu=document.querySelector("[data-link-scene-search]"),ru=document.querySelector("[data-link-scene-options]"),ot=document.querySelector("[data-link-selected-scene]"),uc=document.querySelector("[data-link-dialog-cancel]"),lf=document.querySelector("[data-link-dialog-status]"),gt=document.querySelector("[data-create-scene-dialog]"),fc=document.querySelector("[data-create-dialog-scene]"),ec=document.querySelector("[data-create-dialog-chapter]"),oc=document.querySelector("[data-create-dialog-confirm]"),sc=document.querySelector("[data-create-dialog-cancel]"),ci=document.querySelector("[data-link-existing-chapter-dialog]"),uu=document.querySelector("[data-link-chapter-search]"),fu=document.querySelector("[data-link-chapter-options]"),st=document.querySelector("[data-link-selected-chapter]"),hc=document.querySelector("[data-link-chapter-dialog-cancel]"),af=document.querySelector("[data-link-chapter-dialog-status]"),ni=document.querySelector("[data-create-chapter-dialog]"),cc=document.querySelector("[data-create-chapter-dialog-chapter]"),lc=document.querySelector("[data-create-chapter-dialog-book]"),ac=document.querySelector("[data-create-chapter-dialog-confirm]"),vc=document.querySelector("[data-create-chapter-dialog-cancel]"),ti=document.querySelector("[data-apply-structure-sync-dialog]"),vf=document.querySelector("[data-apply-structure-sync-summary]"),yc=document.querySelector("[data-apply-structure-sync-confirm]"),pc=document.querySelector("[data-apply-structure-sync-cancel]"),wc=document.querySelector("[data-resolve-project-id]"),bc=document.querySelector("[data-resolve-project-title]"),kc=document.querySelector("[data-resolve-book-id]"),dc=document.querySelector("[data-resolve-book-title]"),gc=document.querySelector("[data-resolve-detected-chapter]"),nl=document.querySelector("[data-resolve-detected-scene]"),tl=document.querySelector("[data-resolve-request-chapter]"),il=document.querySelector("[data-resolve-request-scene]"),rl=document.querySelector("[data-resolve-result]"),ul=document.querySelector("[data-resolve-chapter-id]"),fl=document.querySelector("[data-resolve-scene-id]"),pi=document.querySelector("[data-run-diagnostics]"),el=document.querySelector("[data-diagnostic-host]"),ol=document.querySelector("[data-diagnostic-platform]"),sl=document.querySelector("[data-diagnostic-ready]"),hl=document.querySelector("[data-diagnostic-word-api]"),cl=document.querySelector("[data-diagnostic-last-scan]"),ll=document.querySelector("[data-diagnostic-last-error]"),al=document.querySelector("[data-diagnostic-anchor-type]"),vl=document.querySelector("[data-diagnostic-stored-scene-id]"),yl=document.querySelector("[data-diagnostic-stored-chapter-id]"),pl=document.querySelector("[data-diagnostic-resolution-method]"),wl=document.querySelector("[data-diagnostic-paragraphs]"),bl=document.querySelector("[data-diagnostic-heading1]"),kl=document.querySelector("[data-diagnostic-heading2]"),yf=hh?.dataset.authenticated==="true";let tr=[],li=[],at=!1,rt=!1,eu="Unknown",ou="Unknown",c="",y="",sr=null,su=null,o=null,l=null,r=null,u=null,hr="",ii="Title Match",ut=!1,pf=[],cr=null,hu=null,wf=[],lr=null,cu=null,vt=null,ar=!1,lu=null,bf="Manual",tt=!1,kf=null,df=!1,gf=!1,au="",ne="",yt={characters:[],assets:[],locations:[],primaryLocationId:null};const te=n=>{pe&&(pe.textContent=n)},dl=n=>{try{return window.localStorage.getItem(n)||""}catch{return""}},gl=(n,t)=>{try{t?window.localStorage.setItem(n,String(t)):window.localStorage.removeItem(n)}catch{}},go=(n,t=true)=>{const i=ye.has(n)&&uf.some(t=>t.dataset.tabButton===n)?n:"scene";for(const n of uf){const t=n.dataset.tabButton===i;n.classList.toggle("is-active",t);n.setAttribute("aria-selected",t?"true":"false")}for(const n of ch){const t=n.dataset.tabPanel===i;n.classList.toggle("is-active",t);n.hidden=!t}t&&gl(s.activeTab,i)},na=()=>{const n=dl(s.activeTab);go(ye.has(n)?n:"scene",!1)},ns=n=>{we&&(we.textContent=n),be&&(be.textContent=n)},ie=n=>{ge&&(ge.textContent=n)},vr=n=>{no&&(no.textContent=n)},t=n=>{fo&&(fo.textContent=n)},ir=n=>{oo&&(oo.textContent=n)},re=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("anchorType")&&n(al,f(t.anchorType));i("storedSceneId")&&n(vl,f(t.storedSceneId));i("storedChapterId")&&n(yl,f(t.storedChapterId));i("resolutionMethod")&&n(pl,f(t.resolutionMethod))},ri=()=>{const i=e(),f=Number.isInteger(r)&&r>0&&l===r,s=!Number.isInteger(u)||u<=0||o===u,t=f&&s;n(ah,t?"Attached to PlotDirector":"Not attached");n(vh,i?.bookId?String(i.bookId):"-");n(yh,Number.isInteger(u)&&u>0?String(u):"-");n(ph,Number.isInteger(r)&&r>0?String(r):"-");bt&&(bt.disabled=!r||t&&!ut,bt.textContent=l&&!t?"Reattach PlotDirector IDs":"Attach PlotDirector IDs");re({anchorType:ii||"Title Match",storedSceneId:l,storedChapterId:o,resolutionMethod:hr})},yr=(t,i,r,u=null,f=null,e=null)=>{c=t||"",y=i||"",sr=Number.isInteger(r)?r:null,su=Number.isInteger(e)&&e>0?e:null,o=Number.isInteger(u)&&u>0?u:null,l=Number.isInteger(f)&&f>0?f:null,to&&(to.textContent=t||"Not detected"),io&&(io.textContent=i||"Not detected"),ro&&(ro.textContent=Number.isInteger(r)?String(r):"-"),n(wh,Number.isInteger(r)?String(r):"-"),ri()},it=(n,t)=>{n&&(n.hidden=t)},rr=t=>{n(kh,t)},ui=t=>{n(lh,t)},ur=(n="Select a project and book to analyse manuscript structure.")=>{if(vt=null,nr){nr.innerHTML="";const n=document.createElement("p");n.textContent="No preview generated.";nr.append(n)}ui(n);vu()},ta=(n=vt)=>as.flatMap(t=>Array.isArray(n?.[t.key])?n[t.key]:[]),wi=(n=vt)=>ta(n).filter(n=>n.category==="couldLink"||n.category==="wouldCreateChapters"||n.category==="wouldCreateScenes"),vu=()=>{ff&&(ff.disabled=ar||wi().length===0)},yu=()=>{oi&&(oi.disabled=ar||!kr()||!e()),vu()},ue=()=>{wo&&(wo.textContent=r?`Editing links for: ${au||y||"Current scene"}`:"Link a PlotDirector scene first.")},ts=()=>{const n=tt||!r;kt&&(kt.disabled=n);dt&&(dt.disabled=n);si&&(si.disabled=n);for(const t of[er,or])for(const i of t?[...t.querySelectorAll("input[type='checkbox']")]:[])i.disabled=n},pt=t=>{(t==="Live"||t==="Manual")&&(bf=t),n(uo,t||bf||"Manual")},fi=(i,r="")=>{tt=!!i,n(uo,tt?"Stale":bf),ts(),r&&(t(r),bi(r))},ai=(n,t=null,i="")=>{r=Number.isInteger(n)&&n>0?n:null,u=Number.isInteger(t)&&t>0?t:null,hr=i||"",ts(),rr(tt?"Refresh Current Scene before syncing.":r?"Ready to sync.":"No resolved PlotDirector scene."),bi(tt?"Refresh Current Scene before saving.":r?"Ready to save.":"Link a PlotDirector scene first."),ue(),ri()},is=n=>{tu&&(tu.disabled=n,tu.textContent=n?"Refreshing...":"Refresh Current Scene")},f=n=>n===null||n===undefined||n===""?"-":String(n),bi=t=>{n(dh,t)},ki=t=>{n(rc,t)},wt=t=>{n(nc,t)},fe=()=>!!e()&&!!c&&!u,ee=()=>!!e()&&!!y&&Number.isInteger(u)&&u>0,pr=()=>{it(bo,!0),wt(""),k&&(k.disabled=!0,k.textContent="Create Chapter in PlotDirector"),d&&(d.disabled=!0,d.textContent="Link to Existing Chapter")},pu=(t="")=>{n(gh,f(c));it(bo,!1);wt(t);const i=fe();k&&(k.disabled=!i,k.textContent="Create Chapter in PlotDirector");d&&(d.disabled=!i,d.textContent="Link to Existing Chapter")},wu=()=>{it(ko,!0),ki(""),g&&(g.disabled=!0,g.textContent="Create Scene in PlotDirector"),nt&&(nt.disabled=!0,nt.textContent="Link to Existing Scene")},wr=(t="")=>{n(tc,f(c));n(ic,f(y));it(ko,!1);ki(t);const i=ee();g&&(g.disabled=!i,g.textContent="Create Scene in PlotDirector");nt&&(nt.disabled=!i,nt.textContent="Link to Existing Scene")},v=t=>{ir(t),it(so,!0),it(vo,!0),it(po,!1),pr(),wu(),hr="",au="",ne="",ii=l?"SceneID Anchor":o?"ChapterID Anchor":"Title Match",ut=!1,yt={characters:[],assets:[],locations:[],primaryLocationId:null},ku(er,[],"character"),ku(or,[],"asset"),rs([],null,!1),ai(null),n(cf,"-"),n(ho,"-"),n(co,"-"),n(lo,"-"),n(ef,"-"),n(ao,"-"),n(hf,"-"),it(sf,!0),ri(),ue()},bu=(n,t)=>t==="asset"?n?.assetId||n?.AssetId||n?.storyAssetId||n?.StoryAssetId||0:t==="location"?n?.locationId||n?.LocationId||0:n?.characterId||n?.CharacterId||0,ku=(n,t,i,r=false)=>{if(n){n.innerHTML="";const u=Array.isArray(t)?t:[];if(u.length===0){const t=document.createElement("p");t.className="word-companion-empty-list";t.textContent="None";n.append(t);return}for(const t of u){const f=Number.parseInt(bu(t,i),10);if(Number.isInteger(f)&&!(f<=0)){const e=document.createElement("label");e.className="word-companion-check-item";const u=document.createElement("input");u.type="checkbox";u.value=String(f);u.checked=!!t.linked;u.disabled=!r;const o=document.createElement("span");o.textContent=t.name||"Unnamed";e.append(u,o);n.append(e)}}}},rs=(n,t,i=false)=>{if(si){si.innerHTML="";const r=document.createElement("option");r.value="";r.textContent="None";si.append(r);const u=Number.parseInt(t||"",10);for(const t of Array.isArray(n)?n:[]){const n=Number.parseInt(bu(t,"location"),10);if(Number.isInteger(n)&&!(n<=0)){const i=document.createElement("option");i.value=String(n);i.textContent=t.name||"Unnamed";i.selected=n===u;si.append(i)}}si.disabled=!i}},ia=t=>{au=t?.sceneTitle||y||"",ne=t?.chapterTitle||c||"",n(ho,f(t?.sceneTitle)),n(co,f(t?.revisionStatus||t?.revisionStatusName||"Not provided")),n(lo,f(t?.estimatedWords)),n(ef,f(t?.actualWords)),n(cf,f(t?.actualWords)),n(ao,t?.blocked?"Blocked":"Not blocked"),t?.blockedReason?(n(hf,t.blockedReason),it(sf,!1)):(n(hf,"-"),it(sf,!0)),yo&&(yo.textContent=t?.writingBrief||"No writing brief has been added for this scene."),yt={characters:Array.isArray(t?.characters)?t.characters:[],assets:Array.isArray(t?.assets)?t.assets:[],locations:Array.isArray(t?.locations)?t.locations:[],primaryLocationId:t?.primaryLocationId??null},ku(er,yt.characters,"character",!!r&&!tt),ku(or,yt.assets,"asset",!!r&&!tt),rs(yt.locations,yt.primaryLocationId,!!r&&!tt),ue(),bi(tt?"Refresh Current Scene before saving.":r?"Ready to save.":"No resolved PlotDirector scene."),it(so,!1),it(vo,!1),it(po,!1)},di=n=>String(n||"").trim().replace(/\s+/g," "),a=(n,t)=>{const i=di(n);if(!i)return"";const r=t==="scene"?"scene":"chapter",u=new RegExp(`^${r}\\s+${"(?:\\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)"}\\s*(?::|-|\\u2013|\\u2014)\\s*`,"i"),f=di(i.replace(u,""));return f||i},w=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("projectId")&&n(wc,f(t.projectId));i("projectTitle")&&n(bc,f(t.projectTitle));i("bookId")&&n(kc,f(t.bookId));i("bookTitle")&&n(dc,f(t.bookTitle));i("detectedChapter")&&n(gc,f(t.detectedChapter));i("detectedScene")&&n(nl,f(t.detectedScene));i("requestChapter")&&n(tl,f(t.requestChapter));i("requestScene")&&n(il,f(t.requestScene));i("result")&&n(rl,f(t.result));i("chapterId")&&n(ul,f(t.chapterId));i("sceneId")&&n(fl,f(t.sceneId))},ra=async(n,t)=>{const i=await ct(`/api/word-companion/books/${n}/structure`),r=Array.isArray(i?.chapters)?i.chapters:[];for(const n of r){const r=Array.isArray(n.scenes)?n.scenes:[],i=r.find(n=>n.sceneId===t);if(i)return i.revisionStatus||""}return""},ua=async(n,t)=>{const i=await ct(`/api/word-companion/books/${n}/structure`),r=Array.isArray(i?.chapters)?i.chapters:[];for(const n of r){const i=Array.isArray(n.scenes)?n.scenes:[];for(const r of i)if(t(n,r))return{chapter:n,scene:r}}return null},oe=async n=>{const t=await ct(`/api/word-companion/books/${n}/structure`);return Array.isArray(t?.chapters)?t.chapters:[]},us=async n=>{const t=await ct(`/api/word-companion/books/${n}/chapters`);return Array.isArray(t?.chapters)?t.chapters:[]},fs=n=>{if(Number.isInteger(u)&&u>0){const t=n.find(n=>n.chapterId===u);if(t)return t}const t=a(c,"chapter").toLocaleLowerCase();return t?n.find(n=>a(n.title,"chapter").toLocaleLowerCase()===t)||null:null},es=async()=>{const n=e();return n?fs(await oe(n.bookId)):null},du=async(n,i,r,u,f)=>{const e=await ct(`/api/word-companion/scenes/${i}/companion`);try{e.revisionStatus=await ra(n,i)}catch{e.revisionStatus=""}ii=f||"Title Match";ut=!1;fi(!1);ir("Linked to PlotDirector");t("");pr();wu();ai(i,r,u);ia(e)},n=(n,t)=>{n&&(n.textContent=t)},i=t=>{const i=n=>Object.prototype.hasOwnProperty.call(t,n);i("host")&&n(el,t.host);i("platform")&&n(ol,t.platform);i("ready")&&n(sl,t.ready);i("wordApi")&&n(hl,t.wordApi);i("lastScan")&&n(cl,t.lastScan);i("lastError")&&n(ll,t.lastError);i("paragraphs")&&n(wl,t.paragraphs);i("heading1")&&n(bl,t.heading1);i("heading2")&&n(kl,t.heading2)},h=n=>{const t=[];return n?.name&&t.push(n.name),n?.code&&n.code!==n.name&&t.push(n.code),n?.message&&t.push(n.message),n?.debugInfo?.errorLocation&&t.push(`Location: ${n.debugInfo.errorLocation}`),t.length>0?t.join(": "):String(n)},os=async()=>{if(!window.Office||typeof window.Office.onReady!="function")return at=!1,rt=!1,eu="Unavailable",ou="Unavailable",i({host:eu,platform:ou,ready:"No",wordApi:"No"}),null;const n=await window.Office.onReady();return at=!0,eu=n?.host||"Unknown",ou=n?.platform||"Unknown",rt=!!window.Word&&!!window.Office.HostType&&n?.host===window.Office.HostType.Word,i({host:eu,platform:ou,ready:"Yes",wordApi:rt?"Yes":"No"}),n},ss=n=>{try{const i=window.localStorage.getItem(n),t=Number.parseInt(i||"",10);return Number.isInteger(t)&&t>0?t:null}catch{return null}},p=(n,t)=>{try{t?window.localStorage.setItem(n,String(t)):window.localStorage.removeItem(n)}catch{}},ht=(n,t)=>{if(n){n.innerHTML="";const i=document.createElement("option");i.value="";i.textContent=t;n.append(i);n.disabled=!0}},hs=(n,t,i,r,u)=>{if(n){n.innerHTML="";const f=document.createElement("option");f.value="";f.textContent=t;n.append(f);for(const t of i){const i=document.createElement("option");i.value=String(t[r]);i.textContent=t[u];n.append(i)}n.disabled=i.length===0}},br=n=>{const t=String(n?.title||"").trim(),i=String(n?.subtitle||"").trim();return i?`${t}: ${i}`:t},kr=()=>{const n=Number.parseInt(lt?.value||"",10);return tr.find(t=>t.projectId===n)||null},e=()=>{const n=Number.parseInt(b?.value||"",10);return li.find(t=>t.bookId===n)||null},ei=()=>{const t=kr(),n=e();ke&&(ke.textContent=t?.title||"(Not connected)");de&&(de.textContent=n?br(n):"(Not connected)");eo&&(eo.textContent=n?"":"Select a PlotDirector book before refreshing.");yu()},se=n=>{const t=n?.styleBuiltIn||n?.style||"";return String(t).replace(/\s+/g,"").toLowerCase()},gu=(n,t)=>{const i=se(n);return i===`heading${t}`||i.endsWith(`.heading${t}`)||i.includes(`heading${t}`)},fa=n=>{const t=String(n||"").trim().split(/\s+/).filter(Boolean);return t.length},ea=(n,t)=>String(n?.text||"").trim()===String(t?.text||"").trim()&&se(n)===se(t),cs=(n,t)=>{const r=String(n||"").match(new RegExp(`^${t}-(\\d+)$`,"i"));if(!r)return null;const i=Number.parseInt(r[1],10);return Number.isInteger(i)&&i>0?i:null},ls=(n,t)=>{const i=Array.isArray(n?.contentControls?.items)?n.contentControls.items:[];for(const n of i){const i=cs(n.tag,t);if(i)return i}return null},oa=(n,t)=>{const u=[];let o=0,s=0,i=null,r=null;n.forEach((n,t)=>{const f=String(n.text||"").trim();if(f){if(gu(n,1)){o+=1;i={index:u.length+1,paragraphIndex:t,title:f,anchorId:ls(n,"PD-CHAPTER"),scenes:[]};u.push(i);r=null;return}if(gu(n,2)){if(s+=1,!i)return;r={index:i.scenes.length+1,paragraphIndex:t,title:f,anchorId:ls(n,"PD-SCENE"),wordCount:0};i.scenes.push(r);return}r&&(r.wordCount+=fa(f))}});const h=t.find(n=>String(n.text||"").trim()),f=h?n.findIndex(n=>ea(n,h)):-1,e=f>=0?u.filter(n=>n.paragraphIndex<=f).at(-1)||null:null,c=e&&f>=0?e.scenes.filter(n=>n.paragraphIndex<=f).at(-1)||null:null;return{chapters:u,currentChapter:e,currentScene:c,paragraphCount:n.length,heading1Count:o,heading2Count:s}},he=n=>{if(fr){if(fr.innerHTML="",n.chapters.length===0){const n=document.createElement("p");n.textContent="No chapters detected. Use Heading 1 for chapter titles.";fr.append(n);return}const t=n.chapters.some(n=>n.scenes.length>0);if(!t){const n=document.createElement("p");n.textContent="No scenes detected. Use Heading 2 for scene titles.";fr.append(n)}for(const t of n.chapters){const n=document.createElement("div");n.className="word-companion-outline-chapter";const i=document.createElement("strong");if(i.textContent=t.title,n.append(i),t.scenes.length>0){const i=document.createElement("ul");for(const n of t.scenes){const t=document.createElement("li");t.textContent=n.title;i.append(t)}n.append(i)}fr.append(n)}}},as=[{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"}],sa={alreadyLinked:"Already Linked",couldLink:"Could Link",wouldCreateChapter:"Would Create Chapter",wouldCreateScene:"Would Create Scene",manualReview:"Manual Review Required"},ha={alreadyLinked:"✓",couldLink:"~",wouldCreateChapter:"+",wouldCreateScene:"+",manualReview:"?"},nf=(n,t)=>a(n,t).toLocaleLowerCase(),ft=({category:i,action:n,type:s,wordTitle:l,match:r="",anchorStatus:t="None",matches:u=[],pdChapter:e=null,pdScene:o=null,wordChapter:h=null,wordScene:c=null,parentItem:f=null})=>({id:`${s}-${h?.index||0}-${c?.index||0}-${h?.paragraphIndex??c?.paragraphIndex??0}`,category:i,action:n,type:s,wordTitle:l,match:r,anchorStatus:t,matches:u,pdChapter:e,pdScene:o,wordChapter:h,wordScene:c,parentItem:f,result:"Pending",error:""}),et=(n,t)=>{Array.isArray(n[t.category])&&n[t.category].push(t)},ce=n=>Array.isArray(n?.scenes)?n.scenes:[],ca=(n,t)=>{for(const i of n){const n=ce(i).find(n=>n.sceneId===t);if(n)return{chapter:i,scene:n}}return null},la=(n,t,i)=>{const u=n.anchorId?`PD-CHAPTER-${n.anchorId}`:"None";if(n.anchorId){const r=t.find(t=>t.chapterId===n.anchorId);if(r){const t=ft({category:"alreadyLinked",action:"alreadyLinked",type:"Chapter",wordTitle:n.title,match:`Chapter ${r.chapterId}: ${r.title}`,anchorStatus:u,pdChapter:r,wordChapter:n});return et(i,t),t}const f=ft({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:n.title,anchorStatus:`${u} not found`,matches:[],pdChapter:null,wordChapter:n});return et(i,f),f}const r=t.filter(t=>nf(t.title,"chapter")===nf(n.title,"chapter"));if(r.length===1){const t=ft({category:"couldLink",action:"couldLink",type:"Chapter",wordTitle:n.title,match:`Chapter ${r[0].chapterId}: ${r[0].title}`,anchorStatus:u,pdChapter:r[0],wordChapter:n});return et(i,t),t}if(r.length>1){const t=ft({category:"manualReview",action:"manualReview",type:"Chapter",wordTitle:n.title,anchorStatus:u,matches:r.map(n=>`Chapter ${n.chapterId}: ${n.title}`),pdChapter:null,wordChapter:n});return et(i,t),t}const f=ft({category:"wouldCreateChapters",action:"wouldCreateChapter",type:"Chapter",wordTitle:n.title,anchorStatus:u,pdChapter:null,wordChapter:n});return et(i,f),f},aa=(n,t,i,r)=>{const u=n.anchorId?`PD-SCENE-${n.anchorId}`:"None";if(n.anchorId){const f=ca(i,n.anchorId);if(f){et(r,ft({category:"alreadyLinked",action:"alreadyLinked",type:"Scene",wordTitle:n.title,match:`Scene ${f.scene.sceneId}: ${f.scene.title}`,anchorStatus:u,pdChapter:f.chapter,pdScene:f.scene,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}et(r,ft({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:`${u} not found`,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}if(!t?.pdChapter&&t?.category==="manualReview"){et(r,ft({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:u,matches:["Parent chapter requires manual review."],wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}if(!t?.pdChapter){et(r,ft({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:n.title,anchorStatus:u,wordChapter:t?.wordChapter,wordScene:n,parentItem:t}));return}const f=ce(t.pdChapter).filter(t=>nf(t.title,"scene")===nf(n.title,"scene"));if(f.length===1){et(r,ft({category:"couldLink",action:"couldLink",type:"Scene",wordTitle:n.title,match:`Scene ${f[0].sceneId}: ${f[0].title}`,anchorStatus:u,pdChapter:t.pdChapter,pdScene:f[0],wordChapter:t.wordChapter,wordScene:n,parentItem:t}));return}if(f.length>1){et(r,ft({category:"manualReview",action:"manualReview",type:"Scene",wordTitle:n.title,anchorStatus:u,matches:f.map(n=>`Scene ${n.sceneId}: ${n.title}`),wordChapter:t.wordChapter,wordScene:n,parentItem:t}));return}et(r,ft({category:"wouldCreateScenes",action:"wouldCreateScene",type:"Scene",wordTitle:n.title,anchorStatus:u,pdChapter:t.pdChapter,wordChapter:t.wordChapter,wordScene:n,parentItem:t}))},va=(n,t)=>{const i={alreadyLinked:[],couldLink:[],wouldCreateChapters:[],wouldCreateScenes:[],manualReview:[]},r=Array.isArray(t?.chapters)?t.chapters:[];for(const t of Array.isArray(n?.chapters)?n.chapters:[]){const n=la(t,r,i);for(const u of ce(t))aa(u,n,r,i)}return i},ya=n=>{const t=document.createElement("article");t.className="word-companion-preview-item";const i=document.createElement("strong");i.textContent=`${ha[n.action]||""} ${n.type}: ${n.wordTitle}`;t.append(i);const r=document.createElement("span");if(r.textContent=`Anchor: ${n.anchorStatus||"None"}`,t.append(r),n.match){const i=document.createElement("span");i.textContent=`Match: ${n.match}`;t.append(i)}if(Array.isArray(n.matches)&&n.matches.length>0){const i=document.createElement("div");i.className="word-companion-preview-matches";const r=document.createElement("span");r.textContent="Matches:";i.append(r);const u=document.createElement("ul");for(const t of n.matches){const n=document.createElement("li");n.textContent=t;u.append(n)}i.append(u);t.append(i)}const u=document.createElement("span");if(u.textContent=`Action: ${sa[n.action]||n.action}`,t.append(u),n.result&&n.result!=="Pending"){const i=document.createElement("span");i.textContent=n.error?`Result: ${n.result} - ${n.error}`:`Result: ${n.result}`;t.append(i)}return t},vs=n=>{if(nr){nr.innerHTML="";for(const t of as){const i=document.createElement("section");i.className="word-companion-preview-group";const r=document.createElement("strong");r.textContent=t.title;i.append(r);const u=Array.isArray(n?.[t.key])?n[t.key]:[];if(u.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="None";i.append(n)}else for(const n of u)i.append(ya(n));nr.append(i)}vu()}},gi=async n=>{const t=n.document.body.paragraphs,i=n.document.getSelection().paragraphs;t.load("text,styleBuiltIn,style");i.load("text,styleBuiltIn,style");await n.sync();for(const n of t.items)(gu(n,1)||gu(n,2))&&n.contentControls.load("items/tag,title");await n.sync();const r=oa(t.items,i.items);return r.bodyParagraphs=t.items,r},ys=async()=>{if(t(""),!at||!rt||!window.Word||typeof window.Word.run!="function")return yr(null,null,null),t("Word document access is unavailable."),i({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;vi&&(vi.disabled=!0,vi.textContent="Scanning...");t("Scanning document structure...");try{const n=await window.Word.run(async n=>await gi(n));return yr(n.currentChapter?.title,n.currentScene?.title,n.currentScene?.wordCount,n.currentChapter?.anchorId,n.currentScene?.anchorId,n.currentChapter?.index),v("Not detected"),he(n),t(""),i({lastScan:"Success",lastError:"-",paragraphs:String(n.paragraphCount),heading1:String(n.heading1Count),heading2:String(n.heading2Count)}),!0}catch(n){const r=h(n);return console.error("Unable to scan the Word document.",n),yr(null,null,null),t(`Unable to scan the Word document: ${r}`),i({lastScan:"Failure",lastError:r}),!1}finally{vi&&(vi.disabled=!1,vi.textContent="Refresh Document Structure")}},ps=async()=>{const n=e();if(!kr()||!n)return ui("Select a project and book to analyse manuscript structure."),!1;if(!at||!rt||!window.Word||typeof window.Word.run!="function")return ui("Word document access is unavailable."),i({lastScan:"Failure",lastError:"Word document access is unavailable."}),!1;oi&&(oi.disabled=!0,oi.textContent="Analysing...");ui("Analysing manuscript structure...");try{const t=await window.Word.run(async n=>await gi(n)),r=await ct(`/api/word-companion/books/${n.bookId}/structure`);return yr(t.currentChapter?.title,t.currentScene?.title,t.currentScene?.wordCount,t.currentChapter?.anchorId,t.currentScene?.anchorId,t.currentChapter?.index),he(t),vt=va(t,r),vs(vt),ui("Preview generated. No changes have been applied."),i({lastScan:"Success",lastError:"-",paragraphs:String(t.paragraphCount),heading1:String(t.heading1Count),heading2:String(t.heading2Count)}),!0}catch(t){return console.error("Unable to analyse manuscript structure.",t),ui("Unable to analyse manuscript structure."),i({lastScan:"Failure",lastError:h(t)}),!1}finally{oi&&(oi.textContent="Analyse Manuscript Structure",yu())}},pa=(n=vt)=>{const t=wi(n),i=t.filter(n=>n.category==="couldLink"&&n.type==="Chapter").length,r=t.filter(n=>n.category==="couldLink"&&n.type==="Scene").length,u=t.filter(n=>n.category==="wouldCreateChapters").length,f=t.filter(n=>n.category==="wouldCreateScenes").length,e=Array.isArray(n?.manualReview)?n.manualReview.length:0;return{linkChapters:i,linkScenes:r,createChapters:u,createScenes:f,manualReview:e}},wa=n=>{if(vf){vf.innerHTML="";const i=[`Link ${n.linkChapters+n.linkScenes} chapters/scenes`,`Create ${n.createChapters} chapters`,`Create ${n.createScenes} scenes`],t=document.createElement("ul");for(const n of i){const i=document.createElement("li");i.textContent=n;t.append(i)}vf.append(t)}},le=n=>{lu&&(lu(n),lu=null),ti?.close?ti.close():ti&&(ti.hidden=!0)},ba=()=>{const n=pa();return(wa(n),!ti)?Promise.resolve(window.confirm(`Apply Structure Sync? + +This will: + +- Link ${n.linkChapters+n.linkScenes} chapters/scenes +- Create ${n.createChapters} chapters +- Create ${n.createScenes} scenes + +Manual review items will be skipped.`)):new Promise(n=>{lu=n,ti.showModal?ti.showModal():ti.hidden=!1})},dr=(n,t,i="")=>{n.result=t,n.error=i},ws=n=>Number.isInteger(n?.wordChapter?.index)&&n.wordChapter.index>0?n.wordChapter.index*10:null,bs=n=>Number.isInteger(n?.wordScene?.index)&&n.wordScene.index>0?n.wordScene.index*10:null,ka=async(n,t)=>{const i=await gr(`/api/word-companion/books/${n}/chapters`,{title:di(t.wordTitle),sortOrder:ws(t)});if(!i?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");t.pdChapter={chapterId:i.chapterId,title:i.title||t.wordTitle,sortOrder:i.sortOrder||ws(t)||0,scenes:[]};t.match=`Chapter ${t.pdChapter.chapterId}: ${t.pdChapter.title}`},da=async(n,t)=>{const i=t.pdChapter||t.parentItem?.pdChapter;if(!i?.chapterId)throw new Error("Scene parent chapter is not available.");const r=await gr(`/api/word-companion/books/${n}/chapters/${i.chapterId}/scenes`,{sceneTitle:di(t.wordTitle),sortOrder:bs(t)});if(!r?.sceneId)throw new Error("Scene creation did not return a scene ID.");t.pdChapter=i;t.pdScene={sceneId:r.sceneId,title:t.wordTitle,sortOrder:bs(t)||0};t.match=`Scene ${t.pdScene.sceneId}: ${t.pdScene.title}`},ga=async n=>{if(!at||!rt||!window.Word||typeof window.Word.run!="function")throw new Error("Word document access is unavailable.");await window.Word.run(async t=>{const u=await gi(t),r=n.type==="Chapter"?n.wordChapter:n.wordScene,i=Number.isInteger(r?.paragraphIndex)?u.bodyParagraphs[r.paragraphIndex]:null;if(!i)throw new Error("Unable to locate the Word heading.");if(n.type==="Chapter"){const t=n.pdChapter?.chapterId;if(!t)throw new Error("Chapter ID is not available.");nu(i,"PlotDirector Chapter",`PD-CHAPTER-${t}`,"PD-CHAPTER")}else{const t=n.pdScene?.sceneId;if(!t)throw new Error("Scene ID is not available.");nu(i,"PlotDirector Scene",`PD-SCENE-${t}`,"PD-SCENE")}await t.sync()})},nv=n=>`Structure Sync Complete. Created: ${n.createdChapters} Chapters, ${n.createdScenes} Scenes. Linked: ${n.linkedChapters} Chapters, ${n.linkedScenes} Scenes. Skipped: ${n.skipped} Manual Review items. Failed: ${n.failed} Items.`,tv=async()=>{const r=e();if(!r||wi().length===0||ar){vu();return}const f=await ba();if(f){ar=!0;yu();ui("Applying structure sync...");const n={createdChapters:0,createdScenes:0,linkedChapters:0,linkedScenes:0,skipped:Array.isArray(vt?.manualReview)?vt.manualReview.length:0,failed:0},o=wi().filter(n=>n.category==="couldLink"&&n.type==="Chapter"),s=wi().filter(n=>n.category==="wouldCreateChapters"),c=wi().filter(n=>n.category==="couldLink"&&n.type==="Scene"),l=wi().filter(n=>n.category==="wouldCreateScenes"),u=[];let t="";const i=(n,t)=>{u.push({item:n,counterName:t})},a=async(t,i)=>{try{await ga(t);dr(t,"Success");n[i]+=1}catch(r){dr(t,"Failed",h(r));n.failed+=1}};try{for(const n of o)i(n,"linkedChapters");for(const t of s)try{await ka(r.bookId,t);i(t,"createdChapters")}catch(u){dr(t,"Failed",h(u));n.failed+=1}for(const n of c)i(n,"linkedScenes");for(const t of l)try{await da(r.bookId,t);i(t,"createdScenes")}catch(u){dr(t,"Failed",h(u));n.failed+=1}for(const n of u)await a(n.item,n.counterName);for(const n of vt.manualReview||[])dr(n,"Skipped");vs(vt);t=nv(n);ui(t)}finally{ar=!1;yu();t&&(await ps(),ui(`${t} Preview refreshed.`))}}},iv=async()=>{pi&&(pi.disabled=!0,pi.textContent="Running...");try{if(await os(),!at||!rt||!window.Word||typeof window.Word.run!="function"){i({lastScan:"Failure",lastError:"Word document access is unavailable.",paragraphs:"-",heading1:"-",heading2:"-"});return}const n=await window.Word.run(async n=>{const t=n.document.body.paragraphs;return t.load("items"),await n.sync(),t.items.length});i({lastScan:"Success",lastError:"-",paragraphs:String(n)})}catch(n){console.error("Word Companion diagnostics failed.",n);const r=h(n);i({lastScan:"Failure",lastError:r});t(`Unable to scan the Word document: ${r}`)}finally{pi&&(pi.disabled=!1,pi.textContent="Run Diagnostics")}},ct=async(n,t={})=>{const i=await window.fetch(n,{credentials:"same-origin",...t,headers:{Accept:"application/json",...(t.headers||{})}});if(!i.ok)throw new Error(`Request failed: ${i.status}`);return await i.json()},gr=(n,t)=>ct(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),rv=(n,t)=>ct(n,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),uv=(n,t)=>ct(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),tf=n=>n?[...n.querySelectorAll("input[type='checkbox']:checked")].map(n=>Number.parseInt(n.value||"",10)).filter(n=>Number.isInteger(n)&&n>0):[],ks=()=>{const n=Number.parseInt(si?.value||"",10);return Number.isInteger(n)&&n>0?n:null},fv=()=>{const n=new Set(tf(er)),t=new Set(tf(or));yt={characters:yt.characters.map(t=>({...t,linked:n.has(Number.parseInt(bu(t,"character"),10))})),assets:yt.assets.map(n=>({...n,linked:t.has(Number.parseInt(bu(n,"asset"),10))})),locations:yt.locations,primaryLocationId:ks()}},ev=async()=>{if(!r)return!1;if(!at||!rt||!window.Word||typeof window.Word.run!="function")return fi(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1;try{const n=await window.Word.run(async n=>await gi(n)),f=n.currentChapter?.title||"",e=n.currentScene?.title||"",t=n.currentScene?.anchorId||null,i=n.currentChapter?.anchorId||null,o=Number.isInteger(t)&&t===r,s=Number.isInteger(i)&&i===u,h=a(e,"scene").toLocaleLowerCase()===a(au||y,"scene").toLocaleLowerCase(),l=a(f,"chapter").toLocaleLowerCase()===a(ne||c,"chapter").toLocaleLowerCase(),v=o||h&&(s||l);return v?(fi(!1),!0):(fi(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1)}catch(n){return console.error("Unable to verify current Word scene before saving.",n),i({lastError:h(n)}),fi(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving."),!1}},ov=async()=>{if(!r){bi("Link a PlotDirector scene first.");return}if(tt||!await ev()){bi("The Word cursor is now in a different scene. Refresh Current Scene before saving.");return}dt&&(dt.disabled=!0,dt.textContent="Saving...");try{await uv(`/api/word-companion/scenes/${r}/links`,{characterIds:tf(er),assetIds:tf(or),locationIds:[],primaryLocationId:ks()});fv();bi("Scene links saved successfully.");i({lastError:"-"})}catch(n){bi("Unable to save scene links.");i({lastError:h(n)})}finally{dt&&(dt.disabled=!r||tt,dt.textContent="Save Scene Links")}},sv=(n,t)=>{const i=Array.isArray(n?.contentControls?.items)?n.contentControls.items:[];return i.find(n=>cs(n.tag,t))||null},nu=(n,t,i,r)=>{const f=sv(n,r),u=f||n.getRange().insertContentControl();return u.title=t,u.tag=i,u.appearance="Hidden",u},ds=async(n="PlotDirector IDs attached successfully.")=>{if(!r||!u)return t("No resolved PlotDirector scene."),!1;const e=l&&l!==r||o&&o!==u;if(e&&!window.confirm("This scene is already linked. Replace the existing PlotDirector link?"))return!1;if(!at||!rt||!window.Word||typeof window.Word.run!="function")return t("Word document access is unavailable."),!1;bt&&(bt.disabled=!0,bt.textContent="Attaching...");try{return await window.Word.run(async n=>{const t=await gi(n);if(!t.currentChapter||!t.currentScene)throw new Error("No scene detected in Word. Use Heading 2 for scenes.");const i=t.bodyParagraphs[t.currentChapter.paragraphIndex],f=t.bodyParagraphs[t.currentScene.paragraphIndex];if(!i||!f)throw new Error("Unable to locate the current Word headings.");nu(i,"PlotDirector Chapter",`PD-CHAPTER-${u}`,"PD-CHAPTER");nu(f,"PlotDirector Scene",`PD-SCENE-${r}`,"PD-SCENE");await n.sync()}),o=u,l=r,ut=!1,ii="SceneID Anchor",hr="Anchor",t(n),i({lastError:"-"}),ri(),!0}catch(f){return console.error("Unable to attach PlotDirector IDs.",f),t("Unable to attach PlotDirector IDs."),i({lastError:h(f)}),ri(),!1}finally{bt&&(bt.textContent=l===r?"Attach PlotDirector IDs":"Reattach PlotDirector IDs",ri())}},gs=async n=>{if(!u)return wt("No resolved PlotDirector chapter."),!1;if(!at||!rt||!window.Word||typeof window.Word.run!="function")return wt("Word document access is unavailable."),!1;try{return await window.Word.run(async n=>{const t=await gi(n);if(!t.currentChapter)throw new Error("No chapter detected in Word. Use Heading 1 for chapters.");const i=t.bodyParagraphs[t.currentChapter.paragraphIndex];if(!i)throw new Error("Unable to locate the current Word chapter heading.");nu(i,"PlotDirector Chapter",`PD-CHAPTER-${u}`,"PD-CHAPTER");await n.sync()}),o=u,ut=!1,ii="ChapterID Anchor",hr="Chapter anchor",wt(n),t(n),i({lastError:"-"}),ri(),!0}catch(r){return console.error("Unable to attach PlotDirector chapter ID.",r),wt("Unable to attach PlotDirector chapter ID."),i({lastError:h(r)}),ri(),!1}},hv=async()=>{await ds()},nh=async n=>{pr(),await rf(),t(n),wt(n)},ae=n=>{cu&&(cu(n),cu=null),ni?.close?ni.close():ni&&(ni.hidden=!0)},cv=(t,i)=>(n(cc,`"${t}"`),n(lc,`"${i}"`),!ni)?Promise.resolve(window.confirm(`Create PlotDirector chapter: + +"${t}" + +in book: + +"${i}" + +?`)):new Promise(n=>{cu=n,ni.showModal?ni.showModal():ni.hidden=!1}),lv=async()=>{const n=e();if(!n||!c||u){pu("Chapter not found in PlotDirector.");return}const t=di(c),r=await cv(t,br(n)||"selected book");if(r){k&&(k.disabled=!0,k.textContent="Creating...");try{const r=Number.isInteger(su)&&su>0?su*10:null,i=await gr(`/api/word-companion/books/${n.bookId}/chapters`,{title:t,sortOrder:r});if(!i?.chapterId)throw new Error("Chapter creation did not return a chapter ID.");ai(null,i.chapterId,"Manual chapter link");const u=await gs("Chapter created and linked successfully.");if(!u)return;await nh("Chapter created and linked successfully.")}catch(f){wt("Unable to create chapter.");i({lastError:h(f)})}finally{k&&(k.disabled=!fe(),k.textContent="Create Chapter in PlotDirector")}}},th=()=>{if(fu){const n=di(uu?.value||"").toLocaleLowerCase(),t=wf.filter(t=>!n||String(t.title||"").toLocaleLowerCase().includes(n));if(fu.innerHTML="",lr=null,st&&(st.disabled=!0),t.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="No chapters found.";fu.append(n);return}for(const n of t){const i=Number.parseInt(n.chapterId||"",10);if(Number.isInteger(i)&&!(i<=0)){const r=document.createElement("label");r.className="word-companion-scene-option";const t=document.createElement("input");t.type="radio";t.name="word-companion-link-chapter";t.value=String(i);t.addEventListener("change",()=>{lr=i,st&&(st.disabled=!1)});const u=document.createElement("span");u.textContent=n.title||"Untitled chapter";r.append(t,u);fu.append(r)}}}},av=async()=>{const t=e();if(!t||!c||u){pu("Chapter not found in PlotDirector.");return}d&&(d.disabled=!0,d.textContent="Loading...");try{wf=await us(t.bookId);lr=null;uu&&(uu.value="");n(af,"");th();ci?.showModal?ci.showModal():ci&&(ci.hidden=!1)}catch(r){wt("Unable to load chapters.");i({lastError:h(r)})}finally{d&&(d.disabled=!fe(),d.textContent="Link to Existing Chapter")}},ih=()=>{ci?.close?ci.close():ci&&(ci.hidden=!0)},vv=async()=>{const t=wf.find(n=>n.chapterId===lr);if(!t){n(af,"Select a chapter.");return}st&&(st.disabled=!0,st.textContent="Linking...");try{ai(null,t.chapterId,"Manual chapter link");const n=await gs("Chapter linked successfully.");if(!n)return;ih();await nh("Chapter linked successfully.")}catch(r){n(af,"Unable to link chapter.");wt("Unable to link chapter.");i({lastError:h(r)})}finally{st&&(st.disabled=!lr,st.textContent="Link Chapter")}},rh=async(n,t,i)=>{const r=e();if(!r)return ki("Select a PlotDirector book first."),!1;await du(r.bookId,n,t,"Manual link","Title Match");const u=await ds(i);return u?(ki(i),wu(),!0):!1},ve=n=>{hu&&(hu(n),hu=null),gt?.close?gt.close():gt&&(gt.hidden=!0)},yv=(t,i)=>(n(fc,`"${t}"`),n(ec,`"${i}"`),!gt)?Promise.resolve(window.confirm(`Create PlotDirector scene: + +"${t}" + +within chapter: + +"${i}" + +?`)):new Promise(n=>{hu=n,gt.showModal?gt.showModal():gt.hidden=!1}),pv=async()=>{const n=e();if(!n||!y){wr("Scene not found in PlotDirector.");return}const t=a(y,"scene"),r=a(c,"chapter"),u=await yv(t,r);if(u){g&&(g.disabled=!0,g.textContent="Creating...");try{const r=await es();if(!r){wr("This chapter does not exist in PlotDirector. Create or link the chapter first.");return}const i=await gr(`/api/word-companion/books/${n.bookId}/chapters/${r.chapterId}/scenes`,{sceneTitle:t});if(!i?.sceneId||!i?.chapterId)throw new Error("Scene creation did not return a scene ID.");await rh(i.sceneId,i.chapterId,"Scene created and linked successfully.")}catch(f){ki("Unable to create scene.");i({lastError:h(f)})}finally{g&&(g.disabled=!ee(),g.textContent="Create Scene in PlotDirector")}}},uh=()=>{if(ru){const n=di(iu?.value||"").toLocaleLowerCase(),t=pf.filter(t=>!n||String(t.title||"").toLocaleLowerCase().includes(n));if(ru.innerHTML="",cr=null,ot&&(ot.disabled=!0),t.length===0){const n=document.createElement("p");n.className="word-companion-empty-list";n.textContent="No scenes found.";ru.append(n);return}for(const n of t){const i=Number.parseInt(n.sceneId||"",10);if(Number.isInteger(i)&&!(i<=0)){const r=document.createElement("label");r.className="word-companion-scene-option";const t=document.createElement("input");t.type="radio";t.name="word-companion-link-scene";t.value=String(i);t.addEventListener("change",()=>{cr=i,ot&&(ot.disabled=!1)});const u=document.createElement("span");u.textContent=n.title||"Untitled scene";r.append(t,u);ru.append(r)}}}},wv=async()=>{const t=e();if(!t||!y){wr("Scene not found in PlotDirector.");return}nt&&(nt.disabled=!0,nt.textContent="Loading...");try{const r=await oe(t.bookId),i=fs(r);if(!i){wr("This chapter does not exist in PlotDirector. Create or link the chapter first.");return}pf=Array.isArray(i.scenes)?i.scenes:[];cr=null;iu&&(iu.value="");n(lf,"");uh();hi?.showModal?hi.showModal():hi&&(hi.hidden=!1)}catch(r){ki("Unable to load scenes.");i({lastError:h(r)})}finally{nt&&(nt.disabled=!ee(),nt.textContent="Link to Existing Scene")}},fh=()=>{hi?.close?hi.close():hi&&(hi.hidden=!0)},bv=async()=>{const r=e(),t=pf.find(n=>n.sceneId===cr);if(!r||!t){n(lf,"Select a scene.");return}ot&&(ot.disabled=!0,ot.textContent="Linking...");try{const n=await es();if(!n)throw new Error("This chapter does not exist in PlotDirector. Create or link the chapter first.");fh();await rh(t.sceneId,n.chapterId,"Scene linked successfully.")}catch(u){n(lf,"Unable to link scene.");ki("Unable to link scene.");i({lastError:h(u)})}finally{ot&&(ot.disabled=!cr,ot.textContent="Link Scene")}},kv=async()=>{if(!r){rr("No resolved PlotDirector scene.");return}if(tt){rr("Refresh Current Scene before syncing.");return}if(!Number.isInteger(sr)){rr("Unable to sync progress.");return}kt&&(kt.disabled=!0,kt.textContent="Syncing...");const t=(new Date).toISOString();try{const i=await rv(`/api/word-companion/scenes/${r}/word-count`,{actualWordCount:sr,lastWorkedOn:t});n(cf,f(i?.actualWords??sr));n(ef,f(i?.actualWords??sr));n(bh,(new Date).toLocaleString());rr("Progress synced successfully.")}catch{rr("Unable to sync progress.")}finally{kt&&(kt.disabled=!r||tt,kt.textContent="Sync Progress")}},eh=async()=>{const r=kr(),n=e(),u=a(c,"chapter");if(w({projectId:r?.projectId,projectTitle:r?.title,bookId:n?.bookId,bookTitle:n?br(n):undefined,detectedChapter:c,detectedScene:y,requestChapter:u,requestScene:"",result:"Not run",chapterId:null,sceneId:null}),!n)return v("Not detected"),t("Select a PlotDirector book first."),!1;if(!c)return v("Not detected"),t("No chapter detected in Word. Use Heading 1 for chapters."),!1;v("Not detected");try{const f=await us(n.bookId),i=o?f.find(n=>n.chapterId===o):null,e=u.toLocaleLowerCase(),s=e?f.find(n=>a(n.title,"chapter").toLocaleLowerCase()===e):null,r=i||s;return r?(pr(),ai(null,r.chapterId,i?"Chapter anchor":"Chapter title"),ii=i?"ChapterID Anchor":"Title Match",ir("Chapter linked to PlotDirector"),t("No scene detected in Word. Use Heading 2 for scenes."),w({result:"Chapter matched",chapterId:r.chapterId,sceneId:null}),!0):(ai(null),ir("Chapter not found in PlotDirector."),t("Chapter not found in PlotDirector."),w({result:"Chapter not matched",chapterId:null,sceneId:null}),pu("Chapter not found in PlotDirector."),!1)}catch(f){return v("Not found in PlotDirector"),i({lastError:h(f)}),t("Unable to load PlotDirector chapter data."),!1}},rf=async()=>{const f=kr(),n=e(),s=a(c,"chapter"),r=a(y,"scene");if(w({projectId:f?.projectId,projectTitle:f?.title,bookId:n?.bookId,bookTitle:n?br(n):undefined,detectedChapter:c,detectedScene:y,requestChapter:s,requestScene:r,result:"Not run",chapterId:null,sceneId:null}),re({anchorType:l?"SceneID Anchor":o?"ChapterID Anchor":"Title Match",storedSceneId:l,storedChapterId:o,resolutionMethod:"-"}),!n)return v("Not detected"),t("Select a PlotDirector book first."),w({result:"Error"}),!1;if(!c||!y)return v("Not detected"),t("No scene detected in Word. Use Heading 2 for scenes."),w({result:"Error"}),!1;yi&&(yi.disabled=!0,yi.textContent="Refreshing...");const p=()=>{yi&&(yi.disabled=!1,yi.textContent="Refresh PlotDirector Scene")};v("Not detected");t("Resolving PlotDirector scene...");try{if(l){const i=await ua(n.bookId,(n,t)=>t.sceneId===l);if(i)return w({result:"Matched",chapterId:i.chapter.chapterId,sceneId:i.scene.sceneId}),await du(n.bookId,i.scene.sceneId,i.chapter.chapterId,"Anchor","SceneID Anchor"),!0;ut=!0;ii="SceneID Anchor";ir("Not found in PlotDirector");t("Stored PlotDirector ID is invalid.");w({result:"Error",chapterId:o,sceneId:l});re({anchorType:"SceneID Anchor",storedSceneId:l,storedChapterId:o,resolutionMethod:"Anchor"})}if(o){const u=await oe(n.bookId),t=u.find(n=>n.chapterId===o),i=t?(Array.isArray(t.scenes)?t.scenes:[]).find(n=>a(n.title,"scene").toLocaleLowerCase()===r.toLocaleLowerCase()):null;if(i)return w({result:"Matched",chapterId:t.chapterId,sceneId:i.sceneId}),await du(n.bookId,i.sceneId,t.chapterId,"Anchor","ChapterID Anchor"),!0;t&&!l?(ii="ChapterID Anchor",ai(null,o,"Chapter anchor"),w({result:"Chapter matched",chapterId:o,sceneId:null})):l||(ii="ChapterID Anchor",w({result:"Chapter anchor not found",chapterId:o,sceneId:null}))}const i=await gr(`/api/word-companion/books/${n.bookId}/resolve-scene`,{chapterTitle:s,sceneTitle:r});if(!i?.matched||!i.sceneId){const f=ut,e=Number.parseInt(i?.chapterId||"",10),o=Number.isInteger(u)&&u>0?u:null,n=Number.isInteger(e)&&e>0?e:o,r=!!i?.chapterMatched||!!n;return v("Not found in PlotDirector"),ut=f,r&&(ai(null,n,n===o?"Chapter anchor":"Chapter title"),ir("Scene not found in PlotDirector.")),t(f?"Stored PlotDirector ID is invalid.":r?"Scene not found in PlotDirector.":"This chapter does not exist in PlotDirector. Create or link the chapter first."),w({result:"Not matched",chapterId:r?n:i?.chapterId,sceneId:i?.sceneId}),f||(r?(pr(),wr("Scene not found in PlotDirector.")):(wu(),pu("Chapter not found in PlotDirector."))),p(),!1}const f=ut;return w({result:f?"Matched by title fallback":"Matched",chapterId:i.chapterId,sceneId:i.sceneId}),await du(n.bookId,i.sceneId,i.chapterId,f?"Title fallback":"Title","Title Match"),f&&(ut=!0,t("Stored PlotDirector ID is invalid."),ri()),!0}catch(b){const n=ut;return i({lastError:h(b)}),v("Not found in PlotDirector"),ut=n,t(n?"Stored PlotDirector ID is invalid.":"Unable to load PlotDirector scene data."),w({result:"Error"}),!1}finally{p()}},dv=n=>{const t=n.currentChapter?.title||"",i=n.currentScene?.title||"",r=n.currentChapter?.anchorId||null,u=n.currentScene?.anchorId||null;return a(t,"chapter")!==a(c,"chapter")||a(i,"scene")!==a(y,"scene")||r!==o||u!==l},gv=async()=>{if(!gf&&yf&&e()){if(!at||!rt||!window.Word||typeof window.Word.run!="function"){pt("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");return}gf=!0;pt("Refreshing");t("Updating current scene...");try{const n=await window.Word.run(async n=>await gi(n)),r=dv(n);if(yr(n.currentChapter?.title,n.currentScene?.title,n.currentScene?.wordCount,n.currentChapter?.anchorId,n.currentScene?.anchorId,n.currentChapter?.index),he(n),i({lastScan:"Success",lastError:"-",paragraphs:String(n.paragraphCount),heading1:String(n.heading1Count),heading2:String(n.heading2Count)}),!r){fi(!1);pt("Live");t("Current scene updated.");return}y?await rf():await eh();fi(!1);pt("Live");t("Current scene updated.")}catch(n){console.error("Unable to refresh current scene from Word selection.",n);i({lastScan:"Failure",lastError:h(n)});fi(!0,"The Word cursor is now in a different scene. Refresh Current Scene before saving.")}finally{gf=!1}}},ny=()=>{kf&&window.clearTimeout(kf),kf=window.setTimeout(gv,850)},oh=()=>{ny()},ty=()=>{if(df&&window.Office?.context?.document&&typeof window.Office.context.document.removeHandlerAsync=="function"&&window.Office?.EventType?.DocumentSelectionChanged)try{window.Office.context.document.removeHandlerAsync(window.Office.EventType.DocumentSelectionChanged,{handler:oh});df=!1}catch(n){console.warn("Unable to remove Word selection tracking handler.",n)}},iy=()=>{if(yf){if(!window.Office?.context?.document||typeof window.Office.context.document.addHandlerAsync!="function"||!window.Office?.EventType?.DocumentSelectionChanged){pt("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.");return}try{window.Office.context.document.addHandlerAsync(window.Office.EventType.DocumentSelectionChanged,oh,n=>{n?.status===window.Office.AsyncResultStatus.Succeeded?(df=!0,pt("Live")):(pt("Manual"),t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene."))});window.addEventListener("beforeunload",ty)}catch(n){console.warn("Unable to register Word selection tracking handler.",n);pt("Manual");t("Automatic scene tracking is unavailable in this Word version. Use Refresh Current Scene.")}}},ry=async()=>{if(!e()){t("Select a PlotDirector book first.");v("Not detected");return}is(!0);try{const n=await ys();if(!n)return;if(fi(!1),!y){await eh();return}await rf()}finally{is(!1)}},sh=async(n,t)=>{if(!n){li=[];ht(b,"Select a project first");vr("");p(s.bookId,null);ei();v("Not detected");ur();return}ht(b,"Loading books...");vr("");v("Not detected");ur("Select a book to analyse manuscript structure.");try{const r=await ct(`/api/word-companion/projects/${n}/books`);if(li=Array.isArray(r.books)?r.books:[],li.length===0){ht(b,"No books available.");vr("No books available.");p(s.bookId,null);ei();return}hs(b,"Choose a book",li.map(n=>({...n,displayTitle:br(n)})),"bookId","displayTitle");const i=li.find(n=>n.bookId===t);i&&b?(b.value=String(i.bookId),p(s.bookId,i.bookId)):p(s.bookId,null);ei();v(e()?"Not detected":"Not detected");ur(e()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure.")}catch{li=[];ht(b,"Unable to load books.");vr("Unable to load books.");p(s.bookId,null);ei();v("Not detected");ur("Unable to load books.")}},uy=async()=>{ht(lt,"Loading projects...");ht(b,"Select a project first");ie("");vr("");try{const t=await ct("/api/word-companion/projects");if(tr=Array.isArray(t.projects)?t.projects:[],tr.length===0){ht(lt,"No projects available.");ie("No projects available.");p(s.projectId,null);p(s.bookId,null);ei();return}hs(lt,"Choose a project",tr,"projectId","title");const i=ss(s.projectId),n=tr.find(n=>n.projectId===i);n&<?(lt.value=String(n.projectId),p(s.projectId,n.projectId),await sh(n.projectId,ss(s.bookId))):(p(s.projectId,null),p(s.bookId,null),ei())}catch{tr=[];li=[];ht(lt,"Unable to connect to PlotDirector.");ht(b,"Select a project first");ns("Unable to connect to PlotDirector.");ie("Unable to connect to PlotDirector.");p(s.projectId,null);p(s.bookId,null);ei()}};for(const n of uf)n.addEventListener("click",()=>go(n.dataset.tabButton));if(na(),lt?.addEventListener("change",async()=>{const n=Number.parseInt(lt.value||"",10);p(s.projectId,Number.isInteger(n)&&n>0?n:null);p(s.bookId,null);v("Not detected");ur();await sh(n,null)}),b?.addEventListener("change",()=>{const n=Number.parseInt(b.value||"",10);p(s.bookId,Number.isInteger(n)&&n>0?n:null);ei();v("Not detected");ur(e()?"Ready to analyse manuscript structure.":"Select a book to analyse manuscript structure.")}),vi?.addEventListener("click",ys),oi?.addEventListener("click",ps),ff?.addEventListener("click",tv),yc?.addEventListener("click",()=>le(!0)),pc?.addEventListener("click",()=>le(!1)),ti?.addEventListener("cancel",n=>{n.preventDefault(),le(!1)}),yi?.addEventListener("click",rf),tu?.addEventListener("click",ry),kt?.addEventListener("click",kv),dt?.addEventListener("click",ov),bt?.addEventListener("click",hv),k?.addEventListener("click",lv),d?.addEventListener("click",av),uu?.addEventListener("input",th),st?.addEventListener("click",vv),hc?.addEventListener("click",ih),ac?.addEventListener("click",()=>ae(!0)),vc?.addEventListener("click",()=>ae(!1)),ni?.addEventListener("cancel",n=>{n.preventDefault(),ae(!1)}),g?.addEventListener("click",pv),nt?.addEventListener("click",wv),iu?.addEventListener("input",uh),ot?.addEventListener("click",bv),uc?.addEventListener("click",fh),oc?.addEventListener("click",()=>ve(!0)),sc?.addEventListener("click",()=>ve(!1)),gt?.addEventListener("cancel",n=>{n.preventDefault(),ve(!1)}),pi?.addEventListener("click",iv),yf?uy():(ht(lt,"Please sign in to PlotDirector."),ht(b,"Please sign in to PlotDirector."),ei()),!window.Office||typeof window.Office.onReady!="function"){te("Word Companion ready");t("Word document access is unavailable.");pt("Manual");i({host:"Unavailable",platform:"Unavailable",ready:"No",wordApi:"No"});return}os().then(()=>{te("Word Companion ready"),rt?iy():(t("Word document access is unavailable."),pt("Manual"))}).catch(n=>{console.error("Office readiness check failed.",n),ns("Unable to connect to PlotDirector."),te("Word Companion unavailable"),t("Word document access is unavailable."),i({ready:"No",wordApi:"No",lastScan:"Failure"})})})(); \ No newline at end of file