From cea82a922f334a7fe83e42de138d9551887395e1 Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Mon, 22 Jun 2026 10:45:30 +0100 Subject: [PATCH] Implemented Phase 1 Scene Occupancy. What Changed Added scene-owned occupancy data:Scenes.FloorPlanID Scenes.InitialFloorPlanFloorID new SceneFloorPlanOccupancy table Added Occupancy section to the Scene Inspector with AJAX save/refresh. Added Floor Plan editor Structure / Occupancy mode. Occupancy mode shows linked scenes, previous/next scene controls, and character/asset tokens inside assigned locations. Character tokens use image thumbnail, then initials fallback. Asset tokens do the same, smaller. No Features, no new floor-plan architecture, no transition changes. Files Changed [CoreModels.cs](C:/Source/PlotLine/PlotLine/Models/CoreModels.cs) [CoreViewModels.cs](C:/Source/PlotLine/PlotLine/ViewModels/CoreViewModels.cs) [Repositories.cs](C:/Source/PlotLine/PlotLine/Data/Repositories.cs) [CoreServices.cs](C:/Source/PlotLine/PlotLine/Services/CoreServices.cs) [ScenesController.cs](C:/Source/PlotLine/PlotLine/Controllers/ScenesController.cs) [Program.cs](C:/Source/PlotLine/PlotLine/Program.cs) [Edit.cshtml](C:/Source/PlotLine/PlotLine/Views/FloorPlans/Edit.cshtml) [_SceneInspector.cshtml](C:/Source/PlotLine/PlotLine/Views/Scenes/_SceneInspector.cshtml) [_SceneOccupancy.cshtml](C:/Source/PlotLine/PlotLine/Views/Scenes/_SceneOccupancy.cshtml) [site.js](C:/Source/PlotLine/PlotLine/wwwroot/js/site.js) [site.css](C:/Source/PlotLine/PlotLine/wwwroot/css/site.css) minified CSS/JS updated. Database Added new migration only: [080_SceneFloorPlanOccupancy.sql](C:/Source/PlotLine/PlotLine/Sql/080_SceneFloorPlanOccupancy.sql) Applied locally. Added constraints/FKs and filtered unique indexes for one character/asset occupancy row per scene. Stored Procedures Added/Updated Scene_Save Scene_Get Scene_FloorPlanLink_Save Scene_ListByFloorPlan FloorPlanFloor_ListByPlan FloorPlanBlock_ListByPlan SceneFloorPlanOccupancy_ListByScene SceneFloorPlanOccupancy_ListByFloorPlan SceneFloorPlanOccupancy_Save Test Data Permanent Calendar House seed data added: Book: The Calendar House Chapters 1-3 14 scenes Characters: Ellie, Grant, Stephen, Housekeeper, Gardener Assets: Brass Key, Journal, Candle, Map, Letter 45 occupancy assignments Verification dotnet build PlotLine.slnx passes with 0 warnings/errors. Migration applied locally. Local app boots and returns HTTP 200. DB checks confirm 14 linked scenes and 45 occupancy rows. Manual browser click-through of the authenticated UI still needs a human pass for the AJAX controls and visual token placement. --- PlotLine/Controllers/ScenesController.cs | 28 ++ PlotLine/Data/Repositories.cs | 92 +++++- PlotLine/Models/CoreModels.cs | 25 ++ PlotLine/Program.cs | 1 + PlotLine/Services/CoreServices.cs | 211 +++++++++++++- PlotLine/Sql/080_SceneFloorPlanOccupancy.sql | 278 +++++++++++++++++++ PlotLine/ViewModels/CoreViewModels.cs | 83 ++++++ PlotLine/Views/FloorPlans/Edit.cshtml | 123 ++++++++ PlotLine/Views/Scenes/_SceneInspector.cshtml | 8 + PlotLine/Views/Scenes/_SceneOccupancy.cshtml | 98 +++++++ PlotLine/wwwroot/css/site.css | 128 +++++++++ PlotLine/wwwroot/css/site.min.css | 2 +- PlotLine/wwwroot/js/site.js | 103 +++++++ PlotLine/wwwroot/js/site.min.js | 2 +- 14 files changed, 1177 insertions(+), 5 deletions(-) create mode 100644 PlotLine/Sql/080_SceneFloorPlanOccupancy.sql create mode 100644 PlotLine/Views/Scenes/_SceneOccupancy.cshtml diff --git a/PlotLine/Controllers/ScenesController.cs b/PlotLine/Controllers/ScenesController.cs index 21cfab9..f31f832 100644 --- a/PlotLine/Controllers/ScenesController.cs +++ b/PlotLine/Controllers/ScenesController.cs @@ -492,6 +492,32 @@ public sealed class ScenesController( return RedirectToAction(nameof(Edit), new { id = sceneId }); } + [HttpGet] + public async Task OccupancyEditor(int sceneId, int? floorPlanId) + { + var model = await scenes.GetOccupancyEditorAsync(sceneId, floorPlanId); + return model is null ? NotFound() : PartialView("_SceneOccupancy", model); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task SaveOccupancy(SceneOccupancySaveViewModel model) + { + try + { + await scenes.SaveOccupancyAsync(model); + var refreshed = await scenes.GetOccupancyEditorAsync(model.SceneID, model.FloorPlanID); + return refreshed is null + ? NotFound() + : PartialView("_SceneOccupancy", refreshed); + } + catch (InvalidOperationException ex) + { + Response.StatusCode = StatusCodes.Status400BadRequest; + return Json(new { ok = false, message = ex.Message }); + } + } + private string? GetLocalReturnUrl(string? returnUrl = null) { if (string.IsNullOrWhiteSpace(returnUrl) @@ -563,6 +589,8 @@ public sealed class ScenesController( target.SceneOutcomeNotes = source.SceneOutcomeNotes; target.RevisionStatusID = source.RevisionStatusID; target.PrimaryLocationID = source.PrimaryLocationID; + target.FloorPlanID = source.FloorPlanID; + target.InitialFloorPlanFloorID = source.InitialFloorPlanFloorID; target.SelectedPurposeTypeIds = source.SelectedPurposeTypeIds; target.ReturnToTimeline = source.ReturnToTimeline; target.ReturnProjectID = source.ReturnProjectID; diff --git a/PlotLine/Data/Repositories.cs b/PlotLine/Data/Repositories.cs index d8048a0..49a0309 100644 --- a/PlotLine/Data/Repositories.cs +++ b/PlotLine/Data/Repositories.cs @@ -69,8 +69,10 @@ public interface IChapterRepository public interface ISceneRepository { Task> ListByChapterAsync(int chapterId); + Task> ListByFloorPlanAsync(int floorPlanId); Task GetAsync(int sceneId); Task SaveAsync(Scene scene); + Task SaveFloorPlanLinkAsync(int sceneId, int? floorPlanId, int? initialFloorPlanFloorId); Task SavePurposesAsync(int sceneId, IEnumerable purposeIds); Task SaveMetricValuesAsync(int sceneId, IEnumerable metricValues); Task SaveMetricValueAsync(int sceneId, int metricTypeId, int value); @@ -83,6 +85,13 @@ public interface ISceneRepository Task RenumberChapterAsync(int chapterId); } +public interface ISceneFloorPlanOccupancyRepository +{ + Task> ListBySceneAsync(int sceneId); + Task> ListByFloorPlanAsync(int floorPlanId); + Task SaveAsync(int sceneId, int? floorPlanId, int? initialFloorPlanFloorId, IEnumerable occupancyRows); +} + public interface ILookupRepository { Task GetAllAsync(); @@ -223,6 +232,8 @@ public interface IFloorPlanRepository Task<(FloorPlan? FloorPlan, IReadOnlyList Floors, IReadOnlyList Blocks, IReadOnlyList Transitions)> GetEditorAsync(int floorPlanId); Task GetFloorAsync(int floorPlanFloorId); Task> ListBlocksByFloorAsync(int floorPlanFloorId); + Task> ListBlocksByPlanAsync(int floorPlanId); + Task> ListFloorsByPlanAsync(int floorPlanId); Task GetBlockAsync(int floorPlanBlockId); Task SavePlanAsync(FloorPlan floorPlan); Task DeletePlanAsync(int floorPlanId); @@ -582,6 +593,20 @@ public sealed class FloorPlanRepository(ISqlConnectionFactory connectionFactory) return rows.ToList(); } + public async Task> ListBlocksByPlanAsync(int floorPlanId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync("dbo.FloorPlanBlock_ListByPlan", new { FloorPlanID = floorPlanId }, commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + + public async Task> ListFloorsByPlanAsync(int floorPlanId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync("dbo.FloorPlanFloor_ListByPlan", new { FloorPlanID = floorPlanId }, commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + public async Task GetBlockAsync(int floorPlanBlockId) { using var connection = connectionFactory.CreateConnection(); @@ -2446,6 +2471,13 @@ public sealed class SceneRepository(ISqlConnectionFactory connectionFactory) : I return rows.ToList(); } + public async Task> ListByFloorPlanAsync(int floorPlanId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync("dbo.Scene_ListByFloorPlan", new { FloorPlanID = floorPlanId }, commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + public async Task GetAsync(int sceneId) { using var connection = connectionFactory.CreateConnection(); @@ -2483,11 +2515,22 @@ public sealed class SceneRepository(ISqlConnectionFactory connectionFactory) : I scene.ScenePurposeNotes, scene.SceneOutcomeNotes, scene.RevisionStatusID, - scene.PrimaryLocationID + scene.PrimaryLocationID, + scene.FloorPlanID, + scene.InitialFloorPlanFloorID }, commandType: CommandType.StoredProcedure); } + public async Task SaveFloorPlanLinkAsync(int sceneId, int? floorPlanId, int? initialFloorPlanFloorId) + { + using var connection = connectionFactory.CreateConnection(); + await connection.ExecuteAsync( + "dbo.Scene_FloorPlanLink_Save", + new { SceneID = sceneId, FloorPlanID = floorPlanId, InitialFloorPlanFloorID = initialFloorPlanFloorId }, + commandType: CommandType.StoredProcedure); + } + public async Task SavePurposesAsync(int sceneId, IEnumerable purposeIds) { using var connection = connectionFactory.CreateConnection(); @@ -2584,6 +2627,53 @@ public sealed class SceneRepository(ISqlConnectionFactory connectionFactory) : I } } +public sealed class SceneFloorPlanOccupancyRepository(ISqlConnectionFactory connectionFactory) : ISceneFloorPlanOccupancyRepository +{ + public async Task> ListBySceneAsync(int sceneId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync( + "dbo.SceneFloorPlanOccupancy_ListByScene", + new { SceneID = sceneId }, + commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + + public async Task> ListByFloorPlanAsync(int floorPlanId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync( + "dbo.SceneFloorPlanOccupancy_ListByFloorPlan", + new { FloorPlanID = floorPlanId }, + commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + + public async Task SaveAsync(int sceneId, int? floorPlanId, int? initialFloorPlanFloorId, IEnumerable occupancyRows) + { + using var connection = connectionFactory.CreateConnection(); + await connection.ExecuteAsync( + "dbo.Scene_FloorPlanLink_Save", + new { SceneID = sceneId, FloorPlanID = floorPlanId, InitialFloorPlanFloorID = initialFloorPlanFloorId }, + commandType: CommandType.StoredProcedure); + + foreach (var row in occupancyRows) + { + await connection.ExecuteAsync( + "dbo.SceneFloorPlanOccupancy_Save", + new + { + SceneID = sceneId, + FloorPlanID = floorPlanId, + row.CharacterID, + row.StoryAssetID, + LocationID = row.LocationID == 0 ? (int?)null : row.LocationID + }, + commandType: CommandType.StoredProcedure); + } + } +} + public sealed class LookupRepository(ISqlConnectionFactory connectionFactory) : ILookupRepository { public async Task GetAllAsync() diff --git a/PlotLine/Models/CoreModels.cs b/PlotLine/Models/CoreModels.cs index e57cd65..32e994b 100644 --- a/PlotLine/Models/CoreModels.cs +++ b/PlotLine/Models/CoreModels.cs @@ -313,6 +313,8 @@ public sealed class Scene public string? Summary { get; set; } public int? POVCharacterID { get; set; } public int? PrimaryLocationID { get; set; } + public int? FloorPlanID { get; set; } + public int? InitialFloorPlanFloorID { get; set; } public string? PrimaryLocationName { get; set; } public string? PrimaryLocationPath { get; set; } public int SortOrder { get; set; } @@ -1248,6 +1250,29 @@ public static class FloorPlanTransitionTypes } } +public sealed class SceneFloorPlanOccupancy +{ + public int SceneFloorPlanOccupancyID { get; set; } + public int SceneID { get; set; } + public int FloorPlanID { get; set; } + public int? FloorPlanFloorID { get; set; } + public string? FloorName { get; set; } + public int? CharacterID { get; set; } + public string? CharacterName { get; set; } + public string? CharacterShortName { get; set; } + public string? CharacterImagePath { get; set; } + public string? CharacterThumbnailPath { get; set; } + public int? StoryAssetID { get; set; } + public string? AssetName { get; set; } + public string? AssetImagePath { get; set; } + public string? AssetThumbnailPath { get; set; } + public int LocationID { get; set; } + public string LocationName { get; set; } = string.Empty; + public string LocationPath { get; set; } = string.Empty; + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} + public static class FloorPlanTransitionPositions { public const string Centre = "Centre"; diff --git a/PlotLine/Program.cs b/PlotLine/Program.cs index 77b581b..31373a4 100644 --- a/PlotLine/Program.cs +++ b/PlotLine/Program.cs @@ -97,6 +97,7 @@ public class Program builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/PlotLine/Services/CoreServices.cs b/PlotLine/Services/CoreServices.cs index 99174f0..d3fdf29 100644 --- a/PlotLine/Services/CoreServices.cs +++ b/PlotLine/Services/CoreServices.cs @@ -109,6 +109,8 @@ public interface ISceneService Task GetCreateAsync(int chapterId); Task GetEditAsync(int sceneId); Task SaveAsync(SceneEditViewModel model); + Task GetOccupancyEditorAsync(int sceneId, int? floorPlanId = null); + Task SaveOccupancyAsync(SceneOccupancySaveViewModel model); Task ArchiveAsync(int sceneId); Task MoveAsync(int sceneId, string direction); Task MoveRelativeAsync(int sceneId, int anchorSceneId, string position); @@ -1360,6 +1362,8 @@ public sealed class SceneService( IAssetRepository assets, ICharacterRepository characters, ILocationRepository locations, + IFloorPlanRepository floorPlans, + ISceneFloorPlanOccupancyRepository sceneOccupancy, IWarningRepository warnings, ISceneDependencyRepository sceneDependencies, IWriterWorkspaceRepository writerWorkspace, @@ -1427,6 +1431,8 @@ public sealed class SceneService( SceneOutcomeNotes = scene.SceneOutcomeNotes, RevisionStatusID = scene.RevisionStatusID, PrimaryLocationID = scene.PrimaryLocationID, + FloorPlanID = scene.FloorPlanID, + InitialFloorPlanFloorID = scene.InitialFloorPlanFloorID, SelectedPurposeTypeIds = scene.SelectedPurposeTypeIds, Metrics = scene.Metrics.Select(metric => new SceneMetricInputViewModel { @@ -1475,7 +1481,9 @@ public sealed class SceneService( ScenePurposeNotes = model.ScenePurposeNotes, SceneOutcomeNotes = model.SceneOutcomeNotes, RevisionStatusID = model.RevisionStatusID, - PrimaryLocationID = model.PrimaryLocationID + PrimaryLocationID = model.PrimaryLocationID, + FloorPlanID = model.FloorPlanID, + InitialFloorPlanFloorID = model.InitialFloorPlanFloorID }); await scenes.SavePurposesAsync(sceneId, model.SelectedPurposeTypeIds); @@ -1724,10 +1732,172 @@ public sealed class SceneService( ReturnProjectID = model.ReturnProjectID, ReturnBookID = model.ReturnBookID }; + model.Occupancy = model.SceneID == 0 + ? new SceneOccupancyEditorViewModel() + : await BuildOccupancyEditorAsync(model, projectAssets); model.LocationConsistencyMessages = BuildLocationConsistencyMessages(model); return model; } + public async Task GetOccupancyEditorAsync(int sceneId, int? floorPlanId = null) + { + var sceneModel = await GetEditAsync(sceneId); + if (sceneModel is null) + { + return null; + } + + if (floorPlanId.HasValue) + { + sceneModel.FloorPlanID = floorPlanId; + } + + var projectAssets = sceneModel.Project is null ? [] : await assets.ListAssetsAsync(sceneModel.Project.ProjectID); + return await BuildOccupancyEditorAsync(sceneModel, projectAssets); + } + + public async Task SaveOccupancyAsync(SceneOccupancySaveViewModel model) + { + var scene = await scenes.GetAsync(model.SceneID) ?? throw new InvalidOperationException("Scene not found."); + var context = await GetContextAsync(scene.ChapterID) ?? throw new InvalidOperationException("Scene context not found."); + + if (model.FloorPlanID.HasValue) + { + var floorPlan = await floorPlans.GetAsync(model.FloorPlanID.Value); + if (floorPlan is null || floorPlan.ProjectID != context.Project.ProjectID) + { + throw new InvalidOperationException("Floor plan not found."); + } + + if (model.InitialFloorPlanFloorID.HasValue) + { + var floors = await floorPlans.ListFloorsByPlanAsync(model.FloorPlanID.Value); + if (!floors.Any(x => x.FloorPlanFloorID == model.InitialFloorPlanFloorID.Value)) + { + throw new InvalidOperationException("Initial floor does not belong to the selected floor plan."); + } + } + } + else + { + model.InitialFloorPlanFloorID = null; + } + + var allowedLocations = model.FloorPlanID.HasValue + ? (await floorPlans.ListBlocksByPlanAsync(model.FloorPlanID.Value)).Select(x => x.LocationID).ToHashSet() + : []; + + var sceneCharacterIds = (await characters.ListSceneCharactersAsync(model.SceneID)).Select(x => x.CharacterID).ToHashSet(); + var sceneAssetIds = (await assets.ListEventsBySceneAsync(model.SceneID)).Select(x => x.StoryAssetID).ToHashSet(); + var rows = new List(); + + foreach (var character in model.Characters.Where(x => sceneCharacterIds.Contains(x.CharacterID))) + { + if (character.LocationID.HasValue && !allowedLocations.Contains(character.LocationID.Value)) + { + throw new InvalidOperationException("Character location must be on the selected floor plan."); + } + + rows.Add(new SceneFloorPlanOccupancy + { + CharacterID = character.CharacterID, + LocationID = character.LocationID ?? 0 + }); + } + + foreach (var asset in model.Assets.Where(x => sceneAssetIds.Contains(x.StoryAssetID))) + { + if (asset.LocationID.HasValue && !allowedLocations.Contains(asset.LocationID.Value)) + { + throw new InvalidOperationException("Asset location must be on the selected floor plan."); + } + + rows.Add(new SceneFloorPlanOccupancy + { + StoryAssetID = asset.StoryAssetID, + LocationID = asset.LocationID ?? 0 + }); + } + + await sceneOccupancy.SaveAsync(model.SceneID, model.FloorPlanID, model.InitialFloorPlanFloorID, rows); + await activity.RecordAsync(context.Project.ProjectID, "Updated", "Scene Occupancy", model.SceneID, scene.SceneTitle); + } + + private async Task BuildOccupancyEditorAsync(SceneEditViewModel model, IReadOnlyList projectAssets) + { + var floorPlanList = model.Project is null ? [] : await floorPlans.ListByProjectAsync(model.Project.ProjectID); + var selectedFloorPlanId = model.FloorPlanID ?? floorPlanList.FirstOrDefault()?.FloorPlanID; + var existingRows = model.SceneID == 0 ? [] : await sceneOccupancy.ListBySceneAsync(model.SceneID); + var floors = new List(); + var locationsOnPlans = new List(); + + foreach (var plan in floorPlanList) + { + var planFloors = await floorPlans.ListFloorsByPlanAsync(plan.FloorPlanID); + var blocks = await floorPlans.ListBlocksByPlanAsync(plan.FloorPlanID); + var floorsById = planFloors.ToDictionary(x => x.FloorPlanFloorID); + floors.AddRange(planFloors.Select(floor => new SceneOccupancyFloorOption + { + FloorPlanID = floor.FloorPlanID, + FloorPlanFloorID = floor.FloorPlanFloorID, + Name = floor.Name, + SortOrder = floor.SortOrder + })); + + locationsOnPlans.AddRange(blocks + .GroupBy(x => new { x.LocationID, x.FloorPlanFloorID }) + .Select(group => + { + floorsById.TryGetValue(group.Key.FloorPlanFloorID, out var floor); + var first = group.First(); + return new SceneOccupancyLocationOption + { + FloorPlanID = plan.FloorPlanID, + FloorPlanFloorID = group.Key.FloorPlanFloorID, + FloorName = floor?.Name ?? "Floor", + FloorSortOrder = floor?.SortOrder ?? 0, + LocationID = group.Key.LocationID, + LocationName = first.LocationName, + LocationPath = first.LocationPath + }; + })); + } + + var existingByCharacter = existingRows.Where(x => x.CharacterID.HasValue).ToDictionary(x => x.CharacterID!.Value, x => x.LocationID); + var existingByAsset = existingRows.Where(x => x.StoryAssetID.HasValue).ToDictionary(x => x.StoryAssetID!.Value, x => x.LocationID); + var assetNames = projectAssets.ToDictionary(x => x.StoryAssetID, x => x.AssetName); + + return new SceneOccupancyEditorViewModel + { + SceneID = model.SceneID, + FloorPlanID = selectedFloorPlanId, + InitialFloorPlanFloorID = model.InitialFloorPlanFloorID, + FloorPlanOptions = floorPlanList.OrderBy(x => x.Name).Select(x => new SelectListItem(x.Name, x.FloorPlanID.ToString())).ToList(), + Floors = floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name).ToList(), + Locations = locationsOnPlans.OrderBy(x => x.FloorSortOrder).ThenBy(x => x.FloorName).ThenBy(x => x.LocationPath).ToList(), + Characters = model.SceneCharacters + .GroupBy(x => x.CharacterID) + .Select(group => new SceneCharacterOccupancyRowViewModel + { + CharacterID = group.Key, + CharacterName = group.First().CharacterName, + LocationID = existingByCharacter.GetValueOrDefault(group.Key) + }) + .OrderBy(x => x.CharacterName) + .ToList(), + Assets = model.AssetEvents + .GroupBy(x => x.StoryAssetID) + .Select(group => new SceneAssetOccupancyRowViewModel + { + StoryAssetID = group.Key, + AssetName = assetNames.GetValueOrDefault(group.Key, group.First().AssetName), + LocationID = existingByAsset.GetValueOrDefault(group.Key) + }) + .OrderBy(x => x.AssetName) + .ToList() + }; + } + private async Task> BuildAgeContinuityWarningsAsync(SceneEditViewModel model) { if (model.SceneID == 0 || model.Project is null || model.Book is null) @@ -7561,6 +7731,8 @@ public sealed class LocationService(IProjectRepository projects, ILocationReposi public sealed class FloorPlanService( IProjectRepository projects, + ISceneRepository scenes, + ISceneFloorPlanOccupancyRepository sceneOccupancy, IFloorPlanRepository floorPlans, ILocationRepository locations, IFloorPlanBackgroundImageService backgroundImages, @@ -7595,6 +7767,11 @@ public sealed class FloorPlanService( var projectLocations = await locations.ListByProjectAsync(project.ProjectID); var orderedFloors = data.Floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name).ToList(); + var occupancyScenes = await scenes.ListByFloorPlanAsync(floorPlanId); + var occupancyRows = await sceneOccupancy.ListByFloorPlanAsync(floorPlanId); + var firstBlockByLocation = data.Blocks + .GroupBy(x => x.LocationID) + .ToDictionary(x => x.Key, x => x.OrderBy(block => block.FloorPlanFloorID).ThenBy(block => block.Y).ThenBy(block => block.X).First()); return new FloorPlanEditorViewModel { Project = project, @@ -7635,7 +7812,37 @@ public sealed class FloorPlanService( LocationOptions = ToOptionalLocationOptions(projectLocations, "Create/link automatically"), Locations = projectLocations, BlockTypeOptions = FloorPlanBlockTypes.All.Select(x => new SelectListItem(BlockTypeLabel(x), x)).ToList(), - TransitionTypeOptions = FloorPlanTransitionTypes.All.Select(x => new SelectListItem(x, x)).ToList() + TransitionTypeOptions = FloorPlanTransitionTypes.All.Select(x => new SelectListItem(x, x)).ToList(), + OccupancyScenes = occupancyScenes + .OrderBy(x => x.StartDateTime ?? DateTime.MaxValue) + .ThenBy(x => x.SceneNumber) + .ThenBy(x => x.SceneTitle) + .Select(x => new FloorPlanOccupancySceneViewModel + { + SceneID = x.SceneID, + InitialFloorPlanFloorID = x.InitialFloorPlanFloorID, + Label = $"Scene {x.SceneNumber}: {x.SceneTitle}" + }) + .ToList(), + OccupancyTokens = occupancyRows + .Where(x => firstBlockByLocation.ContainsKey(x.LocationID)) + .Select(x => + { + var block = firstBlockByLocation[x.LocationID]; + return new FloorPlanOccupancyTokenViewModel + { + SceneID = x.SceneID, + FloorPlanFloorID = block.FloorPlanFloorID, + LocationID = x.LocationID, + LocationName = x.LocationName, + EntityType = x.CharacterID.HasValue ? "Character" : "Asset", + EntityID = x.CharacterID ?? x.StoryAssetID ?? 0, + DisplayName = x.CharacterName ?? x.AssetName ?? "Occupant", + ImagePath = x.CharacterImagePath ?? x.AssetImagePath, + ThumbnailPath = x.CharacterThumbnailPath ?? x.AssetThumbnailPath + }; + }) + .ToList() }; } diff --git a/PlotLine/Sql/080_SceneFloorPlanOccupancy.sql b/PlotLine/Sql/080_SceneFloorPlanOccupancy.sql new file mode 100644 index 0000000..e8bb80b --- /dev/null +++ b/PlotLine/Sql/080_SceneFloorPlanOccupancy.sql @@ -0,0 +1,278 @@ +SET QUOTED_IDENTIFIER ON; +GO + +IF COL_LENGTH(N'dbo.Scenes', N'FloorPlanID') IS NULL + ALTER TABLE dbo.Scenes ADD FloorPlanID int NULL; +GO + +IF COL_LENGTH(N'dbo.Scenes', N'InitialFloorPlanFloorID') IS NULL + ALTER TABLE dbo.Scenes ADD InitialFloorPlanFloorID int NULL; +GO + +IF OBJECT_ID(N'dbo.FK_Scenes_FloorPlans', N'F') IS NULL + ALTER TABLE dbo.Scenes WITH CHECK ADD CONSTRAINT FK_Scenes_FloorPlans FOREIGN KEY (FloorPlanID) REFERENCES dbo.FloorPlans(FloorPlanID); +GO + +IF OBJECT_ID(N'dbo.FK_Scenes_InitialFloorPlanFloors', N'F') IS NULL + ALTER TABLE dbo.Scenes WITH CHECK ADD CONSTRAINT FK_Scenes_InitialFloorPlanFloors FOREIGN KEY (InitialFloorPlanFloorID) REFERENCES dbo.FloorPlanFloors(FloorPlanFloorID); +GO + +IF OBJECT_ID(N'dbo.SceneFloorPlanOccupancy', N'U') IS NULL +BEGIN + CREATE TABLE dbo.SceneFloorPlanOccupancy + ( + SceneFloorPlanOccupancyID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SceneFloorPlanOccupancy PRIMARY KEY, + SceneID int NOT NULL, + FloorPlanID int NOT NULL, + FloorPlanFloorID int NULL, + CharacterID int NULL, + StoryAssetID int NULL, + LocationID int NOT NULL, + CreatedDate datetime2 NOT NULL CONSTRAINT DF_SceneFloorPlanOccupancy_CreatedDate DEFAULT SYSUTCDATETIME(), + ModifiedDate datetime2 NULL, + CONSTRAINT CK_SceneFloorPlanOccupancy_OneEntity CHECK + ( + (CharacterID IS NOT NULL AND StoryAssetID IS NULL) + OR (CharacterID IS NULL AND StoryAssetID IS NOT NULL) + ), + CONSTRAINT FK_SceneFloorPlanOccupancy_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID) ON DELETE CASCADE, + CONSTRAINT FK_SceneFloorPlanOccupancy_FloorPlans FOREIGN KEY (FloorPlanID) REFERENCES dbo.FloorPlans(FloorPlanID), + CONSTRAINT FK_SceneFloorPlanOccupancy_FloorPlanFloors FOREIGN KEY (FloorPlanFloorID) REFERENCES dbo.FloorPlanFloors(FloorPlanFloorID), + CONSTRAINT FK_SceneFloorPlanOccupancy_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID), + CONSTRAINT FK_SceneFloorPlanOccupancy_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID), + CONSTRAINT FK_SceneFloorPlanOccupancy_Locations FOREIGN KEY (LocationID) REFERENCES dbo.Locations(LocationID) + ); +END; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_SceneFloorPlanOccupancy_Character' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE UNIQUE INDEX UX_SceneFloorPlanOccupancy_Character ON dbo.SceneFloorPlanOccupancy(SceneID, CharacterID) WHERE CharacterID IS NOT NULL; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_SceneFloorPlanOccupancy_Asset' AND object_id = OBJECT_ID(N'dbo.SceneFloorPlanOccupancy')) + CREATE UNIQUE INDEX UX_SceneFloorPlanOccupancy_Asset ON dbo.SceneFloorPlanOccupancy(SceneID, StoryAssetID) WHERE StoryAssetID IS NOT NULL; +GO + +CREATE OR ALTER PROCEDURE dbo.Scene_Save + @SceneID int = NULL, @ChapterID int, @SceneNumber decimal(10,2), @SceneTitle nvarchar(200), @Summary nvarchar(max) = NULL, + @TimeModeID int, @StartDateTime datetime2 = NULL, @EndDateTime datetime2 = NULL, @DurationAmount decimal(10,2) = NULL, + @DurationUnitID int = NULL, @RelativeTimeText nvarchar(200) = NULL, @TimeConfidenceID int, + @ScenePurposeNotes nvarchar(max) = NULL, @SceneOutcomeNotes nvarchar(max) = NULL, @RevisionStatusID int, + @PrimaryLocationID int = NULL, @FloorPlanID int = NULL, @InitialFloorPlanFloorID int = NULL +AS +BEGIN + SET NOCOUNT ON; + DECLARE @NextSortOrder int; + IF @SceneID IS NULL OR @SceneID = 0 + BEGIN + SELECT @NextSortOrder = ISNULL(MAX(SortOrder), 0) + 10 FROM dbo.Scenes WHERE ChapterID = @ChapterID; + INSERT dbo.Scenes (ChapterID, SceneNumber, SceneTitle, Summary, SortOrder, TimeModeID, StartDateTime, EndDateTime, + DurationAmount, DurationUnitID, RelativeTimeText, TimeConfidenceID, ScenePurposeNotes, SceneOutcomeNotes, + RevisionStatusID, PrimaryLocationID, FloorPlanID, InitialFloorPlanFloorID) + VALUES (@ChapterID, @SceneNumber, @SceneTitle, @Summary, @NextSortOrder, @TimeModeID, @StartDateTime, @EndDateTime, + @DurationAmount, @DurationUnitID, @RelativeTimeText, @TimeConfidenceID, @ScenePurposeNotes, @SceneOutcomeNotes, + @RevisionStatusID, @PrimaryLocationID, @FloorPlanID, @InitialFloorPlanFloorID); + SET @SceneID = CAST(SCOPE_IDENTITY() AS int); + END + ELSE + BEGIN + UPDATE dbo.Scenes + SET SceneNumber = @SceneNumber, SceneTitle = @SceneTitle, Summary = @Summary, TimeModeID = @TimeModeID, + StartDateTime = @StartDateTime, EndDateTime = @EndDateTime, DurationAmount = @DurationAmount, DurationUnitID = @DurationUnitID, + RelativeTimeText = @RelativeTimeText, TimeConfidenceID = @TimeConfidenceID, ScenePurposeNotes = @ScenePurposeNotes, + SceneOutcomeNotes = @SceneOutcomeNotes, RevisionStatusID = @RevisionStatusID, PrimaryLocationID = @PrimaryLocationID, + FloorPlanID = @FloorPlanID, InitialFloorPlanFloorID = @InitialFloorPlanFloorID, + UpdatedDate = SYSUTCDATETIME() + WHERE SceneID = @SceneID; + END + SELECT @SceneID; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.Scene_Get + @SceneID int +AS +BEGIN + SET NOCOUNT ON; + EXEC dbo.SceneMetric_EnsureDefaults @SceneID; + SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID, + s.FloorPlanID, s.InitialFloorPlanFloorID, + location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath, + s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID, + du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, + s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived + FROM dbo.Scenes s + INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID + INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID + INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID + LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID + LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID + WHERE s.SceneID = @SceneID AND s.IsArchived = 0; + SELECT ScenePurposeTypeID FROM dbo.ScenePurposes WHERE SceneID = @SceneID; + EXEC dbo.SceneMetric_ListByScene @SceneID; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.Scene_FloorPlanLink_Save + @SceneID int, + @FloorPlanID int = NULL, + @InitialFloorPlanFloorID int = NULL +AS +BEGIN + SET NOCOUNT ON; + IF @FloorPlanID IS NULL + SET @InitialFloorPlanFloorID = NULL; + + UPDATE dbo.Scenes + SET FloorPlanID = @FloorPlanID, + InitialFloorPlanFloorID = @InitialFloorPlanFloorID, + UpdatedDate = SYSUTCDATETIME() + WHERE SceneID = @SceneID; + + IF @FloorPlanID IS NULL + DELETE FROM dbo.SceneFloorPlanOccupancy WHERE SceneID = @SceneID; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.Scene_ListByFloorPlan + @FloorPlanID int +AS +BEGIN + SET NOCOUNT ON; + SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID, + s.FloorPlanID, s.InitialFloorPlanFloorID, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, + s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, + tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes, s.RevisionStatusID, + rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived + FROM dbo.Scenes s + INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID + INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID + INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID + LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID + WHERE s.FloorPlanID = @FloorPlanID AND s.IsArchived = 0 + ORDER BY s.StartDateTime, s.SceneNumber, s.SortOrder, s.SceneTitle; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.FloorPlanFloor_ListByPlan + @FloorPlanID int +AS +BEGIN + SET NOCOUNT ON; + SELECT FloorPlanFloorID, FloorPlanID, LocationID, Name, SortOrder, GridWidth, GridHeight, + BackgroundImagePath, BackgroundImageOriginalFileName, BackgroundOpacity, BackgroundScale, + BackgroundOffsetX, BackgroundOffsetY, BackgroundLocked, CreatedDate, ModifiedDate + FROM dbo.FloorPlanFloors + WHERE FloorPlanID = @FloorPlanID + ORDER BY SortOrder, Name; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.FloorPlanBlock_ListByPlan + @FloorPlanID int +AS +BEGIN + SET NOCOUNT ON; + SELECT fpb.FloorPlanBlockID, fpb.FloorPlanFloorID, fpb.LocationID, + COALESCE(lp.LocationName, l.LocationName) AS LocationName, + COALESCE(lp.LocationPath, l.LocationName) AS LocationPath, + fpb.X, fpb.Y, fpb.WidthCells, fpb.HeightCells, fpb.BlockType, fpb.LabelOverride, fpb.Notes, + fpb.CreatedDate, fpb.ModifiedDate + FROM dbo.FloorPlanBlocks fpb + INNER JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = fpb.FloorPlanFloorID + INNER JOIN dbo.Locations l ON l.LocationID = fpb.LocationID + LEFT JOIN dbo.LocationPaths lp ON lp.LocationID = fpb.LocationID + WHERE fpf.FloorPlanID = @FloorPlanID + ORDER BY fpf.SortOrder, fpf.Name, fpb.Y, fpb.X; +END; +GO + +CREATE OR ALTER PROCEDURE dbo.SceneFloorPlanOccupancy_ListByScene + @SceneID int +AS +BEGIN + SET NOCOUNT ON; + SELECT o.SceneFloorPlanOccupancyID, o.SceneID, o.FloorPlanID, o.FloorPlanFloorID, + o.CharacterID, c.CharacterName, c.ShortName AS CharacterShortName, c.ImagePath AS CharacterImagePath, c.ThumbnailPath AS CharacterThumbnailPath, + o.StoryAssetID, sa.AssetName, sa.ImagePath AS AssetImagePath, sa.ThumbnailPath AS AssetThumbnailPath, + o.LocationID, COALESCE(lp.LocationName, l.LocationName) AS LocationName, COALESCE(lp.LocationPath, l.LocationName) AS LocationPath, + fpf.Name AS FloorName, o.CreatedDate, o.ModifiedDate + FROM dbo.SceneFloorPlanOccupancy o + INNER JOIN dbo.Locations l ON l.LocationID = o.LocationID + LEFT JOIN dbo.LocationPaths lp ON lp.LocationID = o.LocationID + LEFT JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = o.FloorPlanFloorID + LEFT JOIN dbo.Characters c ON c.CharacterID = o.CharacterID + LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = o.StoryAssetID + WHERE o.SceneID = @SceneID + ORDER BY COALESCE(c.CharacterName, sa.AssetName); +END; +GO + +CREATE OR ALTER PROCEDURE dbo.SceneFloorPlanOccupancy_ListByFloorPlan + @FloorPlanID int +AS +BEGIN + SET NOCOUNT ON; + SELECT o.SceneFloorPlanOccupancyID, o.SceneID, o.FloorPlanID, o.FloorPlanFloorID, + o.CharacterID, c.CharacterName, c.ShortName AS CharacterShortName, c.ImagePath AS CharacterImagePath, c.ThumbnailPath AS CharacterThumbnailPath, + o.StoryAssetID, sa.AssetName, sa.ImagePath AS AssetImagePath, sa.ThumbnailPath AS AssetThumbnailPath, + o.LocationID, COALESCE(lp.LocationName, l.LocationName) AS LocationName, COALESCE(lp.LocationPath, l.LocationName) AS LocationPath, + fpf.Name AS FloorName, o.CreatedDate, o.ModifiedDate + FROM dbo.SceneFloorPlanOccupancy o + INNER JOIN dbo.Locations l ON l.LocationID = o.LocationID + LEFT JOIN dbo.LocationPaths lp ON lp.LocationID = o.LocationID + LEFT JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = o.FloorPlanFloorID + LEFT JOIN dbo.Characters c ON c.CharacterID = o.CharacterID + LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = o.StoryAssetID + WHERE o.FloorPlanID = @FloorPlanID + ORDER BY o.SceneID, COALESCE(c.CharacterName, sa.AssetName); +END; +GO + +CREATE OR ALTER PROCEDURE dbo.SceneFloorPlanOccupancy_Save + @SceneID int, + @FloorPlanID int = NULL, + @CharacterID int = NULL, + @StoryAssetID int = NULL, + @LocationID int = NULL +AS +BEGIN + SET NOCOUNT ON; + + IF @FloorPlanID IS NULL OR @LocationID IS NULL + BEGIN + DELETE FROM dbo.SceneFloorPlanOccupancy + WHERE SceneID = @SceneID + AND ((@CharacterID IS NOT NULL AND CharacterID = @CharacterID) + OR (@StoryAssetID IS NOT NULL AND StoryAssetID = @StoryAssetID)); + RETURN; + END; + + DECLARE @FloorPlanFloorID int; + SELECT TOP (1) @FloorPlanFloorID = fpb.FloorPlanFloorID + FROM dbo.FloorPlanBlocks fpb + INNER JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = fpb.FloorPlanFloorID + WHERE fpf.FloorPlanID = @FloorPlanID + AND fpb.LocationID = @LocationID + ORDER BY fpf.SortOrder, fpf.Name, fpb.Y, fpb.X; + + IF @FloorPlanFloorID IS NULL + THROW 51000, 'Location must be placed on the selected floor plan.', 1; + + MERGE dbo.SceneFloorPlanOccupancy AS target + USING + ( + SELECT @SceneID AS SceneID, @FloorPlanID AS FloorPlanID, @FloorPlanFloorID AS FloorPlanFloorID, + @CharacterID AS CharacterID, @StoryAssetID AS StoryAssetID, @LocationID AS LocationID + ) AS source + ON target.SceneID = source.SceneID + AND ((source.CharacterID IS NOT NULL AND target.CharacterID = source.CharacterID) + OR (source.StoryAssetID IS NOT NULL AND target.StoryAssetID = source.StoryAssetID)) + WHEN MATCHED THEN + UPDATE SET FloorPlanID = source.FloorPlanID, FloorPlanFloorID = source.FloorPlanFloorID, + LocationID = source.LocationID, ModifiedDate = SYSUTCDATETIME() + WHEN NOT MATCHED THEN + INSERT (SceneID, FloorPlanID, FloorPlanFloorID, CharacterID, StoryAssetID, LocationID) + VALUES (source.SceneID, source.FloorPlanID, source.FloorPlanFloorID, source.CharacterID, source.StoryAssetID, source.LocationID); +END; +GO diff --git a/PlotLine/ViewModels/CoreViewModels.cs b/PlotLine/ViewModels/CoreViewModels.cs index 3c69055..b31ddb7 100644 --- a/PlotLine/ViewModels/CoreViewModels.cs +++ b/PlotLine/ViewModels/CoreViewModels.cs @@ -294,6 +294,12 @@ public sealed class SceneEditViewModel [Display(Name = "Primary location")] public int? PrimaryLocationID { get; set; } + [Display(Name = "Floor plan")] + public int? FloorPlanID { get; set; } + + [Display(Name = "Initial floor")] + public int? InitialFloorPlanFloorID { get; set; } + [Display(Name = "Scene purposes")] public List SelectedPurposeTypeIds { get; set; } = []; @@ -358,6 +364,7 @@ public sealed class SceneEditViewModel public IReadOnlyList SceneAttachmentTypeOptions { get; set; } = []; public StorageUsage? StorageUsage { get; set; } public StoryStateViewModel StoryState { get; set; } = new(); + public SceneOccupancyEditorViewModel Occupancy { get; set; } = new(); public int? ReturnProjectID { get; set; } public int? ReturnBookID { get; set; } @@ -373,6 +380,60 @@ public sealed class SceneEditViewModel public IReadOnlyList ScenePurposeTypes { get; set; } = []; } +public sealed class SceneOccupancyEditorViewModel +{ + public int SceneID { get; set; } + public int? FloorPlanID { get; set; } + public int? InitialFloorPlanFloorID { get; set; } + public IReadOnlyList FloorPlanOptions { get; set; } = []; + public IReadOnlyList Floors { get; set; } = []; + public IReadOnlyList Locations { get; set; } = []; + public IReadOnlyList Characters { get; set; } = []; + public IReadOnlyList Assets { get; set; } = []; +} + +public sealed class SceneOccupancyFloorOption +{ + public int FloorPlanFloorID { get; set; } + public int FloorPlanID { get; set; } + public string Name { get; set; } = string.Empty; + public int SortOrder { get; set; } +} + +public sealed class SceneOccupancyLocationOption +{ + public int LocationID { get; set; } + public int FloorPlanID { get; set; } + public int FloorPlanFloorID { get; set; } + public string FloorName { get; set; } = string.Empty; + public int FloorSortOrder { get; set; } + public string LocationName { get; set; } = string.Empty; + public string LocationPath { get; set; } = string.Empty; +} + +public sealed class SceneCharacterOccupancyRowViewModel +{ + public int CharacterID { get; set; } + public string CharacterName { get; set; } = string.Empty; + public int? LocationID { get; set; } +} + +public sealed class SceneAssetOccupancyRowViewModel +{ + public int StoryAssetID { get; set; } + public string AssetName { get; set; } = string.Empty; + public int? LocationID { get; set; } +} + +public sealed class SceneOccupancySaveViewModel +{ + public int SceneID { get; set; } + public int? FloorPlanID { get; set; } + public int? InitialFloorPlanFloorID { get; set; } + public List Characters { get; set; } = []; + public List Assets { get; set; } = []; +} + public sealed class StoryStateViewModel { public List Characters { get; set; } = []; @@ -1872,6 +1933,28 @@ public sealed class FloorPlanEditorViewModel public IReadOnlyList Locations { get; set; } = []; public IReadOnlyList BlockTypeOptions { get; set; } = []; public IReadOnlyList TransitionTypeOptions { get; set; } = []; + public IReadOnlyList OccupancyScenes { get; set; } = []; + public IReadOnlyList OccupancyTokens { get; set; } = []; +} + +public sealed class FloorPlanOccupancySceneViewModel +{ + public int SceneID { get; set; } + public int? InitialFloorPlanFloorID { get; set; } + public string Label { get; set; } = string.Empty; +} + +public sealed class FloorPlanOccupancyTokenViewModel +{ + public int SceneID { get; set; } + public int FloorPlanFloorID { get; set; } + public int LocationID { get; set; } + public string LocationName { get; set; } = string.Empty; + public string EntityType { get; set; } = string.Empty; + public int EntityID { get; set; } + public string DisplayName { get; set; } = string.Empty; + public string? ImagePath { get; set; } + public string? ThumbnailPath { get; set; } } public sealed class FloorPlanFloorEditViewModel diff --git a/PlotLine/Views/FloorPlans/Edit.cshtml b/PlotLine/Views/FloorPlans/Edit.cshtml index 571d420..7511fd4 100644 --- a/PlotLine/Views/FloorPlans/Edit.cshtml +++ b/PlotLine/Views/FloorPlans/Edit.cshtml @@ -5,6 +5,14 @@ var activeFloor = Model.Floors.OrderBy(x => x.SortOrder).ThenBy(x => x.Name).FirstOrDefault(); var blocksByFloor = Model.Blocks.GroupBy(x => x.FloorPlanFloorID).ToDictionary(x => x.Key, x => x.ToList()); var transitionsByFloor = Model.Transitions.GroupBy(x => x.FloorPlanFloorID).ToDictionary(x => x.Key, x => x.ToList()); + var firstBlockIdByLocation = Model.Blocks + .Where(x => x.LocationID.HasValue) + .GroupBy(x => x.LocationID) + .ToDictionary(x => x.Key!.Value, x => x.OrderBy(block => block.FloorPlanFloorID).ThenBy(block => block.Y).ThenBy(block => block.X).First().FloorPlanBlockID); + var occupancyTokensByLocation = Model.OccupancyTokens + .GroupBy(x => $"{x.SceneID}:{x.LocationID}") + .ToDictionary(x => x.Key, x => x.OrderBy(token => token.EntityType == "Character" ? 0 : 1).ThenBy(token => token.DisplayName).ToList()); + var activeOccupancyScene = Model.OccupancyScenes.FirstOrDefault(); var selectedBlockId = int.TryParse(Context.Request.Query["selectedBlockId"], out var parsedSelectedBlockId) ? parsedSelectedBlockId : 0; string BlockClass(string blockType) => $"floor-plan-block floor-plan-block--{blockType.ToLowerInvariant()}"; string CssNumber(decimal value) => value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); @@ -187,6 +195,21 @@ Saved +
+ + +
+ + + Back to floor plans @@ -232,6 +255,44 @@ @block.DisplayLabel + if (block.LocationID.HasValue && firstBlockIdByLocation.GetValueOrDefault(block.LocationID.Value) == block.FloorPlanBlockID) + { + var locationTokens = Model.OccupancyScenes + .SelectMany(scene => occupancyTokensByLocation.GetValueOrDefault($"{scene.SceneID}:{block.LocationID.Value}") ?? []) + .ToList(); + if (locationTokens.Any()) + { + foreach (var group in locationTokens.GroupBy(x => x.SceneID)) + { + var tokens = group.ToList(); + var tokenTitle = string.Join(", ", tokens.Select(x => x.DisplayName)); +
+ @foreach (var token in tokens.Take(3)) + { + var imagePath = !string.IsNullOrWhiteSpace(token.ThumbnailPath) ? token.ThumbnailPath : token.ImagePath; + + @if (!string.IsNullOrWhiteSpace(imagePath)) + { + @token.DisplayName + } + else + { + @AvatarHelper.Initials(token.DisplayName) + } + + } + @if (tokens.Count > 3) + { + +@(tokens.Count - 3) + } +
+ } + } + } } @foreach (var transition in floorTransitions) { @@ -913,6 +974,12 @@ const saveButtons = [...editor.querySelectorAll("[data-save-layout-button]")]; const gridCoordinatesToggle = editor.querySelector("[data-grid-coordinates-toggle]"); const referenceFloorSelect = editor.querySelector("[data-reference-floor-select]"); + const modeButtons = [...editor.querySelectorAll("[data-floor-plan-mode]")]; + const occupancyControls = [...editor.querySelectorAll("[data-occupancy-controls], .floor-plan-occupancy-control")]; + const occupancySceneSelect = editor.querySelector("[data-occupancy-scene-select]"); + const occupancyPrev = editor.querySelector("[data-occupancy-prev]"); + const occupancyNext = editor.querySelector("[data-occupancy-next]"); + const occupancyTrays = [...editor.querySelectorAll("[data-occupancy-scene]")]; const initialSelectedBlockId = options.selectedBlockId || "@selectedBlockId"; const saveStatusText = { saved: "Saved", @@ -983,6 +1050,54 @@ saveStatus.textContent = message || saveStatusText[state] || state; } + function selectedOccupancySceneId() { + return occupancySceneSelect?.value || ""; + } + + function refreshOccupancyTrays() { + const sceneId = selectedOccupancySceneId(); + const showOccupancy = editor.classList.contains("floor-plan-editor--occupancy"); + occupancyTrays.forEach(tray => { + tray.hidden = !showOccupancy || tray.dataset.occupancyScene !== sceneId; + }); + } + + function setFloorPlanMode(mode) { + const isOccupancy = mode === "occupancy"; + editor.classList.toggle("floor-plan-editor--occupancy", isOccupancy); + modeButtons.forEach(button => { + const active = button.dataset.floorPlanMode === mode; + button.classList.toggle("active", active); + button.setAttribute("aria-pressed", String(active)); + }); + occupancyControls.forEach(control => { + control.hidden = !isOccupancy; + }); + saveButtons.forEach(button => { + button.hidden = isOccupancy; + }); + refreshOccupancyTrays(); + } + + function moveOccupancyScene(direction) { + if (!occupancySceneSelect || occupancySceneSelect.options.length === 0) { + return; + } + + const nextIndex = Math.max(0, Math.min(occupancySceneSelect.options.length - 1, occupancySceneSelect.selectedIndex + direction)); + occupancySceneSelect.selectedIndex = nextIndex; + applyOccupancySceneFloor(); + refreshOccupancyTrays(); + } + + function applyOccupancySceneFloor() { + const option = occupancySceneSelect?.selectedOptions?.[0]; + const initialFloorId = option?.dataset.initialFloorId; + if (initialFloorId) { + setActiveFloor(initialFloorId); + } + } + function gridColumnLabel(index) { let label = ""; let value = index + 1; @@ -2177,6 +2292,13 @@ tabs.forEach(tab => tab.addEventListener("click", () => setActiveFloor(tab.dataset.floorTab))); toolboxTabs.forEach(tab => tab.addEventListener("click", () => setToolboxTab(tab.dataset.toolboxTab))); + modeButtons.forEach(button => button.addEventListener("click", () => setFloorPlanMode(button.dataset.floorPlanMode))); + occupancySceneSelect?.addEventListener("change", () => { + applyOccupancySceneFloor(); + refreshOccupancyTrays(); + }); + occupancyPrev?.addEventListener("click", () => moveOccupancyScene(-1)); + occupancyNext?.addEventListener("click", () => moveOccupancyScene(1)); editor.querySelectorAll("[data-transition-type-select],[data-transition-from-select]").forEach(input => { const floorId = input.dataset.transitionTypeSelect || input.dataset.transitionFromSelect; input.addEventListener("change", () => refreshTransitionDestination(floorId)); @@ -2386,6 +2508,7 @@ } refreshGridCoordinateLabels(); refreshReferenceOverlay(); + refreshOccupancyTrays(); checkOverlaps(); }; diff --git a/PlotLine/Views/Scenes/_SceneInspector.cshtml b/PlotLine/Views/Scenes/_SceneInspector.cshtml index 4367b57..c126dec 100644 --- a/PlotLine/Views/Scenes/_SceneInspector.cshtml +++ b/PlotLine/Views/Scenes/_SceneInspector.cshtml @@ -85,6 +85,7 @@ Threads Assets Locations + Occupancy Custody Story State @@ -106,6 +107,8 @@ + +
@@ -1161,6 +1164,11 @@ +
+

Occupancy

+ +
+

Asset Custody

@if (!Model.AssetCustodyEvents.Any()) diff --git a/PlotLine/Views/Scenes/_SceneOccupancy.cshtml b/PlotLine/Views/Scenes/_SceneOccupancy.cshtml new file mode 100644 index 0000000..e1ea83d --- /dev/null +++ b/PlotLine/Views/Scenes/_SceneOccupancy.cshtml @@ -0,0 +1,98 @@ +@model SceneOccupancyEditorViewModel +@{ + var selectedPlanId = Model.FloorPlanID; + var locationOptions = Model.Locations + .Where(x => !selectedPlanId.HasValue || x.FloorPlanID == selectedPlanId.Value) + .OrderBy(x => x.FloorSortOrder) + .ThenBy(x => x.FloorName) + .ThenBy(x => x.LocationPath) + .ToList(); +} + +
+ +
Saved
+
+
+ + +
+
+ + +
+
+ + @if (!Model.FloorPlanOptions.Any()) + { +

No floor plans exist for this project yet.

+ } + else + { +
+
+

Characters

+ @if (!Model.Characters.Any()) + { +

No characters appear in this scene yet.

+ } + else + { + @for (var i = 0; i < Model.Characters.Count; i++) + { +
+ + @Model.Characters.ElementAt(i).CharacterName + +
+ } + } +
+ +
+

Assets

+ @if (!Model.Assets.Any()) + { +

No story assets appear in this scene yet.

+ } + else + { + @for (var i = 0; i < Model.Assets.Count; i++) + { +
+ + @Model.Assets.ElementAt(i).AssetName + +
+ } + } +
+
+ + + } +
diff --git a/PlotLine/wwwroot/css/site.css b/PlotLine/wwwroot/css/site.css index 27cc621..75abc55 100644 --- a/PlotLine/wwwroot/css/site.css +++ b/PlotLine/wwwroot/css/site.css @@ -5189,6 +5189,116 @@ body.dragging-location [data-drag-type="location"] { color: var(--muted-text, #5d6f65); } +.scene-occupancy-form { + display: grid; + gap: 0.5rem; +} + +.scene-occupancy-status { + justify-self: start; + border-radius: 999px; + padding: 0.2rem 0.55rem; + color: var(--plotline-muted); + background: var(--plotline-soft); + font-size: 0.78rem; + font-weight: 700; +} + +.scene-occupancy-status[data-save-state="saving"] { + color: #7a4d08; + background: #fff4d6; +} + +.scene-occupancy-status[data-save-state="failed"] { + color: #842029; + background: #f8d7da; +} + +.scene-occupancy-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; +} + +.scene-occupancy-grid h4 { + margin: 0 0 0.5rem; + font-size: 0.95rem; +} + +.scene-occupancy-row { + display: grid; + grid-template-columns: minmax(8rem, 0.45fr) minmax(0, 0.55fr); + align-items: center; + gap: 0.5rem; + margin-bottom: 0.45rem; +} + +.floor-plan-editor--occupancy .floor-plan-block { + cursor: default; +} + +.floor-plan-editor--occupancy .floor-plan-resize-handle { + display: none; +} + +.floor-plan-occupancy-tray { + position: absolute; + z-index: 14; + grid-column: calc(var(--x) + 1) / span var(--w); + grid-row: calc(var(--y) + 1) / span var(--h); + align-self: end; + justify-self: center; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 0.18rem; + margin: 0 0 0.25rem; + pointer-events: auto; +} + +.floor-plan-occupancy-tray[hidden] { + display: none; +} + +.floor-plan-occupancy-token { + display: grid; + place-items: center; + width: 1.8rem; + height: 1.8rem; + overflow: hidden; + border: 2px solid #fff; + border-radius: 999px; + color: #fff; + background: var(--plotline-accent); + box-shadow: 0 4px 12px rgba(30, 37, 43, 0.18); + font-size: 0.68rem; + font-weight: 800; +} + +.floor-plan-occupancy-token img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.floor-plan-occupancy-token--asset { + width: 1.45rem; + height: 1.45rem; + background: #805c15; + font-size: 0.58rem; +} + +.floor-plan-occupancy-more { + border-radius: 999px; + padding: 0.15rem 0.36rem; + color: var(--plotline-ink); + background: rgba(255, 255, 255, 0.92); + box-shadow: 0 4px 12px rgba(30, 37, 43, 0.12); + font-size: 0.72rem; + font-weight: 800; +} + .floor-plan-transition-accordion .accordion-item { background: transparent; border-color: var(--border-color, #d8ded9); @@ -5374,6 +5484,24 @@ body.dragging-location [data-drag-type="location"] { border-color: rgba(212, 154, 98, .22); } +[data-bs-theme="dark"] .scene-occupancy-status, +.dark .scene-occupancy-status { + color: #d9c8b8; + background: rgba(212, 154, 98, .12); +} + +[data-bs-theme="dark"] .floor-plan-occupancy-token, +.dark .floor-plan-occupancy-token { + border-color: #1f2630; + box-shadow: 0 4px 12px rgba(0, 0, 0, .28); +} + +[data-bs-theme="dark"] .floor-plan-occupancy-more, +.dark .floor-plan-occupancy-more { + color: #f1e7dd; + background: rgba(31, 38, 48, .92); +} + [data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-item, .dark .floor-plan-transition-accordion .accordion-item { border-color: rgba(212, 154, 98, .22); diff --git a/PlotLine/wwwroot/css/site.min.css b/PlotLine/wwwroot/css/site.min.css index a94e3e0..c0ef3b3 100644 --- a/PlotLine/wwwroot/css/site.min.css +++ b/PlotLine/wwwroot/css/site.min.css @@ -1 +1 @@ -html{font-size:15px;min-height:100%;}@media (min-width:768px){html{font-size:16px;}}:root{--plotline-ink:#1e252b;--plotline-muted:#66717b;--plotline-paper:#fbfaf7;--plotline-panel:#ffffff;--plotline-line:#d8ddd8;--plotline-accent:#2f6f63;--plotline-accent-dark:#22534a;--plotline-soft:#eef5f2;--timeline-label-width:180px;--timeline-scene-width:220px;--timeline-grid-gap:10px;}body{min-height:100%;margin-bottom:0;color:var(--plotline-ink);background:var(--plotline-paper);}a{color:var(--plotline-accent-dark);}.btn-primary{--bs-btn-bg:var(--plotline-accent);--bs-btn-border-color:var(--plotline-accent);--bs-btn-hover-bg:var(--plotline-accent-dark);--bs-btn-hover-border-color:var(--plotline-accent-dark);}.btn-outline-primary{--bs-btn-color:var(--plotline-accent-dark);--bs-btn-border-color:var(--plotline-accent);--bs-btn-hover-bg:var(--plotline-accent);--bs-btn-hover-border-color:var(--plotline-accent);}.plotline-nav{background:rgba(255,255,255,0.94);backdrop-filter:blur(8px);}.plotline-shell{max-width:1480px;padding-left:24px;padding-right:24px;}.plotline-shell-wide{max-width:none;padding-left:clamp(18px,2vw,32px);padding-right:clamp(18px,2vw,32px);}.page-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin:18px 0 24px;}.workspace-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;margin:14px 0 18px;}.workspace-heading h1{margin:0;font-size:clamp(1.8rem,3vw,2.7rem);line-height:1.05;}.page-heading.compact{max-width:980px;}.page-heading h1{margin:0;font-size:clamp(2rem,4vw,3.2rem);line-height:1.05;letter-spacing:0;}.eyebrow{margin:0 0 6px;color:var(--plotline-accent-dark);font-size:0.78rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;}.lead-text{max-width:760px;margin:10px 0 0;color:var(--plotline-muted);font-size:1.05rem;}.button-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}.button-row form,.compact-buttons form,.asset-card-footer form,td.text-end form,form[data-confirm-message]{display:inline-flex;align-items:center;margin:0;}td.text-end{white-space:nowrap;}.content-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;}.plain-card,.empty-panel,.edit-panel,.list-section{background:var(--plotline-panel);border:1px solid var(--plotline-line);border-radius:8px;padding:20px;box-shadow:0 10px 24px rgba(30,37,43,0.04);}.plain-card h2,.empty-panel h2,.list-section h2{margin-top:0;font-size:1.35rem;}.plain-card p,.empty-panel p,.muted{color:var(--plotline-muted);}.edit-panel{max-width:980px;}.trial-status-panel,.trial-dashboard-banner{border:1px solid var(--plotline-line);border-radius:8px;padding:18px 20px;background:var(--plotline-panel);}.trial-status-panel{display:grid;gap:12px;margin-bottom:18px;}.trial-status-panel--signup{grid-template-columns:minmax(0,1fr) auto;align-items:center;max-width:980px;}.trial-status-panel h2,.trial-status-panel h3,.trial-dashboard-banner h2{margin:0;}.trial-status-panel p,.trial-dashboard-banner p{margin-bottom:0;}.trial-status-panel__heading,.trial-dashboard-banner{display:flex;gap:16px;align-items:center;justify-content:space-between;}.trial-dashboard-banner{margin-bottom:18px;}.trial-dashboard-banner__body{min-width:0;}.trial-dashboard-banner__actions{display:flex;flex:0 0 auto;flex-wrap:wrap;gap:8px;}.trial-progress{height:10px;overflow:hidden;border-radius:999px;background:rgba(84,68,48,0.12);}.trial-progress__bar{height:100%;border-radius:inherit;}.trial-status-panel[hidden],.trial-dashboard-banner[hidden]{display:none;}.location-page .page-heading.compact,.location-page .edit-panel,.location-page .empty-panel,.location-page .drag-drop-panel{max-width:none;}.import-panel,.import-preview-section{max-width:none;}.import-json-input{font-family:Consolas,"Liberation Mono",Menlo,monospace;font-size:0.88rem;line-height:1.45;min-height:34rem;max-height:64vh;overflow:auto;resize:vertical;white-space:pre;}.import-preview-heading,.import-counts{display:flex;align-items:flex-start;gap:12px;}.import-preview-heading{justify-content:space-between;margin-bottom:16px;}.import-counts{flex-wrap:wrap;}.import-counts span{display:inline-flex;align-items:baseline;gap:5px;border:1px solid var(--plotline-line);border-radius:999px;padding:5px 11px;background:var(--plotline-soft);color:var(--plotline-muted);font-weight:700;}.import-counts strong{color:var(--plotline-ink);}.import-tree{display:grid;gap:12px;}.import-tree-book{border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:rgba(255,255,255,0.54);}.import-tree-book>summary,.import-tree-chapter>summary{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;}.import-tree-book>summary span,.import-tree-chapter>summary span{color:var(--plotline-muted);font-size:0.84rem;font-weight:700;white-space:nowrap;}.import-tree-book h3{margin:0 0 10px;font-size:1.08rem;}.import-tree-chapter{border-top:1px solid var(--plotline-line);padding:10px 0 0;margin-top:10px;}.import-tree-chapter ul{margin:8px 0 0;color:var(--plotline-muted);}.import-scene-meta{display:block;margin-top:2px;color:var(--plotline-muted);font-size:0.82rem;}.import-mapping-summary{display:grid;gap:6px;border:1px solid rgba(184,118,43,0.28);border-radius:8px;padding:10px 12px;margin-bottom:14px;background:rgba(251,236,211,0.5);color:var(--plotline-muted);font-size:0.9rem;}.import-duplicate-confirm{border:1px solid rgba(184,118,43,0.34);border-radius:8px;padding:12px 12px 12px 38px;background:rgba(251,236,211,0.72);}.import-confirmation,.import-docs details{border:1px solid var(--plotline-line);border-radius:8px;padding:16px;background:rgba(255,255,255,0.42);}.import-confirmation h3,.import-doc-grid h3{margin-top:0;font-size:1.05rem;}.import-docs summary{cursor:pointer;font-weight:800;}.import-doc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-top:14px;}.import-message-list ul{max-height:16rem;overflow:auto;}.scene-editor{max-width:1180px;}.table{margin-bottom:0;}.table th{color:var(--plotline-muted);font-size:0.78rem;letter-spacing:0.06em;text-transform:uppercase;}.narrow{width:90px;white-space:nowrap;}.status-pill{display:inline-flex;align-items:center;width:fit-content;border:1px solid #c8d8d2;border-radius:999px;padding:2px 8px;color:var(--plotline-accent-dark);background:var(--plotline-soft);font-size:0.78rem;font-weight:700;white-space:nowrap;}.dashboard-summary-card{border-color:var(--plotline-line);}.dashboard-summary-body{padding:10px 12px;}.dashboard-summary-label{margin-bottom:4px;font-size:0.7rem;line-height:1.15;}.dashboard-summary-value{display:block;font-size:1.45rem;line-height:1;}.dashboard-summary-calm{border-color:rgba(47,111,99,0.28);background:rgba(238,245,242,0.62);}.dashboard-summary-mild{border-color:rgba(197,139,43,0.32);background:rgba(255,248,232,0.68);}.dashboard-summary-attention{border-color:rgba(142,80,103,0.32);background:rgba(252,241,246,0.7);}.dashboard-progress-card{border-color:rgba(47,111,99,0.18);background:linear-gradient(180deg,#ffffff 0%,rgba(238,245,242,0.64) 100%);}.dashboard-progress-body{padding:12px 14px;}.dashboard-progress-heading{margin-bottom:8px;}.dashboard-progress-title{margin:0 0 2px;font-size:1.05rem;line-height:1.2;}.dashboard-series-progress{height:7px;background:rgba(47,111,99,0.1);}.dashboard-series-progress .progress-bar{background:linear-gradient(90deg,var(--plotline-accent),#6fa99b);}.dashboard-progress-source{border-color:rgba(47,111,99,0.2);color:var(--plotline-accent-dark);background:rgba(238,245,242,0.9);}.dashboard-book-title-block h3{line-height:1.16;}.dashboard-book-title-block a{color:var(--plotline-ink);text-decoration-color:rgba(47,111,99,0.35);}.dashboard-book-subtitle{color:var(--plotline-muted);font-size:0.95rem;line-height:1.25;}.dashboard-status-pill{border-color:var(--dashboard-status-border,#c8d8d2);color:var(--dashboard-status-ink,var(--plotline-accent-dark));background:var(--dashboard-status-bg,var(--plotline-soft));}.dashboard-status-published{--dashboard-status-border:rgba(47,111,99,0.32);--dashboard-status-bg:#e7f2ed;--dashboard-status-ink:#22534a;}.dashboard-status-drafting{--dashboard-status-border:rgba(184,118,43,0.35);--dashboard-status-bg:#fff2dd;--dashboard-status-ink:#7b4b12;}.dashboard-status-planning{--dashboard-status-border:rgba(51,117,155,0.3);--dashboard-status-bg:#e9f3f8;--dashboard-status-ink:#245b78;}.dashboard-status-research,.dashboard-status-outlining{--dashboard-status-border:rgba(103,80,164,0.26);--dashboard-status-bg:#f0edf8;--dashboard-status-ink:#51417c;}.dashboard-status-revising{--dashboard-status-border:rgba(123,82,148,0.3);--dashboard-status-bg:#f4eefa;--dashboard-status-ink:#5f3e73;}.dashboard-status-editing{--dashboard-status-border:rgba(68,75,130,0.3);--dashboard-status-bg:#eceef8;--dashboard-status-ink:#343b72;}.dashboard-status-proofreading{--dashboard-status-border:rgba(43,130,123,0.3);--dashboard-status-bg:#e6f5f2;--dashboard-status-ink:#23625d;}.dashboard-status-ready{--dashboard-status-border:rgba(185,142,30,0.34);--dashboard-status-bg:#fff6d8;--dashboard-status-ink:#765a0f;}.dashboard-status-paused{--dashboard-status-border:rgba(102,113,123,0.28);--dashboard-status-bg:#f0f2f1;--dashboard-status-ink:#56616b;}.dashboard-status-archived{--dashboard-status-border:rgba(139,80,86,0.28);--dashboard-status-bg:#f3eded;--dashboard-status-ink:#76474d;}.dashboard-attention-soft{border-color:rgba(102,113,123,0.24);color:#56616b;background:#f3f4f2;}.order-buttons{display:flex;gap:6px;}.purpose-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:8px;max-height:260px;overflow:auto;padding:10px;border:1px solid var(--plotline-line);border-radius:8px;background:#fcfcfb;}.purpose-check{display:flex;align-items:center;gap:8px;font-size:0.92rem;}.timeline-filter{display:flex;align-items:center;gap:8px;min-width:min(420px,100%);}.workspace-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:0;align-items:start;--timeline-inspector-width:min(40vw,560px);}.workspace-layout.inspector-drawer-open{grid-template-columns:minmax(420px,1fr) 10px minmax(420px,var(--timeline-inspector-width));gap:12px;}.timeline-workspace{min-width:0;max-width:100%;}.timeline-inspector-resizer{position:sticky;top:76px;z-index:25;width:10px;height:calc(100vh - 96px);border-radius:999px;cursor:col-resize;background:linear-gradient(180deg,rgba(47,111,99,0.16),rgba(47,111,99,0.04));}.timeline-inspector-resizer::before{content:"";display:block;width:2px;height:48px;margin:18px auto;border-radius:999px;background:var(--plotline-accent);opacity:0.55;}.timeline-inspector-resizer:hover,.timeline-inspector-resizer:focus-visible{background:rgba(47,111,99,0.16);}body.timeline-inspector-resizing{cursor:col-resize;user-select:none;}.pacing-panel{margin-top:14px;margin-bottom:0;border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:#fff;box-shadow:0 10px 24px rgba(30,37,43,0.04);}.pacing-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px;}.pacing-heading h2{margin:0;font-size:1.1rem;}.metric-graph-stack{display:grid;gap:10px;max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;padding-bottom:4px;}.metric-graph-row{display:grid;grid-template-columns:150px minmax(260px,1fr);gap:10px;align-items:center;min-width:max(100%,calc(150px+(var(--scene-count,1) * 34px)));}.metric-graph-label{color:var(--plotline-muted);font-size:0.84rem;font-weight:700;}.metric-graph-points{display:grid;grid-template-columns:repeat(var(--scene-count),minmax(28px,1fr));gap:5px;align-items:end;min-height:52px;border-radius:8px;padding:6px;background:linear-gradient(180deg,#f6faf8 0%,#edf4f1 100%);min-width:calc(var(--scene-count) * 34px);}.metric-point{display:flex;align-items:flex-end;justify-content:center;height:48px;min-width:28px;color:var(--plotline-accent-dark);text-decoration:none;}.metric-point::before{content:"";display:block;width:100%;height:max(8px,var(--metric-height));border-radius:5px 5px 2px 2px;background:linear-gradient(180deg,#6fa99b,var(--plotline-accent-dark));box-shadow:inset 0 1px 0 rgba(255,255,255,0.35);}.metric-point span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);}.timeline-shell{overflow-x:auto;padding:16px;border:1px solid var(--plotline-line);border-radius:8px;background:linear-gradient(180deg,#ffffff 0%,#f7faf8 100%);}.workspace-timeline{min-height:420px;}.timeline-series-row{display:grid;grid-template-columns:var(--timeline-label-width) max-content;gap:var(--timeline-grid-gap);align-items:stretch;width:max-content;min-width:100%;}.timeline-project-title{position:sticky;left:0;z-index:20;display:grid;align-content:start;gap:4px;width:var(--timeline-label-width);min-height:100%;border-radius:8px;padding:12px;color:#fff;background:var(--plotline-accent-dark);font-weight:700;box-shadow:8px 0 18px rgba(30,37,43,0.08);}.timeline-project-title span,.timeline-book-title span{color:rgba(255,255,255,0.78);font-size:0.72rem;letter-spacing:0.08em;text-transform:uppercase;}.timeline-project-title strong,.timeline-book-title strong{line-height:1.15;}.timeline-books{display:flex;gap:var(--timeline-grid-gap);align-items:stretch;}.timeline-book{flex:0 0 auto;width:calc((var(--book-scene-count) * var(--timeline-scene-width))+((var(--book-scene-count) - 1) * var(--timeline-grid-gap)));min-width:var(--timeline-scene-width);}.timeline-book-title{display:grid;gap:2px;margin-bottom:var(--timeline-grid-gap);border-radius:8px;padding:10px 12px;color:#fff;background:var(--plotline-accent-dark);font-weight:700;}.timeline-chapters{display:flex;gap:var(--timeline-grid-gap);align-items:flex-start;}.timeline-chapter{flex:0 0 auto;width:calc((var(--chapter-scene-count) * var(--timeline-scene-width))+((var(--chapter-scene-count) - 1) * var(--timeline-grid-gap)));min-width:var(--timeline-scene-width);box-sizing:border-box;border-radius:8px;background:rgba(238,245,242,0.7);outline:1px solid #d4ded8;outline-offset:0;overflow:visible;}.timeline-chapter-title{display:grid;gap:2px;border-bottom:1px solid #d4ded8;padding:10px 12px;color:var(--plotline-accent-dark);font-weight:700;}.timeline-chapter-title span{color:var(--plotline-muted);font-size:0.76rem;text-transform:uppercase;}.timeline-scenes{display:grid;grid-template-columns:repeat(var(--chapter-scene-count),minmax(0,1fr));gap:var(--timeline-grid-gap);width:100%;box-sizing:border-box;min-height:190px;padding:0;}.timeline-scene-card,.timeline-empty-scene{display:flex;flex-direction:column;gap:6px;width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--plotline-line);border-radius:8px;padding:12px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 8px 18px rgba(30,37,43,0.05);}.timeline-scene-card:hover{border-color:var(--plotline-accent);color:var(--plotline-ink);}.timeline-placeholder-scene,.timeline-placeholder-cell,.metric-point-placeholder{cursor:default;opacity:0.72;}.timeline-placeholder-scene{align-items:center;justify-content:center;border-style:dashed;color:var(--plotline-muted);background:rgba(255,255,255,0.38);font-size:0.86rem;font-weight:800;text-align:center;}.timeline-placeholder-cell{border-style:dashed;background:repeating-linear-gradient( -45deg,rgba(216,221,216,0.18) 0,rgba(216,221,216,0.18) 7px,rgba(255,255,255,0.18) 7px,rgba(255,255,255,0.18) 14px );}.metric-point-placeholder::before{height:4px;background:rgba(102,113,123,0.2);box-shadow:none;}.timeline-scene-card.selected{border-color:var(--plotline-accent-dark);box-shadow:0 0 0 3px rgba(47,111,99,0.16),0 10px 22px rgba(30,37,43,0.08);}.scene-badge-row,.purpose-chip-row{display:flex;flex-wrap:wrap;gap:5px;align-items:center;}.warning-placeholder{display:inline-flex;width:fit-content;border:1px dashed #d6b25e;border-radius:999px;padding:2px 8px;color:#755715;background:#fff8e8;font-size:0.74rem;font-weight:700;}.warning-placeholder.active{border-color:rgba(159,69,69,0.36);color:#8a3434;background:rgba(255,232,232,0.9);gap:5px;font-weight:800;}.dependency-placeholder{display:inline-flex;width:fit-content;border:1px solid rgba(47,111,99,0.2);border-radius:999px;padding:2px 8px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);font-size:0.74rem;font-weight:700;}.purpose-chip{display:inline-flex;width:fit-content;border-radius:999px;padding:2px 7px;color:#38453e;background:#edf0eb;font-size:0.72rem;font-weight:700;}.future-lane-placeholder{border-top:1px dashed #cbd8d2;padding:8px 12px;color:var(--plotline-muted);font-size:0.78rem;background:rgba(255,255,255,0.45);}.metric-timeline-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.metric-shape-controls{position:sticky;left:0;z-index:6;display:grid;gap:8px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;border-radius:8px;padding:10px;background:rgba(255,255,255,0.88);}.metric-timeline-row{display:grid;grid-template-columns:var(--timeline-label-width) calc((var(--scene-count) * var(--timeline-scene-width))+((var(--scene-count) - 1) * var(--timeline-grid-gap)));gap:var(--timeline-grid-gap);align-items:stretch;}.metric-lane-label{position:sticky;left:0;z-index:12;display:grid;align-content:start;gap:4px;min-height:320px;border:1px solid rgba(47,111,99,0.18);border-radius:8px;padding:10px;color:var(--plotline-accent-dark);background:#fff;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.metric-lane-label span{color:var(--plotline-muted);font-size:0.78rem;font-weight:600;}.colour-swatch{display:inline-block;width:18px;height:18px;border:1px solid rgba(30,37,43,0.18);border-radius:999px;vertical-align:middle;}.plot-lane-board{position:relative;display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.plot-lane-svg-overlay{position:absolute;inset:0 auto auto 0;z-index:4;pointer-events:none;overflow:visible;}.plot-lane-svg-health-overlay{z-index:8;}.plot-line-svg-path{fill:none;stroke-width:3.5;stroke-linecap:round;opacity:0.72;}.plot-line-svg-segment-dormant{stroke-dasharray:9 8;opacity:0.48;}.plot-line-svg-connector{fill:none;stroke-width:3;stroke-linecap:round;opacity:0.58;}.plot-line-svg-path.plotline-state-resolved,.plot-line-svg-path.plotline-state-questionable{stroke:#8c9491;opacity:0.42;}.plot-line-svg-path.plotline-state-abandoned{stroke:#9b2f36;opacity:0.5;}.plot-event-svg-node.plotline-state-resolved,.plot-event-svg-node.plotline-state-questionable{opacity:0.88;}.plot-event-svg-node.plotline-state-abandoned{opacity:0.9;}.plot-event-svg-node.plotline-state-abandoned line{stroke:#ffffff;}.plotline-health-marker path,.plotline-health-marker circle{fill:#f4c430;stroke:#8a6712;stroke-width:1.5;}.plotline-health-marker{pointer-events:visiblePainted;}.plotline-health-marker line,.plotline-health-marker text{stroke:#5e4710;fill:#5e4710;stroke-width:1.6;stroke-linecap:round;}.plotline-health-marker text{font-size:11px;font-weight:800;stroke-width:0;pointer-events:none;}.plotline-health-count{fill:#ffffff;stroke:#8a6712;stroke-width:2;paint-order:stroke;}.plotline-health-marker-dangling path,.plotline-health-marker-dangling circle{fill:#f8df8f;}.plotline-health-marker-abandoned path,.plotline-health-marker-abandoned circle{fill:#d85c63;stroke:#8b1e2d;}.plotline-health-marker-abandoned line{stroke:#ffffff;}.plot-event-svg-node circle,.plot-event-svg-node ellipse,.plot-event-svg-node path{stroke:#ffffff;stroke-width:2;}.plot-event-svg-node line,.plot-event-svg-node path[fill="none"]{stroke:#8b1e2d;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round;}.plot-event-svg-node-reveal ellipse{stroke-width:2.4;}.plot-event-svg-label{font-size:9.5px;font-weight:900;font-family:system-ui,-apple-system,"Segoe UI",sans-serif;paint-order:stroke;stroke:rgba(30,37,43,0.22);stroke-width:0.8px;pointer-events:none;}.plot-event-svg-node-resolve path[fill="none"]{stroke:#ffffff;}.lane-board-heading,.metric-lane-board-heading,.plot-lane-board-heading{position:sticky;left:0;z-index:6;display:flex;align-items:center;justify-content:space-between;gap:14px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;margin-bottom:2px;border-radius:8px;padding:8px 10px;color:var(--plotline-accent-dark);background:rgba(255,255,255,0.92);font-weight:700;box-shadow:0 8px 16px rgba(30,37,43,0.05);}.lane-board-heading small,.metric-lane-board-heading small,.plot-lane-board-heading small{color:var(--plotline-muted);font-weight:500;white-space:nowrap;}.timeline-heading-with-help{display:inline-flex;align-items:center;gap:6px;min-width:0;}.plot-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.plot-lane-label{position:sticky;left:0;z-index:12;display:flex;align-items:center;gap:8px;min-height:46px;border:1px solid color-mix(in srgb,var(--plot-colour),#ffffff 55%);border-left:5px solid var(--plot-colour);border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.plot-lane-label:hover{color:var(--plotline-ink);border-color:var(--plot-colour);}.plot-lane-slots{display:contents;}.plot-lane-slot{display:flex;flex-wrap:wrap;align-content:center;align-items:center;justify-content:center;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(255,255,255,0.62);}.thread-marker{position:relative;z-index:5;display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:34px;height:30px;border:2px solid color-mix(in srgb,var(--plot-colour),#000000 20%);border-radius:999px;padding:0 8px;color:var(--plotline-ink);background:color-mix(in srgb,var(--plot-colour),#ffffff 66%);font-size:0.74rem;font-weight:900;text-decoration:none;box-shadow:0 3px 8px rgba(30,37,43,0.14);}.plot-lane-board [data-plot-event-node]{opacity:1;}.thread-marker:hover,.thread-marker:focus-visible{color:var(--plotline-ink);background:color-mix(in srgb,var(--plot-colour),#ffffff 48%);outline:3px solid rgba(47,111,99,0.22);outline-offset:2px;}.thread-marker.resolved{border-color:#5a8c60;background:#e6f4e7;color:#24512b;}.thread-marker.contradicted{border-color:#b45c5c;background:#fff0f0;color:#7a2222;}.thread-events-section{margin-top:16px;}.thread-event-list{display:grid;gap:8px;margin-bottom:12px;}.thread-event-item{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;border:1px solid color-mix(in srgb,var(--plot-colour),#ffffff 55%);border-left:4px solid var(--plot-colour);border-radius:8px;padding:8px;background:#fff;}.thread-event-item>div{display:grid;gap:3px;}.thread-event-marker{display:inline-flex;align-items:center;justify-content:center;width:fit-content;min-width:24px;height:22px;border-radius:999px;padding:0 7px;background:color-mix(in srgb,var(--plot-colour),#ffffff 72%);font-size:0.72rem;font-weight:800;}.thread-event-create{border-top:1px solid var(--plotline-line);padding-top:12px;}.asset-lane-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.asset-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.asset-lane-label{position:sticky;left:0;z-index:12;display:grid;gap:2px;min-height:46px;border:1px solid #d4d7df;border-left:5px solid #6b5b95;border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.asset-lane-label span{color:var(--plotline-muted);font-size:0.75rem;}.asset-lane-slots{display:contents;}.asset-lane-slot{display:flex;flex-wrap:wrap;align-content:flex-start;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(250,249,255,0.72);}.asset-marker,.asset-event-marker{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:24px;border:1px solid #7f70aa;border-radius:7px;padding:0 7px;color:#33284e;background:#eee9fb;font-size:0.72rem;font-weight:800;text-decoration:none;}.asset-marker:hover{color:#33284e;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;}.asset-event-list,.asset-mini-list{display:grid;gap:8px;margin-bottom:12px;}.asset-event-item,.asset-mini-item{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;border:1px solid #ded9ea;border-left:4px solid #6b5b95;border-radius:8px;padding:8px;background:#fff;}.asset-event-item>div,.asset-mini-item>div{display:grid;gap:3px;}.asset-create-form{border-top:1px solid var(--plotline-line);padding-top:12px;}.asset-card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px;}.asset-card{display:grid;gap:12px;border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:#fff;box-shadow:0 8px 18px rgba(30,37,43,0.04);}.asset-card h2{margin:0;font-size:1.1rem;}.asset-card-footer{display:flex;flex-wrap:wrap;align-items:center;gap:6px;}.asset-detail-grid{display:grid;grid-template-columns:minmax(260px,0.8fr) minmax(320px,1.2fr);gap:14px;}.character-lane-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.character-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.character-lane-label{position:sticky;left:0;z-index:12;display:grid;gap:2px;min-height:46px;border:1px solid #d7d4ce;border-left:5px solid #8a6f3d;border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.character-lane-label span{color:var(--plotline-muted);font-size:0.75rem;}.character-lane-slots{display:contents;}.character-lane-slot{display:flex;flex-wrap:wrap;align-content:flex-start;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(255,252,246,0.72);}.character-marker{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:24px;border:1px solid #9a7a3f;border-radius:999px;padding:0 7px;color:#4f3810;background:#fff2d7;font-size:0.72rem;font-weight:800;text-decoration:none;}.character-card{border-left:4px solid #8a6f3d;}.character-section{margin-top:16px;}.character-item{border-left-color:#8a6f3d;}.character-appearance-card{display:grid;gap:8px;border:1px solid #d7d4ce;border-left:4px solid #8a6f3d;border-radius:8px;padding:10px;background:#fff;}.character-appearance-summary{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;}.character-appearance-summary>div:first-child{display:grid;gap:3px;}.character-appearance-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;}.character-appearance-edit .asset-create-form{margin-top:8px;border-top:1px solid var(--plotline-line);}.form-helper-message{margin:0 0 8px;font-size:0.86rem;font-weight:700;}.scene-number,.time-label{color:var(--plotline-muted);font-size:0.82rem;}.location-pill,.location-badge{display:inline-flex;align-items:center;width:fit-content;border:1px solid rgba(47,111,99,0.18);border-radius:999px;padding:2px 7px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);font-size:0.74rem;font-weight:700;}.scene-summary{display:-webkit-box;overflow:hidden;color:var(--plotline-muted);font-size:0.88rem;-webkit-box-orient:vertical;-webkit-line-clamp:4;}.timeline-empty-scene{justify-content:center;color:var(--plotline-muted);background:rgba(255,255,255,0.58);}.form-control:focus,.form-select:focus,.form-check-input:focus{border-color:var(--plotline-accent);box-shadow:0 0 0 0.2rem rgba(47,111,99,0.16);}.scene-inspector-panel{position:sticky;top:76px;display:flex;flex-direction:column;max-height:calc(100vh - 96px);min-width:0;overflow:hidden;border:1px solid var(--plotline-line);border-radius:8px;background:#fff;box-shadow:0 14px 32px rgba(30,37,43,0.08);}.inspector-header{position:sticky;top:0;z-index:5;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;border-bottom:1px solid var(--plotline-line);padding:16px;background:#fff;}.scene-inspector-body{flex:1 1 auto;min-height:0;overflow:auto;padding:16px;}.inspector-header h2{margin:0;font-size:1.25rem;}.scene-inspector-form{display:grid;gap:14px;}.inspector-section{border-top:1px solid var(--plotline-line);padding-top:12px;}.inspector-section:first-of-type{border-top:0;padding-top:0;}.inspector-section h3{margin:0 0 10px;font-size:0.95rem;color:var(--plotline-accent-dark);}.location-helper{border:1px solid rgba(138,111,61,0.22);border-radius:8px;padding:10px;background:rgba(255,248,232,0.74);}.location-warning-list{margin:0;padding-left:18px;color:#6f5526;font-size:0.86rem;}.location-tree{display:grid;gap:8px;}.location-tree-row{display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--plotline-line);padding:10px 0 10px calc(var(--location-depth,0) * 22px);}.location-tree-row:last-child{border-bottom:0;}.location-tree-row>div:first-child{display:grid;gap:3px;}.compact-buttons{flex-wrap:nowrap;}.location-chip-list{display:flex;flex-wrap:wrap;gap:8px;}.location-chip{border:1px solid var(--plotline-line);border-radius:8px;padding:7px 10px;background:#fff;text-decoration:none;}.location-relationship-list{display:grid;gap:8px;}.location-relationship-card{display:flex;justify-content:space-between;gap:12px;border:1px solid var(--plotline-line);border-radius:8px;padding:10px;background:#fff;}.location-flags{display:flex;flex-wrap:wrap;gap:10px 16px;color:var(--plotline-muted);font-size:0.86rem;}.validation-summary,.warning-filter-panel{border:1px solid var(--plotline-line);border-radius:8px;margin-bottom:16px;padding:12px;background:#fff;}.validation-summary{display:flex;flex-wrap:wrap;gap:12px;color:var(--plotline-muted);}.warning-dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-bottom:18px;}.warning-count-row,.warning-card-title,.inspector-section-heading{display:flex;align-items:center;justify-content:space-between;gap:10px;}.warning-list,.warning-mini-list{display:grid;gap:10px;}.warning-card,.warning-mini-card{border:1px solid var(--plotline-line);border-radius:8px;padding:12px;background:#fff;}.warning-card{display:grid;grid-template-columns:1fr auto;gap:12px;}.warning-card p,.warning-mini-card p{margin:6px 0;}.warning-actions{display:flex;align-items:flex-start;flex-wrap:wrap;gap:6px;}.severity-pill{display:inline-flex;align-items:center;border-radius:999px;padding:2px 8px;font-size:0.74rem;font-weight:800;}.severity-pill.info{color:#365f7c;background:rgba(107,153,184,0.14);}.severity-pill.warning{color:#7a5527;background:rgba(205,154,72,0.17);}.severity-pill.error{color:#8a3434;background:rgba(190,83,83,0.15);}.warning-mini-card{background:rgba(255,255,255,0.76);}.dependency-columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;}.dependency-card{display:grid;gap:3px;border:1px solid var(--plotline-line);border-radius:8px;margin-bottom:8px;padding:9px;background:rgba(255,255,255,0.78);}.move-preview-panel{max-width:900px;}.focused-validation-summary{display:flex;flex-wrap:wrap;gap:10px;border:1px solid rgba(47,111,99,0.16);border-radius:8px;margin-top:12px;padding:10px;color:var(--plotline-muted);background:rgba(47,111,99,0.05);}.inspector-purpose-list{grid-template-columns:1fr;max-height:210px;}.metric-slider-stack{display:grid;gap:12px;}.metric-slider{display:grid;gap:4px;}.metric-slider-label{display:flex;justify-content:space-between;gap:10px;color:var(--plotline-muted);font-size:0.86rem;font-weight:700;}.metric-slider-label output{color:var(--plotline-accent-dark);}.metric-slider .form-range{accent-color:var(--plotline-accent);}.asset-importance-slider{border:1px solid var(--plotline-line);border-radius:8px;padding:10px 12px;background:rgba(47,111,99,0.05);}.story-asset-checkbox-field{margin-top:1.95rem;}.story-asset-event-item{justify-content:flex-start;gap:8px;}.story-asset-event-item .asset-event-marker{flex:0 0 auto;min-width:1.55rem;width:auto;}.story-asset-event-details{min-width:0;}.scene-inspector-root{display:grid;gap:12px;}.scene-overview-card{display:grid;gap:10px;border:1px solid rgba(47,111,99,0.18);border-radius:10px;padding:12px;background:linear-gradient(180deg,rgba(47,111,99,0.08),rgba(255,255,255,0.88));}.scene-overview-card h3{margin:0;font-size:1.05rem;}.scene-overview-card .muted{display:flex;flex-wrap:wrap;gap:7px;margin:0;}.overview-chip-grid,.context-nav,.breadcrumb-trail,.inspector-nav-links{display:flex;flex-wrap:wrap;gap:7px;}.overview-chip,.context-nav a,.breadcrumb-trail a,.breadcrumb-trail span{display:inline-flex;align-items:center;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-decoration:none;background:rgba(255,255,255,0.72);}.overview-chip.attention{color:#7a5527;border-color:rgba(205,154,72,0.35);background:rgba(205,154,72,0.14);}.overview-outcome{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;margin:0;color:var(--plotline-muted);}.inspector-quick-nav{position:sticky;top:0;z-index:5;display:grid;gap:8px;border:1px solid var(--plotline-line);border-radius:10px;padding:10px;background:rgba(255,255,255,0.94);box-shadow:0 10px 24px rgba(55,48,39,0.08);backdrop-filter:blur(8px);}.inspector-nav-links a{border:1px solid var(--plotline-line);border-radius:999px;padding:4px 8px;color:var(--plotline-muted);font-size:0.76rem;font-weight:800;text-decoration:none;}.inspector-nav-links a:hover,.inspector-nav-links a.active{color:var(--plotline-accent-dark);border-color:rgba(47,111,99,0.35);background:rgba(47,111,99,0.08);}.inspector-accordion-toggle{display:flex;align-items:center;justify-content:space-between;width:100%;border:0;padding:0;color:var(--plotline-ink);font-size:0.95rem;font-weight:900;text-align:left;background:transparent;}.inspector-accordion-toggle::before{content:"+";display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:999px;margin-right:7px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.09);}.inspector-section.is-open>.inspector-accordion-toggle::before{content:"-";}.inspector-accordion-toggle span:first-child{margin-right:auto;}.accordion-count{color:var(--plotline-muted);font-size:0.75rem;}.inspector-subheading{margin:14px 0 8px;color:var(--plotline-muted);font-size:0.88rem;font-weight:900;}.inspector-accordion-body{display:none;margin-top:12px;}.inspector-section.is-open>.inspector-accordion-body{display:block;}.inspector-section.is-filtered-out{display:none;}.breadcrumb-trail{margin-bottom:12px;}.breadcrumb-trail a:hover,.context-nav a:hover{color:var(--plotline-accent-dark);border-color:rgba(47,111,99,0.35);background:rgba(47,111,99,0.08);}.context-header,.working-context-banner{display:flex;align-items:center;justify-content:space-between;gap:14px;border:1px solid var(--plotline-line);border-radius:10px;margin-bottom:16px;padding:10px 12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.context-title{display:grid;gap:2px;}.context-title strong{color:var(--plotline-ink);}.health-kpi-grid,.analytics-grid-two,.analytics-grid-three{display:grid;gap:14px;margin:18px 0;}.health-kpi-grid{grid-template-columns:repeat(4,minmax(0,1fr));}.health-kpi-grid .plain-card{display:grid;gap:4px;}.health-kpi-grid strong{color:var(--plotline-ink);font-size:2rem;line-height:1;}.analytics-grid-two{grid-template-columns:repeat(2,minmax(0,1fr));}.analytics-grid-three{grid-template-columns:repeat(3,minmax(0,1fr));}.analytics-section{border:1px solid var(--plotline-line);border-radius:10px;margin:18px 0;padding:16px;background:rgba(255,255,255,0.84);box-shadow:0 14px 34px rgba(55,48,39,0.07);}.analytics-section-heading{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:14px;}.analytics-section-heading h2,.plain-card h3{margin:0;}.analytics-metric-stack{display:grid;gap:12px;overflow-x:auto;padding-bottom:4px;}.metric-shape-chart{display:grid;gap:12px;}.metric-shape-intro{max-width:760px;margin:0;color:var(--plotline-muted);}.metric-toggle-row{display:flex;flex-wrap:wrap;gap:8px;}.metric-toggle-pill{display:inline-flex;align-items:center;gap:6px;border:1px solid rgba(82,75,65,0.16);border-radius:999px;padding:5px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.78);cursor:pointer;}.metric-toggle-pill::before{content:"";width:10px;height:10px;border-radius:999px;background:var(--metric-colour);}.metric-toggle-pill input{margin:0;accent-color:var(--metric-colour);}.timeline-metric-edit-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:end;}.timeline-metric-edit-select{display:grid;gap:3px;min-width:180px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;}.timeline-metric-edit-status{align-self:center;border:1px solid rgba(47,111,99,0.18);border-radius:999px;padding:5px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.72);}.timeline-metric-edit-hint{font-size:0.82rem;}.metric-chart-frame canvas.metric-curve-editing{cursor:ns-resize;}.metric-chart-frame{position:relative;min-height:320px;border:1px solid var(--plotline-line);border-radius:10px;padding:14px 12px 32px;background:linear-gradient(180deg,rgba(255,255,255,0.92),rgba(247,245,240,0.76));}.metric-timeline-frame{width:calc((var(--scene-count) * var(--timeline-scene-width))+((var(--scene-count) - 1) * var(--timeline-grid-gap)));}.metric-chart-frame canvas{width:100%;height:300px;}.metric-timeline-board .metric-graph-stack{width:max-content;min-width:100%;}.metric-timeline-board .metric-graph-row{grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);min-width:100%;}.metric-timeline-board .metric-graph-points{display:contents;}.metric-timeline-board .metric-point{border:1px solid rgba(47,111,99,0.12);border-radius:8px;background:rgba(255,255,255,0.62);}.metric-raw-details{border-top:1px solid var(--plotline-line);padding-top:8px;}.metric-raw-details summary{color:var(--plotline-muted);font-size:0.82rem;font-weight:800;cursor:pointer;}.timeline-control-panel{display:grid;gap:12px;border:1px solid var(--plotline-line);border-radius:10px;margin-bottom:16px;padding:12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.timeline-filter-drawer summary{color:var(--plotline-ink);font-weight:900;cursor:pointer;}.timeline-filter-grid{display:grid;grid-template-columns:repeat(6,minmax(130px,1fr));gap:10px;margin-top:12px;}.timeline-filter-checks,.timeline-filter-actions,.timeline-visibility-panel,.timeline-preset-panel,.preset-chip-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}.timeline-filter-checks{grid-column:span 3;color:var(--plotline-muted);font-size:0.82rem;font-weight:700;}.timeline-filter-actions{grid-column:span 3;justify-content:flex-end;}.timeline-visibility-panel label,.preset-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 8px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.76);}.timeline-preset-panel form{display:inline-flex;align-items:center;gap:6px;}.preset-chip a{color:var(--plotline-accent-dark);text-decoration:none;}.preset-chip button{border:0;color:var(--plotline-muted);background:transparent;font-weight:900;}.timeline-focus-banner{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid rgba(47,111,99,0.22);border-radius:10px;margin-bottom:16px;padding:10px 12px;background:rgba(47,111,99,0.08);}.thread-marker-icon{display:inline-flex;align-items:center;justify-content:center;min-width:16px;font-size:0.78rem;font-weight:900;}.thread-marker-type-start .thread-marker-icon,.thread-marker-type-resolve .thread-marker-icon,.thread-marker-type-abandon .thread-marker-icon,.thread-marker-type-twist .thread-marker-icon{font-size:0.9rem;}.thread-marker-type-start{border-radius:8px 999px 999px 8px;}.thread-marker-type-twist{border-color:#b8762b;background:#fff4dc;}.thread-marker-type-branch,.thread-marker-type-split,.thread-marker-type-merge{border-color:#6750a4;background:#f0ebff;}.thread-marker-type-reveal .thread-marker-icon{border:1px solid currentColor;border-radius:999px;font-size:0;}.thread-marker-type-reveal .thread-marker-icon::after{content:"";width:4px;height:4px;border-radius:999px;background:currentColor;}.timeline-navigation-card{display:grid;grid-template-areas:"icon copy" "icon actions";grid-template-columns:auto minmax(0,620px);gap:8px 14px;align-items:center;justify-content:center;border:1px solid rgba(47,111,99,0.42);border-left:5px solid var(--plotline-accent);border-radius:8px;margin:0 0 12px;padding:14px 16px;max-height:280px;overflow:hidden;color:var(--plotline-ink);background:linear-gradient(135deg,rgba(238,245,242,0.98),rgba(255,255,255,0.94));box-shadow:0 10px 26px rgba(30,37,43,0.08);opacity:1;transform:translateY(0);transition:opacity 1.15s ease,max-height 1.2s ease,margin 1.2s ease,padding 1.2s ease,transform 1.15s ease;}.timeline-navigation-card[hidden]{display:none;}.timeline-navigation-card.is-dismissing{margin-bottom:0;padding-top:0;padding-bottom:0;max-height:0;opacity:0;transform:translateY(-6px);}.timeline-navigation-card-icon{grid-area:icon;display:grid;place-items:center;width:42px;height:42px;border-radius:50%;color:#fff;background:var(--plotline-accent);font-size:1.25rem;font-weight:900;}.timeline-navigation-card-copy{grid-area:copy;text-align:center;}.timeline-navigation-card-copy h2{margin:0 0 6px;color:var(--plotline-accent-dark);font-size:1rem;font-weight:900;}.timeline-navigation-card-copy p{margin:2px 0;color:var(--plotline-ink);font-size:0.9rem;}.timeline-navigation-card-actions{grid-area:actions;display:flex;flex-wrap:wrap;gap:8px;justify-content:center;}.timeline-horizontal-overflow{transition:box-shadow 0.18s ease;}.timeline-horizontal-overflow.has-scroll-left{box-shadow:inset 18px 0 18px -20px rgba(30,37,43,0.55);}.timeline-horizontal-overflow.has-scroll-right{box-shadow:inset -18px 0 18px -20px rgba(30,37,43,0.55);}.timeline-horizontal-overflow.has-scroll-left.has-scroll-right{box-shadow:inset 18px 0 18px -20px rgba(30,37,43,0.55),inset -18px 0 18px -20px rgba(30,37,43,0.55);}[data-theme="dark"] .timeline-navigation-card{border-color:rgba(111,169,155,0.52);border-left-color:#6fa99b;color:#f4eadc;background:linear-gradient(135deg,rgba(34,83,74,0.72),rgba(32,31,34,0.96));box-shadow:0 12px 28px rgba(0,0,0,0.28);}[data-theme="dark"] .timeline-navigation-card-copy h2,[data-theme="dark"] .timeline-navigation-card-copy p{color:#f4eadc;}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-left{box-shadow:inset 18px 0 18px -20px rgba(244,234,220,0.55);}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-right{box-shadow:inset -18px 0 18px -20px rgba(244,234,220,0.55);}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-left.has-scroll-right{box-shadow:inset 18px 0 18px -20px rgba(244,234,220,0.55),inset -18px 0 18px -20px rgba(244,234,220,0.55);}@media (prefers-reduced-motion:reduce){.timeline-navigation-card{transition:opacity 0.12s ease;}}.timeline-scene-card.filter-dim,.timeline-scene-card.focus-dim,.lane-dim{opacity:0.35;}.timeline-scene-card.focus-match,.timeline-scene-card.filter-match.focus-match{outline:3px solid rgba(47,111,99,0.32);box-shadow:0 12px 26px rgba(47,111,99,0.16);}.timeline-section-hidden{display:none !important;}.hide-scene-cards .timeline-scene-card{display:none;}.timeline-control-panel{position:sticky;top:56px;z-index:18;}.timeline-control-select{padding-right:6px;}.timeline-control-select .form-select{width:auto;min-width:132px;border:0;padding-top:2px;padding-bottom:2px;background-color:transparent;color:var(--plotline-accent-dark);font-weight:800;}.timeline-jump-panel{display:grid;grid-template-columns:auto minmax(180px,1.2fr) minmax(180px,1fr) minmax(170px,0.9fr) minmax(180px,1fr) auto;gap:8px;align-items:center;width:100%;}.timeline-shortcut-hint{color:var(--plotline-muted);font-size:0.76rem;font-weight:700;white-space:nowrap;}.timeline-minimap{display:flex;align-items:stretch;gap:4px;margin:0 0 12px;padding:8px;max-width:100%;min-width:0;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-gutter:stable;border:1px solid rgba(47,111,99,0.18);border-radius:8px;background:rgba(255,255,255,0.72);}.timeline-minimap button{position:relative;flex:0 0 max(42px,calc(var(--chapter-scenes) * 18px));min-width:42px;min-height:34px;border:1px solid rgba(47,111,99,0.18);border-radius:7px;color:var(--plotline-accent-dark);background:linear-gradient(180deg,#f8fbf9 0%,#edf4f1 100%);font-size:0.72rem;font-weight:800;}.timeline-minimap button.is-active{border-color:var(--plotline-accent);color:#fff;background:linear-gradient(180deg,var(--plotline-accent) 0%,var(--plotline-accent-dark) 100%);box-shadow:0 0 0 2px rgba(47,111,99,0.14);}.timeline-minimap button::after{content:"";position:absolute;right:5px;bottom:5px;width:calc(var(--chapter-warnings) * 4px);max-width:28px;height:4px;border-radius:999px;background:#b45c5c;opacity:0.75;}.timeline-drag-palette,.drag-drop-panel{border:1px solid rgba(47,111,99,0.18);border-radius:10px;margin-bottom:12px;padding:12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.timeline-drag-palette{display:grid;grid-template-columns:minmax(220px,0.35fr) minmax(0,1fr);gap:12px;align-items:center;}.drag-chip-group{display:flex;flex-wrap:wrap;gap:6px;max-height:104px;overflow:auto;padding-right:4px;}.drag-chip{display:inline-flex;align-items:center;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 9px;background:#fff;color:var(--plotline-ink);font-size:0.78rem;font-weight:800;cursor:grab;}.drag-chip.character{border-color:#dacb9e;background:#fff8e8;}.drag-chip.asset{border-color:#ded9ea;background:#f4f0ff;}.drag-chip.location{border-color:rgba(47,111,99,0.18);background:#eef8f4;}.is-dragging{opacity:0.55;}.drop-target-active{outline:3px solid rgba(47,111,99,0.28);outline-offset:2px;}.timeline-chapter.chapter-drop-active,.timeline-scenes.drop-chapter-end{background:rgba(47,111,99,0.06);}.timeline-scenes.drop-chapter-end::after{content:"Drop scene at end of chapter";display:flex;align-items:center;justify-content:center;min-width:var(--timeline-scene-width);min-height:74px;border:2px dashed rgba(197,139,43,0.48);border-radius:12px;color:#7a5527;background:rgba(255,248,232,0.82);font-size:0.8rem;font-weight:900;}.timeline-scene-card.drop-before{box-shadow:inset 5px 0 0 #c58b2b,0 12px 26px rgba(197,139,43,0.16);}.timeline-scene-card.drop-after{box-shadow:inset -5px 0 0 #c58b2b,0 12px 26px rgba(197,139,43,0.16);}.drag-drop-panel{position:sticky;top:132px;z-index:19;}.drag-drop-panel-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;}.drag-drop-panel h2{margin:0;font-size:1.08rem;}.drag-drop-form{border-top:1px solid var(--plotline-line);margin-top:10px;padding-top:10px;}.scene-move-modal-content{border:1px solid rgba(47,111,99,0.18);border-radius:14px;background:var(--plotline-surface);color:var(--plotline-ink);box-shadow:0 24px 70px rgba(55,48,39,0.22);}.scene-move-modal-content .modal-header,.scene-move-modal-content .modal-footer{border-color:var(--plotline-line);}.scene-move-modal-content .modal-title{margin:0;color:var(--plotline-ink);font-size:1.2rem;font-weight:900;}.scene-move-summary{margin:0 0 12px;color:var(--plotline-ink);font-size:1rem;font-weight:800;}[data-theme="dark"] .scene-move-modal-content{background:#201f22;color:#f4eadc;border-color:rgba(244,234,220,0.16);box-shadow:0 24px 70px rgba(0,0,0,0.55);}[data-theme="dark"] .scene-move-modal-content .modal-title,[data-theme="dark"] .scene-move-summary{color:#f4eadc;}[data-theme="dark"] .scene-move-modal-content .modal-header,[data-theme="dark"] .scene-move-modal-content .modal-footer{border-color:rgba(244,234,220,0.14);}[data-theme="dark"] .scene-move-modal-content .btn-close{filter:invert(1) grayscale(100%);}.plain-preview{border:1px solid rgba(197,139,43,0.28);border-radius:8px;margin:10px 0 0;padding:8px 10px;color:#5e4518;background:#fff8e8;font-size:0.86rem;font-weight:800;}.drag-check-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 10px;color:var(--plotline-muted);font-size:0.82rem;font-weight:700;}.timeline-section-header,.lane-board-heading,.pacing-heading{position:sticky;left:0;z-index:6;}.timeline-section-header{display:flex;align-items:center;justify-content:space-between;gap:10px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;margin-bottom:10px;border-radius:8px;padding:8px 10px;background:rgba(255,255,255,0.92);box-shadow:0 8px 16px rgba(30,37,43,0.05);}.timeline-section-header button,.lane-board-heading button,.plot-lane-board-heading button,.pacing-heading button,.lane-group-heading{border:0;padding:0;color:var(--plotline-accent-dark);background:transparent;font:inherit;font-weight:900;text-align:left;}.timeline-section-header button::before,.lane-board-heading button::before,.plot-lane-board-heading button::before,.pacing-heading button::before,.lane-group-heading::before{content:"v";display:inline-block;margin-right:6px;color:var(--plotline-muted);font-size:0.72rem;}.timeline-section-header button.is-collapsed::before,.lane-board-heading button.is-collapsed::before,.plot-lane-board-heading button.is-collapsed::before,.pacing-heading button.is-collapsed::before,.lane-group-heading.is-collapsed::before{content:">";}.lane-group{display:grid;gap:7px;}.character-lane-group-body{display:grid;gap:7px;}.lane-group-heading{position:sticky;left:0;z-index:6;width:var(--timeline-label-width);border-top:1px solid rgba(47,111,99,0.12);padding:7px 8px 2px;color:var(--plotline-muted);background:rgba(247,250,248,0.96);font-size:0.78rem;text-transform:uppercase;}.timeline-section-collapsed{display:none !important;}.timeline-chapter-title{position:sticky;top:0;z-index:5;background:rgba(238,245,242,0.96);backdrop-filter:blur(6px);}.scene-pov-label,.metric-mini-summary{display:inline-flex;width:fit-content;border-radius:999px;padding:2px 7px;font-size:0.72rem;font-weight:800;}.scene-pov-label{color:#514018;background:#fff3d3;}.metric-mini-summary{color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);}.scene-overview-panel{display:none;gap:8px;margin-top:4px;}.scene-overview-section{display:grid;gap:4px;}.scene-overview-label{color:var(--plotline-muted);font-size:0.68rem;font-weight:900;letter-spacing:0.06em;text-transform:uppercase;}.scene-overview-chip-row{display:flex;flex-wrap:wrap;gap:5px;min-width:0;}.scene-overview-chip,.scene-overview-empty,.scene-overview-brief{display:inline-flex;width:fit-content;max-width:100%;border-radius:999px;padding:3px 8px;background:rgba(47,111,99,0.08);color:var(--plotline-ink);font-size:0.72rem;font-weight:750;line-height:1.25;overflow-wrap:anywhere;}.scene-overview-chip.is-pov{border:1px solid rgba(197,139,43,0.38);background:#fff3d3;}.scene-overview-chip.is-important{border:1px solid rgba(103,80,164,0.3);background:#f0edf8;}.scene-overview-chip.is-more,.scene-overview-empty{color:var(--plotline-muted);background:rgba(102,113,123,0.08);}.scene-overview-brief{display:block;width:auto;border-radius:8px;background:rgba(255,255,255,0.62);color:var(--plotline-muted);font-weight:600;}.timeline-scene-card.search-hit,.timeline-scene-card.keyboard-focus{outline:3px solid rgba(197,139,43,0.34);box-shadow:0 12px 26px rgba(197,139,43,0.16);}.timeline-scene-card.search-dim{opacity:0.28;}.thread-marker,.asset-marker,.character-marker{transition:transform 0.12s ease,box-shadow 0.12s ease;}.thread-marker:hover,.asset-marker:hover,.character-marker:hover{transform:translateY(-1px);box-shadow:0 6px 12px rgba(30,37,43,0.12);}.timeline-filtered-root.density-compact{--timeline-scene-width:170px;--timeline-grid-gap:6px;}.timeline-filtered-root.density-expanded{--timeline-scene-width:280px;--timeline-grid-gap:14px;}.timeline-filtered-root.density-compact .timeline-scene-card,.timeline-filtered-root.zoom-book .timeline-scene-card{gap:4px;padding:9px;}.timeline-filtered-root.density-compact .scene-summary,.timeline-filtered-root.density-compact .purpose-chip-row,.timeline-filtered-root.density-compact .metric-mini-summary,.timeline-filtered-root.zoom-book .scene-summary,.timeline-filtered-root.zoom-book .purpose-chip-row,.timeline-filtered-root.zoom-book .metric-mini-summary,.timeline-filtered-root.zoom-book .location-pill,.timeline-filtered-root.zoom-book .scene-pov-label{display:none;}.timeline-filtered-root.zoom-book{--timeline-scene-width:150px;--timeline-grid-gap:6px;}.timeline-filtered-root.zoom-scene-detail{--timeline-scene-width:300px;}.timeline-filtered-root.zoom-scene-detail .scene-summary{-webkit-line-clamp:7;}.timeline-filtered-root.zoom-scene-overview{--timeline-scene-width:380px;}.timeline-filtered-root.zoom-scene-overview .timeline-scenes{min-height:320px;}.timeline-filtered-root.zoom-scene-overview .timeline-scene-card{gap:8px;padding:14px;}.timeline-filtered-root.zoom-scene-overview .scene-summary{display:none;}.timeline-filtered-root.zoom-scene-overview .scene-overview-panel{display:grid;}.timeline-filtered-root.density-expanded .timeline-scenes{min-height:230px;}.timeline-control-panel{position:relative;top:auto;z-index:4;display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:10px;padding:8px;box-shadow:none;}.timeline-filter-drawer,.timeline-control-group{border:1px solid var(--plotline-line);border-radius:999px;background:rgba(255,255,255,0.82);}.timeline-filter-drawer[open],.timeline-control-group[open]{border-radius:10px;flex-basis:100%;}.timeline-filter-drawer summary,.timeline-control-group summary{min-width:max-content;padding:5px 10px;color:var(--plotline-accent-dark);font-size:0.82rem;font-weight:900;cursor:pointer;list-style:none;}.timeline-filter-drawer summary::-webkit-details-marker,.timeline-control-group summary::-webkit-details-marker,.timeline-drag-palette summary::-webkit-details-marker{display:none;}.timeline-filter-drawer summary::after,.timeline-control-group summary::after,.timeline-drag-palette summary::after{content:" v";color:var(--plotline-muted);font-size:0.72rem;}.timeline-filter-drawer[open] summary::after,.timeline-control-group[open] summary::after,.timeline-drag-palette[open] summary::after{content:" ^";}.timeline-filter-grid{grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;max-height:min(48vh,430px);overflow:auto;padding:0 10px 10px;}.timeline-filter-grid .form-label{margin-bottom:2px;font-size:0.72rem;font-weight:800;}.timeline-filter-checks,.timeline-filter-actions{grid-column:1 / -1;}.timeline-visibility-panel,.timeline-jump-panel,.timeline-preset-panel{padding:0 10px 10px;}.timeline-jump-panel{grid-template-columns:minmax(180px,1.5fr) repeat(3,minmax(150px,1fr));}.timeline-shortcut-hint{grid-column:1 / -1;}.timeline-preset-panel form{flex-wrap:nowrap;}.timeline-preset-panel .form-control{width:150px;}.timeline-preset-panel .btn,.timeline-filter-actions .btn{white-space:nowrap;}.timeline-drag-palette{display:block;margin-bottom:8px;padding:7px 9px;box-shadow:none;}.timeline-drag-palette summary{color:var(--plotline-accent-dark);font-size:0.82rem;font-weight:900;cursor:pointer;}.timeline-drag-palette .drag-chip-group{margin-top:8px;}.drag-drop-panel{position:relative;top:auto;z-index:9;box-shadow:0 12px 28px rgba(30,37,43,0.08);}.timeline-filtered-root,.timeline-filtered-root.density-compact,.timeline-filtered-root.zoom-book{--timeline-scene-width:220px;--timeline-grid-gap:10px;}.timeline-filtered-root.density-expanded,.timeline-filtered-root.zoom-scene-detail{--timeline-scene-width:290px;}.timeline-filtered-root.density-compact.zoom-book{--timeline-scene-width:200px;}.timeline-chapter,.timeline-scene-card,.timeline-empty-scene{overflow-wrap:normal;word-break:normal;}.timeline-scene-card strong,.timeline-chapter-title strong,.plot-lane-label strong,.asset-lane-label strong,.character-lane-label strong{min-width:0;white-space:normal;word-break:normal;overflow-wrap:break-word;}.timeline-scene-card{cursor:grab;}.timeline-scene-card:active,.drag-chip:active,[draggable="true"]:active{cursor:grabbing;}body.drag-active .timeline-scene-card,body.dragging-asset [data-asset-drop-target],body.dragging-location [data-drag-type="location"]{transition:outline-color 0.12s ease,box-shadow 0.12s ease,opacity 0.12s ease;}body.dragging-character .timeline-scene-card,body.dragging-asset .timeline-scene-card,body.dragging-scene .timeline-scene-card,body.dragging-scene .timeline-scenes[data-chapter-drop-target],body.dragging-asset [data-asset-drop-target],body.dragging-location [data-drag-type="location"]{outline:1px dashed rgba(47,111,99,0.22);outline-offset:2px;}.is-dragging{opacity:0.42;transform:scale(0.98);}.drop-target-active{outline:3px solid rgba(47,111,99,0.42) !important;outline-offset:3px;}.analytics-metric-row{display:grid;grid-template-columns:170px minmax(560px,1fr);gap:12px;align-items:stretch;}.analytics-metric-label{display:flex;align-items:center;border-right:1px solid var(--plotline-line);color:var(--plotline-muted);font-weight:800;}.analytics-sparkline{display:grid;grid-template-columns:repeat(var(--point-count),minmax(28px,1fr));align-items:end;gap:5px;min-height:88px;border-bottom:1px solid rgba(47,111,99,0.25);padding-top:10px;}.analytics-bar{position:relative;display:flex;align-items:end;justify-content:center;min-height:12px;height:max(12px,var(--bar-height));border-radius:6px 6px 2px 2px;color:var(--plotline-accent-dark);text-decoration:none;background:linear-gradient(180deg,rgba(47,111,99,0.58),rgba(47,111,99,0.18));}.analytics-bar:hover{background:linear-gradient(180deg,rgba(47,111,99,0.82),rgba(47,111,99,0.28));}.analytics-bar span{position:absolute;bottom:calc(100%+3px);color:var(--plotline-muted);font-size:0.68rem;font-weight:800;}.analytics-list-item,.analytics-link-row,.analytics-count-row,.purpose-stat-row{border-top:1px solid var(--plotline-line);padding:9px 0;}.analytics-list-item{display:grid;gap:3px;}.analytics-list-item p{margin:0;}.analytics-link-row,.analytics-count-row{display:flex;align-items:center;justify-content:space-between;gap:12px;}.analytics-link-row{color:inherit;text-decoration:none;}.analytics-link-row:hover{color:var(--plotline-accent-dark);}.analytics-link-row span,.analytics-link-row strong{min-width:0;}.purpose-stat-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(90px,1.5fr) 42px;align-items:center;gap:10px;}.purpose-stat-bar{overflow:hidden;height:8px;border-radius:999px;background:rgba(47,111,99,0.08);}.purpose-stat-bar span{display:block;height:100%;border-radius:inherit;background:var(--plotline-accent);}.inspector-actions{position:sticky;bottom:-16px;display:flex;gap:8px;border-top:1px solid var(--plotline-line);margin:2px -16px -16px;padding:12px 16px;background:rgba(255,255,255,0.95);backdrop-filter:blur(8px);}.story-bible-heading{align-items:end;}.story-bible-search{display:flex;gap:8px;min-width:min(100%,420px);}.story-bible-search .form-control{min-width:0;}.story-bible-nav{position:sticky;top:72px;z-index:4;display:flex;flex-wrap:wrap;gap:8px;margin:0 0 18px;padding:10px;border:1px solid var(--plotline-line);border-radius:12px;background:rgba(250,249,246,0.92);backdrop-filter:blur(10px);}.story-bible-nav a,.story-bible-actions a{display:inline-flex;align-items:center;border-radius:999px;padding:6px 10px;background:rgba(47,111,99,0.08);color:var(--plotline-ink);font-size:0.86rem;font-weight:650;text-decoration:none;}.story-bible-nav a:hover,.story-bible-actions a:hover{background:rgba(47,111,99,0.16);}.story-bible-section{margin:0 0 28px;}.story-bible-section-heading{display:flex;align-items:end;justify-content:space-between;gap:16px;margin-bottom:12px;}.story-bible-section-heading h2{margin:0;}.soft-count{color:var(--plotline-muted);font-size:0.9rem;font-weight:650;white-space:nowrap;}.story-bible-grid,.story-bible-search-results{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;}.story-bible-grid-compact{grid-template-columns:repeat(auto-fit,minmax(260px,1fr));}.story-bible-card{border:1px solid var(--plotline-line);border-radius:14px;padding:14px;background:rgba(255,255,255,0.86);box-shadow:0 14px 34px rgba(36,32,26,0.06);}.story-bible-card h3{margin:0 0 8px;font-size:1.05rem;}.story-bible-card h4{margin:14px 0 8px;font-size:0.96rem;}.story-bible-card p{color:var(--plotline-muted);}.story-bible-card-title{display:flex;align-items:start;justify-content:space-between;gap:10px;}.story-bible-card-title span{border:1px solid var(--plotline-line);border-radius:999px;padding:3px 8px;background:rgba(250,249,246,0.9);color:var(--plotline-muted);font-size:0.78rem;font-weight:700;white-space:nowrap;}.story-bible-meta{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0;}.story-bible-meta span{border-radius:999px;padding:4px 8px;background:rgba(36,32,26,0.05);color:var(--plotline-muted);font-size:0.78rem;font-weight:650;}.story-bible-facts{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 10px;margin:12px 0;}.story-bible-facts dt{color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-transform:uppercase;}.story-bible-facts dd{margin:0;min-width:0;overflow-wrap:anywhere;}.story-bible-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;}.story-bible-link-list{display:grid;gap:8px;margin:0;padding:0;list-style:none;}.story-bible-link-list li{display:grid;gap:2px;padding:8px 0;border-bottom:1px solid rgba(36,32,26,0.08);}.story-bible-link-list li:last-child{border-bottom:0;}.story-bible-link-list span{color:var(--plotline-muted);font-size:0.88rem;}.story-bible-timeline-summary{display:grid;gap:14px;}.story-bible-wide-card{max-width:none;}.story-bible-chapter-summary{border-top:1px solid var(--plotline-line);padding-top:8px;}.story-bible-scene-summary{display:grid;grid-template-columns:minmax(220px,1.5fr) repeat(3,minmax(120px,0.8fr));gap:8px;padding:9px 0;border-top:1px solid rgba(36,32,26,0.08);}.story-bible-scene-summary p{grid-column:1 / -1;margin:0;}.story-bible-scene-summary span{color:var(--plotline-muted);font-size:0.88rem;}.attention-list{display:grid;gap:10px;}.attention-list article{display:grid;grid-template-columns:max-content minmax(0,1fr) auto;align-items:center;gap:10px;border:1px solid var(--plotline-line);border-radius:12px;padding:10px 12px;background:rgba(255,255,255,0.82);}.attention-list p{grid-column:2 / -1;margin:0;color:var(--plotline-muted);}.writer-workspace-form,.writer-add-form,.writer-edit-form,.chapter-goal-form{display:grid;gap:10px;}.writer-checkbox-grid{display:flex;flex-wrap:wrap;gap:8px 14px;}.writer-checkbox-grid label{display:inline-flex;align-items:center;gap:6px;color:var(--plotline-muted);font-size:0.86rem;font-weight:650;}.writer-priority-control{display:grid;grid-template-columns:minmax(0,1fr) max-content;align-items:center;gap:12px;}.writer-priority-control .form-range{min-width:0;}.writer-note-list,.writer-queue-list{display:grid;gap:10px;}.writer-mini-card{border:1px solid var(--plotline-line);border-radius:12px;padding:10px;background:rgba(255,255,255,0.72);}.writer-mini-card summary{display:flex;align-items:center;gap:8px;cursor:pointer;}.writer-mini-card summary strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.attachment-card-list{display:grid;gap:10px;}.attachment-summary{align-items:center;}.attachment-kind{border-radius:999px;padding:3px 8px;background:rgba(47,111,99,0.1);color:var(--plotline-accent);font-size:0.76rem;font-weight:800;text-transform:uppercase;}.attachment-card-body{display:grid;gap:6px;margin-top:10px;}.attachment-card-body p{margin:0;}.attachment-add-card{margin-top:10px;}.writer-checklist{display:grid;gap:6px;}.writer-checklist-row,.writer-add-inline{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;}.writer-remove-inline{display:flex;justify-content:end;margin:-2px 0 4px;}.writer-dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin-bottom:26px;}.writer-dashboard-panel{border:1px solid var(--plotline-line);border-radius:14px;padding:14px;background:rgba(255,255,255,0.7);box-shadow:0 14px 34px rgba(36,32,26,0.05);}.writer-queue-card{border:1px solid var(--plotline-line);border-radius:12px;padding:12px;background:rgba(255,255,255,0.9);}.writer-queue-card h3{margin:0;font-size:1rem;}.writer-queue-card p{margin:8px 0 0;color:var(--plotline-muted);}.writer-queue-title{display:flex;align-items:start;justify-content:space-between;gap:12px;}.writer-kpi{display:block;color:var(--plotline-accent);font-size:2.2rem;line-height:1;}.export-action-row{margin:-8px 0 18px;}.dynamics-timeline{position:relative;min-height:128px;border:1px solid var(--plotline-line);border-radius:14px;background:linear-gradient(180deg,rgba(47,111,99,0.07),rgba(255,255,255,0.84));overflow:hidden;}.dynamics-timeline::before{content:"";position:absolute;left:12px;right:12px;top:64px;height:1px;background:rgba(36,32,26,0.18);}.dynamics-marker{position:absolute;bottom:18px;width:12px;height:86px;transform:translateX(-50%);display:flex;align-items:end;justify-content:center;}.dynamics-marker span{display:block;width:8px;min-height:12px;max-height:82px;border-radius:999px;background:var(--plotline-accent);box-shadow:0 8px 20px rgba(47,111,99,0.22);}.dynamics-marker.pov span{background:#8a4b2f;}.dynamics-timeline.relationship .dynamics-marker span{background:#7c5fb0;}.scenario-banner{display:flex;justify-content:space-between;gap:18px;align-items:flex-start;border:1px solid rgba(103,80,164,0.22);border-radius:12px;padding:16px;margin-bottom:16px;background:linear-gradient(135deg,rgba(103,80,164,0.10),rgba(255,255,255,0.86));box-shadow:0 12px 28px rgba(36,32,26,0.08);}.scenario-banner h1{margin:0 0 4px;}.scenario-banner p{margin:0;color:var(--plotline-muted);}.scenario-card{border-color:rgba(103,80,164,0.18);}.scenario-warning-strip{display:flex;gap:10px;align-items:center;border:1px solid var(--plotline-line);border-radius:10px;padding:10px 12px;margin-bottom:14px;background:rgba(255,255,255,0.76);color:var(--plotline-muted);}.scenario-warning-strip strong{color:var(--plotline-ink);}.scenario-board{border:1px solid var(--plotline-line);border-radius:12px;padding:12px;background:rgba(247,245,240,0.74);overflow:hidden;margin-bottom:18px;}.scenario-scroll{display:flex;gap:14px;overflow-x:auto;padding-bottom:8px;}.scenario-chapter{min-width:360px;max-width:520px;border:1px solid rgba(82,75,65,0.14);border-radius:10px;background:rgba(255,255,255,0.86);}.scenario-chapter header{display:grid;gap:2px;border-bottom:1px solid var(--plotline-line);padding:10px 12px;}.scenario-chapter header span{color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-transform:uppercase;}.scenario-scene-row{display:grid;gap:10px;padding:10px;}.scenario-scene-card{display:grid;gap:8px;border:1px solid rgba(82,75,65,0.12);border-radius:9px;padding:10px;background:white;}.scenario-scene-title{display:grid;gap:2px;}.scenario-scene-title span,.scenario-mini-data{color:var(--plotline-muted);font-size:0.78rem;}.scenario-mini-data{display:grid;gap:2px;}.scenario-move-actions,.scenario-chapter-form,.scenario-compare-list article{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}.scenario-chapter-form select{min-width:160px;width:auto;}.scenario-compare-list{display:grid;gap:10px;}.scenario-compare-list article{justify-content:space-between;border:1px solid var(--plotline-line);border-radius:9px;padding:10px;background:rgba(255,255,255,0.82);}.danger-zone{border-color:rgba(163,61,61,0.24);}.archive-filter-form{align-items:end;}.archive-item-list{display:grid;gap:10px;}.archive-item-card{display:flex;justify-content:space-between;gap:14px;align-items:center;border:1px solid var(--plotline-line);border-radius:10px;padding:12px;background:rgba(255,255,255,0.82);}.archive-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-items:end;}.delete-forever-form{display:inline-flex;margin:0;}.archive-item-card h3{margin:4px 0;}.archived-badge{display:inline-flex;border:1px solid rgba(82,75,65,0.16);border-radius:999px;padding:2px 8px;color:var(--plotline-muted);font-size:0.72rem;font-weight:800;text-transform:uppercase;background:rgba(247,245,240,0.86);}.restore-button{white-space:nowrap;}.archive-button-form{display:inline-flex;align-items:center;margin:0;}.acceptance-summary-grid{display:grid;grid-template-columns:repeat(3,minmax(160px,1fr));gap:12px;margin-bottom:16px;}.acceptance-summary{display:grid;gap:4px;padding:16px;}.acceptance-summary strong{font-size:2rem;line-height:1;}.acceptance-summary.pass{border-left:5px solid #4d7654;}.acceptance-summary.review{border-left:5px solid #b8762b;}.acceptance-summary.blocked{border-left:5px solid #963f36;}.acceptance-check-list{display:grid;gap:14px;}.acceptance-area{border:1px solid var(--plotline-line);border-radius:10px;padding:12px;background:rgba(255,255,255,0.62);}.acceptance-area h3{margin:0 0 10px;font-size:1.05rem;}.acceptance-check-items{display:grid;gap:8px;}.acceptance-check-item{display:grid;grid-template-columns:92px minmax(0,1fr);gap:10px;align-items:start;border:1px solid rgba(82,75,65,0.12);border-radius:8px;padding:10px;background:rgba(255,255,255,0.74);}.acceptance-check-item p{margin:2px 0 0;color:var(--plotline-muted);}.acceptance-status{display:inline-flex;justify-content:center;width:fit-content;min-width:74px;border-radius:999px;padding:3px 9px;font-size:0.72rem;font-weight:900;text-transform:uppercase;}.acceptance-check-item.pass .acceptance-status{color:#24512b;background:#e6f4e7;}.acceptance-check-item.review .acceptance-status{color:#7b4b13;background:#fbecd3;}.acceptance-check-item.blocked .acceptance-status{color:#7a2222;background:#fff0f0;}.plotline-confirm-modal .modal-title{color:var(--plotline-ink);}.plotline-confirm-modal .modal-body p{white-space:pre-line;}.delete-confirm-field{border:1px solid rgba(163,61,61,0.22);border-radius:8px;padding:12px;background:rgba(255,247,244,0.7);}@media print{header,.breadcrumb-trail,.context-header,.button-row,.story-bible-nav,.inspector-quick-nav{display:none !important;}.plotline-shell{max-width:none;padding:0;}}@media (max-width:760px){.plotline-shell{padding-left:14px;padding-right:14px;}.page-heading{display:block;}.page-heading .button-row,.timeline-filter{margin-top:14px;}.timeline-filter{align-items:stretch;flex-direction:column;}.timeline-navigation-card{grid-template-areas:"copy" "actions";grid-template-columns:1fr;}.timeline-navigation-card-icon{display:none;}.timeline-navigation-card-actions{justify-content:center;}.story-bible-search,.story-bible-section-heading{align-items:stretch;flex-direction:column;}.story-bible-scene-summary,.attention-list article{grid-template-columns:1fr;}.writer-dashboard-grid{grid-template-columns:1fr;}.writer-checklist-row,.writer-add-inline{grid-template-columns:1fr;}.trial-status-panel--signup,.trial-status-panel__heading,.trial-dashboard-banner{align-items:stretch;flex-direction:column;}.trial-dashboard-banner__actions,.trial-dashboard-banner__actions .btn,.trial-status-panel--signup .btn{width:100%;}.attention-list p{grid-column:auto;}}@media (max-width:900px){.workspace-layout,.workspace-layout.inspector-drawer-open{grid-template-columns:1fr;gap:14px;}.timeline-inspector-resizer{display:none;}.scene-inspector-panel{position:static;max-height:none;overflow:visible;}.scene-inspector-body{max-height:none;overflow:visible;}}@media (max-width:1100px){.metric-graph-row{grid-template-columns:1fr;}.health-kpi-grid,.analytics-grid-two,.analytics-grid-three{grid-template-columns:1fr;}.analytics-metric-row{grid-template-columns:1fr;}.analytics-metric-label{border-right:0;}}.floor-plan-list{display:grid;gap:12px;}.floor-plan-list-item{align-items:center;border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:flex;justify-content:space-between;gap:16px;padding:14px;}.floor-plan-list-item h2{font-size:1.05rem;margin:0 0 4px;}.floor-plan-list-item p{margin:0;}.floor-plan-tools{display:grid;gap:14px;}.floor-plan-meta-wide{max-width:none;}.floor-plan-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;}.floor-plan-tab{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:999px;color:inherit;padding:6px 12px;}.floor-plan-tab.active{background:var(--bs-primary,#2f6f63);border-color:var(--bs-primary,#2f6f63);color:#fff;}.floor-plan-layout{display:grid;gap:16px;grid-template-columns:minmax(0,1fr) minmax(320px,360px);}.floor-plan-editor-toolbar{align-items:center;background:rgba(255,255,255,.92);border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:grid;gap:12px;grid-template-columns:auto minmax(0,1fr) auto;margin-bottom:12px;padding:10px 12px;position:sticky;top:10px;z-index:20;}.floor-plan-editor-toolbar .muted{display:block;font-size:.76rem;line-height:1.1;}.floor-plan-toolbar-check,.floor-plan-reference-control{align-items:center;color:var(--muted-color,#6b756f);display:inline-flex;font-size:.82rem;font-weight:700;gap:6px;}.floor-plan-reference-control{align-items:flex-start;flex-direction:column;gap:2px;}.floor-plan-reference-control .form-select{min-width:180px;}.floor-plan-save-status{border:1px solid rgba(47,111,99,.2);border-radius:999px;color:var(--plotline-accent-dark,#22534a);background:rgba(47,111,99,.08);font-size:.78rem;font-weight:800;padding:4px 9px;}.floor-plan-save-status[data-save-state="dirty"]{border-color:rgba(184,118,43,.32);color:#7b4b12;background:rgba(251,236,211,.72);}.floor-plan-save-status[data-save-state="saving"]{border-color:rgba(51,117,155,.3);color:#245b78;background:rgba(233,243,248,.82);}.floor-plan-save-status[data-save-state="failed"]{border-color:rgba(163,61,61,.32);color:#8a3434;background:rgba(255,232,232,.9);}.floor-plan-floor{display:none;}.floor-plan-floor.active{display:block;}.floor-plan-stage{min-width:0;}.floor-plan-grid-wrap{max-width:100%;max-height:calc(100vh - 250px);min-height:min(58vh,520px);overflow:auto;padding-bottom:8px;}.floor-plan-grid{--cell-size:34px;background:linear-gradient(to right,rgba(93,111,101,.18) 1px,transparent 1px),linear-gradient(to bottom,rgba(93,111,101,.18) 1px,transparent 1px),var(--panel-bg,#fff);background-size:var(--cell-size) var(--cell-size),var(--cell-size) var(--cell-size),auto;border:1px solid var(--border-color,#d8ded9);border-radius:8px;height:calc(var(--grid-height) * var(--cell-size));min-width:calc(var(--grid-width) * var(--cell-size));position:relative;width:calc(var(--grid-width) * var(--cell-size));}.floor-plan-coordinate-label{color:rgba(33,61,55,.42);font-size:.62rem;font-weight:800;line-height:1;pointer-events:none;position:absolute;text-shadow:0 1px 0 rgba(255,255,255,.7);user-select:none;z-index:5;}.floor-plan-coordinate-label--column{left:calc(var(--coord-x) * var(--cell-size)+4px);top:3px;}.floor-plan-coordinate-label--row{left:4px;top:calc(var(--coord-y) * var(--cell-size)+4px);}.floor-plan-reference-overlay{inset:0;pointer-events:none;position:absolute;z-index:1;}.floor-plan-reference-block{align-items:center;background:rgba(47,111,99,.08);border:1px dashed rgba(47,111,99,.34);border-radius:2px;color:rgba(27,55,49,.46);display:flex;font-size:.62rem;font-weight:800;height:calc(var(--h) * var(--cell-size));justify-content:center;left:calc(var(--x) * var(--cell-size));line-height:1.05;overflow:hidden;padding:3px;position:absolute;text-align:center;top:calc(var(--y) * var(--cell-size));width:calc(var(--w) * var(--cell-size));}.floor-plan-reference-warning{background:rgba(251,236,211,.92);border:1px solid rgba(184,118,43,.34);border-radius:999px;color:#7b4b12;font-size:.76rem;font-weight:800;left:10px;padding:4px 10px;pointer-events:none;position:absolute;top:10px;z-index:6;}.floor-plan-background-image{height:auto;left:0;max-width:none;opacity:var(--bg-opacity,.35);pointer-events:none;position:absolute;top:0;transform:translate(var(--bg-offset-x,0),var(--bg-offset-y,0)) scale(var(--bg-scale,1));transform-origin:top left;user-select:none;width:100%;z-index:0;}.floor-plan-background-image.is-locked{pointer-events:none;}.floor-plan-block{align-items:center;--floor-plan-wall-color:rgba(44,84,75,.55);border:2px solid transparent;border-radius:2px;color:#12332c;cursor:grab;display:flex;font-size:.72rem;font-weight:700;height:calc(var(--h) * var(--cell-size));justify-content:center;left:calc(var(--x) * var(--cell-size));line-height:1.08;overflow:hidden;padding:4px;position:absolute;text-align:center;top:calc(var(--y) * var(--cell-size));touch-action:none;width:calc(var(--w) * var(--cell-size));z-index:2;}.floor-plan-wall-segment{background:var(--floor-plan-wall-color);pointer-events:none;position:absolute;z-index:2;}.floor-plan-wall-segment--north,.floor-plan-wall-segment--south{height:2px;left:var(--wall-start);width:var(--wall-length);}.floor-plan-wall-segment--north{top:0;}.floor-plan-wall-segment--south{bottom:0;}.floor-plan-wall-segment--east,.floor-plan-wall-segment--west{height:var(--wall-length);top:var(--wall-start);width:2px;}.floor-plan-wall-segment--east{right:0;}.floor-plan-wall-segment--west{left:0;}.floor-plan-block-label{display:-webkit-box;max-width:100%;overflow:hidden;overflow-wrap:normal;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:1;}.floor-plan-block[style*="--h:2"] .floor-plan-block-label,.floor-plan-block[style*="--h:3"] .floor-plan-block-label,.floor-plan-block[style*="--h:4"] .floor-plan-block-label,.floor-plan-block[style*="--h:5"] .floor-plan-block-label,.floor-plan-block[style*="--h:6"] .floor-plan-block-label,.floor-plan-block[style*="--h:7"] .floor-plan-block-label,.floor-plan-block[style*="--h:8"] .floor-plan-block-label{-webkit-line-clamp:2;}.floor-plan-block.selected{box-shadow:0 0 0 3px rgba(47,111,99,.28);outline:2px solid var(--bs-primary,#2f6f63);z-index:3;}.floor-plan-block.overlap{border-color:#b45544;box-shadow:inset 0 0 0 2px rgba(180,85,68,.18);}.floor-plan-block.is-hidden-location{background-image:repeating-linear-gradient(135deg,rgba(18,51,44,.08) 0,rgba(18,51,44,.08) 3px,transparent 3px,transparent 9px);box-shadow:inset 0 0 0 1px rgba(43,54,49,.18);}.floor-plan-block.is-hidden-location.selected{box-shadow:inset 0 0 0 1px rgba(43,54,49,.18),0 0 0 3px rgba(47,111,99,.28);}.floor-plan-block.is-hidden-location.overlap{box-shadow:inset 0 0 0 2px rgba(180,85,68,.18),inset 0 0 0 1px rgba(43,54,49,.18);}.floor-plan-secret-route{border-top:2px dashed rgba(69,55,42,.58);height:0;left:calc(var(--route-x,0) * var(--cell-size));opacity:.72;pointer-events:none;position:absolute;top:calc(var(--route-y,0) * var(--cell-size));transform:rotate(var(--route-angle,0));transform-origin:0 50%;width:calc(var(--route-length,0) * var(--cell-size));z-index:3;}.floor-plan-secret-route::after{background:rgba(255,250,242,.9);border:1px solid rgba(69,55,42,.5);border-radius:50%;content:"";height:7px;left:50%;position:absolute;top:-5px;transform:translateX(-50%);width:7px;}.floor-plan-transition-marker{align-items:center;--transition-marker-ink:#12332c;--transition-marker-window:#246f9f;--transition-marker-blocked:#9b342b;background:rgba(255,250,242,.98);border:1px solid rgba(47,111,99,.55);border-radius:50%;box-shadow:0 2px 6px rgba(31,37,34,.16);color:var(--transition-marker-ink);display:flex;font-size:.72rem;font-weight:900;height:21px;justify-content:center;left:calc(var(--transition-x,0) * var(--cell-size));line-height:1;pointer-events:none;position:absolute;top:calc(var(--transition-y,0) * var(--cell-size));transform:translate(-50%,-50%);width:21px;z-index:4;}.floor-plan-transition-marker svg{display:block;height:21px;overflow:visible;width:21px;}.floor-plan-transition-marker.is-vertical svg{transform:rotate(90deg);}.floor-plan-transition-marker .marker-line,.floor-plan-transition-marker .marker-arc,.floor-plan-transition-marker .marker-window,.floor-plan-transition-marker .marker-blocked{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.7;}.floor-plan-transition-marker .marker-arc{stroke-width:1.35;}.floor-plan-transition-marker .marker-window{stroke:var(--transition-marker-window);}.floor-plan-transition-marker .marker-dotted{opacity:.72;stroke-dasharray:1.4 2;}.floor-plan-transition-marker .marker-blocked{stroke:var(--transition-marker-blocked);stroke-width:1.8;}.floor-plan-transition-marker .marker-strong{stroke-width:2;}.floor-plan-transition-marker .marker-track{opacity:.72;}.floor-plan-transition-marker--window{background:rgba(239,249,255,.98);border-color:rgba(36,111,159,.48);}.floor-plan-transition-marker--sliding-door{background:rgba(248,252,249,.98);border-color:rgba(47,111,99,.58);}.floor-plan-transition-marker--french-door{background:rgba(255,252,246,.98);border-color:rgba(119,86,45,.5);}.floor-plan-transition-marker--secret-door{background:rgba(255,250,242,.88);border-style:dashed;}.floor-plan-transition-marker--ladder{background:rgba(246,248,245,.98);border-color:rgba(77,91,67,.55);}.floor-plan-transition-marker--blocked-door{background:rgba(255,244,241,.98);border-color:rgba(155,52,43,.52);}.floor-plan-transition-marker--exterior-door{border-width:2px;}.floor-plan-transition-marker.is-shared-edge{background:rgba(255,255,255,.98);border-color:rgba(47,111,99,.72);}.floor-plan-transition-marker--window.is-shared-edge{background:rgba(239,249,255,.98);border-color:rgba(36,111,159,.58);}.floor-plan-transition-marker--blocked-door.is-shared-edge{background:rgba(255,244,241,.98);border-color:rgba(155,52,43,.6);}.visual-card-heading{align-items:flex-start;display:flex;gap:12px;}.visual-card-heading>div{min-width:0;}.visual-avatar{align-items:center;aspect-ratio:1;background:linear-gradient(135deg,rgba(47,111,99,.16),rgba(212,154,98,.16));border:1px solid rgba(47,111,99,.22);border-radius:999px;color:var(--plotline-accent-dark,#22534a);display:inline-flex;flex:0 0 auto;font-weight:900;justify-content:center;letter-spacing:.02em;overflow:hidden;text-transform:uppercase;}.visual-avatar img{height:100%;object-fit:cover;width:100%;}.visual-avatar--sm{font-size:.72rem;width:32px;}.visual-avatar--md{font-size:.9rem;width:48px;}.visual-avatar--lg{font-size:1.3rem;width:96px;}.visual-avatar--xl{font-size:1.6rem;width:128px;}.visual-image-editor{align-items:center;background:rgba(47,111,99,.05);border:1px solid rgba(47,111,99,.14);border-radius:8px;display:flex;gap:18px;padding:14px;}.visual-image-editor__controls{flex:1 1 auto;min-width:220px;}.floor-plan-block--room{background:#d9eee7;}.floor-plan-block--corridor{background:#e7e2f4;}.floor-plan-block--openspace{background:#e5efd4;}.floor-plan-block--exterior{background:#d9ecf3;}.floor-plan-block--other{background:#ece9e1;}.floor-plan-resize-handle{border-bottom:10px solid rgba(18,51,44,.45);border-left:10px solid transparent;bottom:4px;height:0;position:absolute;right:4px;width:0;}.floor-plan-side-panel{align-self:start;position:sticky;top:82px;}.floor-plan-side-panel h2{font-size:1.05rem;margin-bottom:8px;}.floor-plan-side-panel h3{font-size:.92rem;margin:0 0 8px;}.floor-plan-toolbox{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:grid;grid-template-rows:auto minmax(0,1fr);max-height:calc(100vh - 250px);min-height:min(58vh,520px);overflow:hidden;}.floor-plan-toolbox-tabs{border-bottom:1px solid var(--border-color,#d8ded9);display:flex;flex-wrap:wrap;gap:0;}.floor-plan-toolbox-tab{background:transparent;border:0;border-right:1px solid var(--border-color,#d8ded9);border-bottom:1px solid var(--border-color,#d8ded9);color:inherit;flex:1 1 118px;font-size:.82rem;font-weight:800;min-width:112px;padding:10px 8px;}.floor-plan-toolbox-tab:last-child,.floor-plan-toolbox-tab.active:last-child{border-right:0;}.floor-plan-toolbox-tab.active{background:rgba(47,111,99,.1);border-bottom-color:var(--plotline-accent,#2f6f63);color:var(--plotline-accent-dark,#22534a);}.floor-plan-toolbox-body{min-height:0;overflow:auto;}.floor-plan-tool-card{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:8px;padding:14px;}.floor-plan-toolbox .floor-plan-tool-card{background:transparent;border:0;border-radius:0;}.floor-plan-tool-card[hidden]{display:none;}.floor-plan-tool-card p{margin-bottom:10px;}.floor-plan-tool-subsection{border-top:1px solid var(--border-color,#d8ded9);margin-top:12px;padding-top:12px;}.floor-plan-tool-subsection:first-of-type{border-top:0;margin-top:0;padding-top:0;}.floor-plan-background-file{border:1px solid rgba(47,111,99,.16);border-radius:6px;font-size:.86rem;padding:8px 10px;}.floor-plan-background-range{align-items:center;display:grid;gap:10px;grid-template-columns:minmax(0,1fr) 44px;}.floor-plan-background-range span{color:var(--muted-text,#5d6f65);font-size:.8rem;font-variant-numeric:tabular-nums;text-align:right;}.floor-plan-transition-list{display:grid;gap:8px;}.floor-plan-transition-item{border:1px solid rgba(47,111,99,.14);border-radius:6px;display:grid;gap:8px;padding:8px;}.floor-plan-transition-item strong,.floor-plan-transition-item span{display:block;font-size:.84rem;}.floor-plan-transition-item span{color:var(--muted-text,#5d6f65);}.floor-plan-transition-accordion .accordion-item{background:transparent;border-color:var(--border-color,#d8ded9);}.floor-plan-transition-accordion .accordion-button{background:rgba(47,111,99,.06);color:inherit;font-size:.88rem;font-weight:800;padding:10px 12px;}.floor-plan-transition-accordion .accordion-button:not(.collapsed){background:rgba(47,111,99,.12);color:var(--plotline-accent-dark,#22534a);box-shadow:inset 0 -1px 0 var(--border-color,#d8ded9);}.floor-plan-transition-accordion .accordion-body{padding:12px;}.floor-plan-checkbox{align-items:center;display:inline-flex;gap:6px;font-weight:700;margin-bottom:4px;}.floor-plan-choice-row{display:grid;gap:4px;margin-bottom:10px;}.floor-plan-choice-row label{align-items:center;display:flex;gap:6px;font-size:.88rem;}.floor-plan-overlap-warning{background:rgba(180,85,68,.12);border:1px solid rgba(180,85,68,.35);border-radius:6px;color:#8f3f31;margin-bottom:10px;padding:8px 10px;}[data-bs-theme="dark"] .floor-plan-grid,.dark .floor-plan-grid{background:linear-gradient(to right,rgba(214,224,218,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(214,224,218,.12) 1px,transparent 1px),#15201d;background-size:var(--cell-size) var(--cell-size),var(--cell-size) var(--cell-size),auto;}[data-bs-theme="dark"] .floor-plan-editor-toolbar,.dark .floor-plan-editor-toolbar,[data-bs-theme="dark"] .floor-plan-toolbox,.dark .floor-plan-toolbox,[data-bs-theme="dark"] .floor-plan-tool-card,.dark .floor-plan-tool-card{background:var(--panel-bg,#1f2522);}[data-bs-theme="dark"] .floor-plan-toolbox .floor-plan-tool-card,.dark .floor-plan-toolbox .floor-plan-tool-card{background:transparent;}[data-bs-theme="dark"] .floor-plan-toolbox-tab.active,.dark .floor-plan-toolbox-tab.active{background:rgba(212,154,98,.16);color:var(--plotline-accent-dark,#f0c99d);}[data-bs-theme="dark"] .floor-plan-block,.dark .floor-plan-block{--floor-plan-wall-color:rgba(212,154,98,.6);color:#f1f6f3;}[data-bs-theme="dark"] .floor-plan-block.is-hidden-location,.dark .floor-plan-block.is-hidden-location{background-image:repeating-linear-gradient(135deg,rgba(244,234,220,.09) 0,rgba(244,234,220,.09) 3px,transparent 3px,transparent 9px);box-shadow:inset 0 0 0 1px rgba(244,234,220,.2);}[data-bs-theme="dark"] .floor-plan-secret-route,.dark .floor-plan-secret-route{border-top-color:rgba(244,204,160,.58);opacity:.76;}[data-bs-theme="dark"] .floor-plan-secret-route::after,.dark .floor-plan-secret-route::after{background:rgba(42,35,30,.95);border-color:rgba(244,204,160,.55);}[data-bs-theme="dark"] .floor-plan-coordinate-label,.dark .floor-plan-coordinate-label{color:rgba(244,234,220,.46);text-shadow:0 1px 0 rgba(0,0,0,.55);}[data-bs-theme="dark"] .floor-plan-reference-block,.dark .floor-plan-reference-block{background:rgba(131,199,242,.08);border-color:rgba(131,199,242,.32);color:rgba(244,234,220,.46);}[data-bs-theme="dark"] .floor-plan-reference-warning,.dark .floor-plan-reference-warning{background:rgba(84,57,25,.92);border-color:rgba(244,177,100,.32);color:#ffd9a5;}[data-bs-theme="dark"] .floor-plan-transition-marker,.dark .floor-plan-transition-marker{--transition-marker-ink:#f4eadc;--transition-marker-window:#83c7f2;--transition-marker-blocked:#f08a78;background:rgba(42,35,30,.98);border-color:rgba(212,154,98,.6);}[data-bs-theme="dark"] .floor-plan-transition-marker.is-shared-edge,.dark .floor-plan-transition-marker.is-shared-edge{background:rgba(48,39,32,.98);border-color:rgba(212,154,98,.78);}[data-bs-theme="dark"] .floor-plan-transition-marker--window,.dark .floor-plan-transition-marker--window,[data-bs-theme="dark"] .floor-plan-transition-marker--window.is-shared-edge,.dark .floor-plan-transition-marker--window.is-shared-edge{background:rgba(24,45,58,.98);border-color:rgba(131,199,242,.66);}[data-bs-theme="dark"] .floor-plan-transition-marker--sliding-door,.dark .floor-plan-transition-marker--sliding-door,[data-bs-theme="dark"] .floor-plan-transition-marker--french-door,.dark .floor-plan-transition-marker--french-door,[data-bs-theme="dark"] .floor-plan-transition-marker--ladder,.dark .floor-plan-transition-marker--ladder{background:rgba(39,43,37,.98);border-color:rgba(212,154,98,.58);}[data-bs-theme="dark"] .floor-plan-transition-marker--blocked-door,.dark .floor-plan-transition-marker--blocked-door,[data-bs-theme="dark"] .floor-plan-transition-marker--blocked-door.is-shared-edge,.dark .floor-plan-transition-marker--blocked-door.is-shared-edge{background:rgba(58,33,28,.98);border-color:rgba(240,138,120,.66);}[data-bs-theme="dark"] .visual-avatar,.dark .visual-avatar{background:linear-gradient(135deg,rgba(131,199,242,.14),rgba(212,154,98,.18));border-color:rgba(244,234,220,.18);color:#f4eadc;}[data-bs-theme="dark"] .visual-image-editor,.dark .visual-image-editor{background:rgba(244,234,220,.04);border-color:rgba(244,234,220,.12);}[data-bs-theme="dark"] .floor-plan-transition-item,.dark .floor-plan-transition-item{border-color:rgba(212,154,98,.22);}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-item,.dark .floor-plan-transition-accordion .accordion-item{border-color:rgba(212,154,98,.22);}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-button,.dark .floor-plan-transition-accordion .accordion-button{background:rgba(212,154,98,.08);color:#f4eadc;}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-button:not(.collapsed),.dark .floor-plan-transition-accordion .accordion-button:not(.collapsed){background:rgba(212,154,98,.16);color:var(--plotline-accent-dark,#f0c99d);box-shadow:inset 0 -1px 0 rgba(212,154,98,.22);}[data-bs-theme="dark"] .floor-plan-block--room,.dark .floor-plan-block--room{background:#29584f;}[data-bs-theme="dark"] .floor-plan-block--corridor,.dark .floor-plan-block--corridor{background:#514876;}[data-bs-theme="dark"] .floor-plan-block--openspace,.dark .floor-plan-block--openspace{background:#4f6133;}[data-bs-theme="dark"] .floor-plan-block--exterior,.dark .floor-plan-block--exterior{background:#315d6f;}[data-bs-theme="dark"] .floor-plan-block--other,.dark .floor-plan-block--other{background:#5b564c;}@media (max-width:1100px){.floor-plan-layout,.floor-plan-editor-toolbar{grid-template-columns:1fr;}.floor-plan-grid-wrap{max-height:62vh;}.floor-plan-side-panel{position:static;}.floor-plan-toolbox{max-height:none;}} \ No newline at end of file +html{font-size:15px;min-height:100%;}@media (min-width:768px){html{font-size:16px;}}:root{--plotline-ink:#1e252b;--plotline-muted:#66717b;--plotline-paper:#fbfaf7;--plotline-panel:#ffffff;--plotline-line:#d8ddd8;--plotline-accent:#2f6f63;--plotline-accent-dark:#22534a;--plotline-soft:#eef5f2;--timeline-label-width:180px;--timeline-scene-width:220px;--timeline-grid-gap:10px;}body{min-height:100%;margin-bottom:0;color:var(--plotline-ink);background:var(--plotline-paper);}a{color:var(--plotline-accent-dark);}.btn-primary{--bs-btn-bg:var(--plotline-accent);--bs-btn-border-color:var(--plotline-accent);--bs-btn-hover-bg:var(--plotline-accent-dark);--bs-btn-hover-border-color:var(--plotline-accent-dark);}.btn-outline-primary{--bs-btn-color:var(--plotline-accent-dark);--bs-btn-border-color:var(--plotline-accent);--bs-btn-hover-bg:var(--plotline-accent);--bs-btn-hover-border-color:var(--plotline-accent);}.plotline-nav{background:rgba(255,255,255,0.94);backdrop-filter:blur(8px);}.plotline-shell{max-width:1480px;padding-left:24px;padding-right:24px;}.plotline-shell-wide{max-width:none;padding-left:clamp(18px,2vw,32px);padding-right:clamp(18px,2vw,32px);}.page-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin:18px 0 24px;}.workspace-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;margin:14px 0 18px;}.workspace-heading h1{margin:0;font-size:clamp(1.8rem,3vw,2.7rem);line-height:1.05;}.page-heading.compact{max-width:980px;}.page-heading h1{margin:0;font-size:clamp(2rem,4vw,3.2rem);line-height:1.05;letter-spacing:0;}.eyebrow{margin:0 0 6px;color:var(--plotline-accent-dark);font-size:0.78rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;}.lead-text{max-width:760px;margin:10px 0 0;color:var(--plotline-muted);font-size:1.05rem;}.button-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}.button-row form,.compact-buttons form,.asset-card-footer form,td.text-end form,form[data-confirm-message]{display:inline-flex;align-items:center;margin:0;}td.text-end{white-space:nowrap;}.content-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;}.plain-card,.empty-panel,.edit-panel,.list-section{background:var(--plotline-panel);border:1px solid var(--plotline-line);border-radius:8px;padding:20px;box-shadow:0 10px 24px rgba(30,37,43,0.04);}.plain-card h2,.empty-panel h2,.list-section h2{margin-top:0;font-size:1.35rem;}.plain-card p,.empty-panel p,.muted{color:var(--plotline-muted);}.edit-panel{max-width:980px;}.trial-status-panel,.trial-dashboard-banner{border:1px solid var(--plotline-line);border-radius:8px;padding:18px 20px;background:var(--plotline-panel);}.trial-status-panel{display:grid;gap:12px;margin-bottom:18px;}.trial-status-panel--signup{grid-template-columns:minmax(0,1fr) auto;align-items:center;max-width:980px;}.trial-status-panel h2,.trial-status-panel h3,.trial-dashboard-banner h2{margin:0;}.trial-status-panel p,.trial-dashboard-banner p{margin-bottom:0;}.trial-status-panel__heading,.trial-dashboard-banner{display:flex;gap:16px;align-items:center;justify-content:space-between;}.trial-dashboard-banner{margin-bottom:18px;}.trial-dashboard-banner__body{min-width:0;}.trial-dashboard-banner__actions{display:flex;flex:0 0 auto;flex-wrap:wrap;gap:8px;}.trial-progress{height:10px;overflow:hidden;border-radius:999px;background:rgba(84,68,48,0.12);}.trial-progress__bar{height:100%;border-radius:inherit;}.trial-status-panel[hidden],.trial-dashboard-banner[hidden]{display:none;}.location-page .page-heading.compact,.location-page .edit-panel,.location-page .empty-panel,.location-page .drag-drop-panel{max-width:none;}.import-panel,.import-preview-section{max-width:none;}.import-json-input{font-family:Consolas,"Liberation Mono",Menlo,monospace;font-size:0.88rem;line-height:1.45;min-height:34rem;max-height:64vh;overflow:auto;resize:vertical;white-space:pre;}.import-preview-heading,.import-counts{display:flex;align-items:flex-start;gap:12px;}.import-preview-heading{justify-content:space-between;margin-bottom:16px;}.import-counts{flex-wrap:wrap;}.import-counts span{display:inline-flex;align-items:baseline;gap:5px;border:1px solid var(--plotline-line);border-radius:999px;padding:5px 11px;background:var(--plotline-soft);color:var(--plotline-muted);font-weight:700;}.import-counts strong{color:var(--plotline-ink);}.import-tree{display:grid;gap:12px;}.import-tree-book{border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:rgba(255,255,255,0.54);}.import-tree-book>summary,.import-tree-chapter>summary{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;}.import-tree-book>summary span,.import-tree-chapter>summary span{color:var(--plotline-muted);font-size:0.84rem;font-weight:700;white-space:nowrap;}.import-tree-book h3{margin:0 0 10px;font-size:1.08rem;}.import-tree-chapter{border-top:1px solid var(--plotline-line);padding:10px 0 0;margin-top:10px;}.import-tree-chapter ul{margin:8px 0 0;color:var(--plotline-muted);}.import-scene-meta{display:block;margin-top:2px;color:var(--plotline-muted);font-size:0.82rem;}.import-mapping-summary{display:grid;gap:6px;border:1px solid rgba(184,118,43,0.28);border-radius:8px;padding:10px 12px;margin-bottom:14px;background:rgba(251,236,211,0.5);color:var(--plotline-muted);font-size:0.9rem;}.import-duplicate-confirm{border:1px solid rgba(184,118,43,0.34);border-radius:8px;padding:12px 12px 12px 38px;background:rgba(251,236,211,0.72);}.import-confirmation,.import-docs details{border:1px solid var(--plotline-line);border-radius:8px;padding:16px;background:rgba(255,255,255,0.42);}.import-confirmation h3,.import-doc-grid h3{margin-top:0;font-size:1.05rem;}.import-docs summary{cursor:pointer;font-weight:800;}.import-doc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-top:14px;}.import-message-list ul{max-height:16rem;overflow:auto;}.scene-editor{max-width:1180px;}.table{margin-bottom:0;}.table th{color:var(--plotline-muted);font-size:0.78rem;letter-spacing:0.06em;text-transform:uppercase;}.narrow{width:90px;white-space:nowrap;}.status-pill{display:inline-flex;align-items:center;width:fit-content;border:1px solid #c8d8d2;border-radius:999px;padding:2px 8px;color:var(--plotline-accent-dark);background:var(--plotline-soft);font-size:0.78rem;font-weight:700;white-space:nowrap;}.dashboard-summary-card{border-color:var(--plotline-line);}.dashboard-summary-body{padding:10px 12px;}.dashboard-summary-label{margin-bottom:4px;font-size:0.7rem;line-height:1.15;}.dashboard-summary-value{display:block;font-size:1.45rem;line-height:1;}.dashboard-summary-calm{border-color:rgba(47,111,99,0.28);background:rgba(238,245,242,0.62);}.dashboard-summary-mild{border-color:rgba(197,139,43,0.32);background:rgba(255,248,232,0.68);}.dashboard-summary-attention{border-color:rgba(142,80,103,0.32);background:rgba(252,241,246,0.7);}.dashboard-progress-card{border-color:rgba(47,111,99,0.18);background:linear-gradient(180deg,#ffffff 0%,rgba(238,245,242,0.64) 100%);}.dashboard-progress-body{padding:12px 14px;}.dashboard-progress-heading{margin-bottom:8px;}.dashboard-progress-title{margin:0 0 2px;font-size:1.05rem;line-height:1.2;}.dashboard-series-progress{height:7px;background:rgba(47,111,99,0.1);}.dashboard-series-progress .progress-bar{background:linear-gradient(90deg,var(--plotline-accent),#6fa99b);}.dashboard-progress-source{border-color:rgba(47,111,99,0.2);color:var(--plotline-accent-dark);background:rgba(238,245,242,0.9);}.dashboard-book-title-block h3{line-height:1.16;}.dashboard-book-title-block a{color:var(--plotline-ink);text-decoration-color:rgba(47,111,99,0.35);}.dashboard-book-subtitle{color:var(--plotline-muted);font-size:0.95rem;line-height:1.25;}.dashboard-status-pill{border-color:var(--dashboard-status-border,#c8d8d2);color:var(--dashboard-status-ink,var(--plotline-accent-dark));background:var(--dashboard-status-bg,var(--plotline-soft));}.dashboard-status-published{--dashboard-status-border:rgba(47,111,99,0.32);--dashboard-status-bg:#e7f2ed;--dashboard-status-ink:#22534a;}.dashboard-status-drafting{--dashboard-status-border:rgba(184,118,43,0.35);--dashboard-status-bg:#fff2dd;--dashboard-status-ink:#7b4b12;}.dashboard-status-planning{--dashboard-status-border:rgba(51,117,155,0.3);--dashboard-status-bg:#e9f3f8;--dashboard-status-ink:#245b78;}.dashboard-status-research,.dashboard-status-outlining{--dashboard-status-border:rgba(103,80,164,0.26);--dashboard-status-bg:#f0edf8;--dashboard-status-ink:#51417c;}.dashboard-status-revising{--dashboard-status-border:rgba(123,82,148,0.3);--dashboard-status-bg:#f4eefa;--dashboard-status-ink:#5f3e73;}.dashboard-status-editing{--dashboard-status-border:rgba(68,75,130,0.3);--dashboard-status-bg:#eceef8;--dashboard-status-ink:#343b72;}.dashboard-status-proofreading{--dashboard-status-border:rgba(43,130,123,0.3);--dashboard-status-bg:#e6f5f2;--dashboard-status-ink:#23625d;}.dashboard-status-ready{--dashboard-status-border:rgba(185,142,30,0.34);--dashboard-status-bg:#fff6d8;--dashboard-status-ink:#765a0f;}.dashboard-status-paused{--dashboard-status-border:rgba(102,113,123,0.28);--dashboard-status-bg:#f0f2f1;--dashboard-status-ink:#56616b;}.dashboard-status-archived{--dashboard-status-border:rgba(139,80,86,0.28);--dashboard-status-bg:#f3eded;--dashboard-status-ink:#76474d;}.dashboard-attention-soft{border-color:rgba(102,113,123,0.24);color:#56616b;background:#f3f4f2;}.order-buttons{display:flex;gap:6px;}.purpose-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:8px;max-height:260px;overflow:auto;padding:10px;border:1px solid var(--plotline-line);border-radius:8px;background:#fcfcfb;}.purpose-check{display:flex;align-items:center;gap:8px;font-size:0.92rem;}.timeline-filter{display:flex;align-items:center;gap:8px;min-width:min(420px,100%);}.workspace-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:0;align-items:start;--timeline-inspector-width:min(40vw,560px);}.workspace-layout.inspector-drawer-open{grid-template-columns:minmax(420px,1fr) 10px minmax(420px,var(--timeline-inspector-width));gap:12px;}.timeline-workspace{min-width:0;max-width:100%;}.timeline-inspector-resizer{position:sticky;top:76px;z-index:25;width:10px;height:calc(100vh - 96px);border-radius:999px;cursor:col-resize;background:linear-gradient(180deg,rgba(47,111,99,0.16),rgba(47,111,99,0.04));}.timeline-inspector-resizer::before{content:"";display:block;width:2px;height:48px;margin:18px auto;border-radius:999px;background:var(--plotline-accent);opacity:0.55;}.timeline-inspector-resizer:hover,.timeline-inspector-resizer:focus-visible{background:rgba(47,111,99,0.16);}body.timeline-inspector-resizing{cursor:col-resize;user-select:none;}.pacing-panel{margin-top:14px;margin-bottom:0;border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:#fff;box-shadow:0 10px 24px rgba(30,37,43,0.04);}.pacing-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px;}.pacing-heading h2{margin:0;font-size:1.1rem;}.metric-graph-stack{display:grid;gap:10px;max-width:100%;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;padding-bottom:4px;}.metric-graph-row{display:grid;grid-template-columns:150px minmax(260px,1fr);gap:10px;align-items:center;min-width:max(100%,calc(150px+(var(--scene-count,1) * 34px)));}.metric-graph-label{color:var(--plotline-muted);font-size:0.84rem;font-weight:700;}.metric-graph-points{display:grid;grid-template-columns:repeat(var(--scene-count),minmax(28px,1fr));gap:5px;align-items:end;min-height:52px;border-radius:8px;padding:6px;background:linear-gradient(180deg,#f6faf8 0%,#edf4f1 100%);min-width:calc(var(--scene-count) * 34px);}.metric-point{display:flex;align-items:flex-end;justify-content:center;height:48px;min-width:28px;color:var(--plotline-accent-dark);text-decoration:none;}.metric-point::before{content:"";display:block;width:100%;height:max(8px,var(--metric-height));border-radius:5px 5px 2px 2px;background:linear-gradient(180deg,#6fa99b,var(--plotline-accent-dark));box-shadow:inset 0 1px 0 rgba(255,255,255,0.35);}.metric-point span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);}.timeline-shell{overflow-x:auto;padding:16px;border:1px solid var(--plotline-line);border-radius:8px;background:linear-gradient(180deg,#ffffff 0%,#f7faf8 100%);}.workspace-timeline{min-height:420px;}.timeline-series-row{display:grid;grid-template-columns:var(--timeline-label-width) max-content;gap:var(--timeline-grid-gap);align-items:stretch;width:max-content;min-width:100%;}.timeline-project-title{position:sticky;left:0;z-index:20;display:grid;align-content:start;gap:4px;width:var(--timeline-label-width);min-height:100%;border-radius:8px;padding:12px;color:#fff;background:var(--plotline-accent-dark);font-weight:700;box-shadow:8px 0 18px rgba(30,37,43,0.08);}.timeline-project-title span,.timeline-book-title span{color:rgba(255,255,255,0.78);font-size:0.72rem;letter-spacing:0.08em;text-transform:uppercase;}.timeline-project-title strong,.timeline-book-title strong{line-height:1.15;}.timeline-books{display:flex;gap:var(--timeline-grid-gap);align-items:stretch;}.timeline-book{flex:0 0 auto;width:calc((var(--book-scene-count) * var(--timeline-scene-width))+((var(--book-scene-count) - 1) * var(--timeline-grid-gap)));min-width:var(--timeline-scene-width);}.timeline-book-title{display:grid;gap:2px;margin-bottom:var(--timeline-grid-gap);border-radius:8px;padding:10px 12px;color:#fff;background:var(--plotline-accent-dark);font-weight:700;}.timeline-chapters{display:flex;gap:var(--timeline-grid-gap);align-items:flex-start;}.timeline-chapter{flex:0 0 auto;width:calc((var(--chapter-scene-count) * var(--timeline-scene-width))+((var(--chapter-scene-count) - 1) * var(--timeline-grid-gap)));min-width:var(--timeline-scene-width);box-sizing:border-box;border-radius:8px;background:rgba(238,245,242,0.7);outline:1px solid #d4ded8;outline-offset:0;overflow:visible;}.timeline-chapter-title{display:grid;gap:2px;border-bottom:1px solid #d4ded8;padding:10px 12px;color:var(--plotline-accent-dark);font-weight:700;}.timeline-chapter-title span{color:var(--plotline-muted);font-size:0.76rem;text-transform:uppercase;}.timeline-scenes{display:grid;grid-template-columns:repeat(var(--chapter-scene-count),minmax(0,1fr));gap:var(--timeline-grid-gap);width:100%;box-sizing:border-box;min-height:190px;padding:0;}.timeline-scene-card,.timeline-empty-scene{display:flex;flex-direction:column;gap:6px;width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--plotline-line);border-radius:8px;padding:12px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 8px 18px rgba(30,37,43,0.05);}.timeline-scene-card:hover{border-color:var(--plotline-accent);color:var(--plotline-ink);}.timeline-placeholder-scene,.timeline-placeholder-cell,.metric-point-placeholder{cursor:default;opacity:0.72;}.timeline-placeholder-scene{align-items:center;justify-content:center;border-style:dashed;color:var(--plotline-muted);background:rgba(255,255,255,0.38);font-size:0.86rem;font-weight:800;text-align:center;}.timeline-placeholder-cell{border-style:dashed;background:repeating-linear-gradient( -45deg,rgba(216,221,216,0.18) 0,rgba(216,221,216,0.18) 7px,rgba(255,255,255,0.18) 7px,rgba(255,255,255,0.18) 14px );}.metric-point-placeholder::before{height:4px;background:rgba(102,113,123,0.2);box-shadow:none;}.timeline-scene-card.selected{border-color:var(--plotline-accent-dark);box-shadow:0 0 0 3px rgba(47,111,99,0.16),0 10px 22px rgba(30,37,43,0.08);}.scene-badge-row,.purpose-chip-row{display:flex;flex-wrap:wrap;gap:5px;align-items:center;}.warning-placeholder{display:inline-flex;width:fit-content;border:1px dashed #d6b25e;border-radius:999px;padding:2px 8px;color:#755715;background:#fff8e8;font-size:0.74rem;font-weight:700;}.warning-placeholder.active{border-color:rgba(159,69,69,0.36);color:#8a3434;background:rgba(255,232,232,0.9);gap:5px;font-weight:800;}.dependency-placeholder{display:inline-flex;width:fit-content;border:1px solid rgba(47,111,99,0.2);border-radius:999px;padding:2px 8px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);font-size:0.74rem;font-weight:700;}.purpose-chip{display:inline-flex;width:fit-content;border-radius:999px;padding:2px 7px;color:#38453e;background:#edf0eb;font-size:0.72rem;font-weight:700;}.future-lane-placeholder{border-top:1px dashed #cbd8d2;padding:8px 12px;color:var(--plotline-muted);font-size:0.78rem;background:rgba(255,255,255,0.45);}.metric-timeline-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.metric-shape-controls{position:sticky;left:0;z-index:6;display:grid;gap:8px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;border-radius:8px;padding:10px;background:rgba(255,255,255,0.88);}.metric-timeline-row{display:grid;grid-template-columns:var(--timeline-label-width) calc((var(--scene-count) * var(--timeline-scene-width))+((var(--scene-count) - 1) * var(--timeline-grid-gap)));gap:var(--timeline-grid-gap);align-items:stretch;}.metric-lane-label{position:sticky;left:0;z-index:12;display:grid;align-content:start;gap:4px;min-height:320px;border:1px solid rgba(47,111,99,0.18);border-radius:8px;padding:10px;color:var(--plotline-accent-dark);background:#fff;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.metric-lane-label span{color:var(--plotline-muted);font-size:0.78rem;font-weight:600;}.colour-swatch{display:inline-block;width:18px;height:18px;border:1px solid rgba(30,37,43,0.18);border-radius:999px;vertical-align:middle;}.plot-lane-board{position:relative;display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.plot-lane-svg-overlay{position:absolute;inset:0 auto auto 0;z-index:4;pointer-events:none;overflow:visible;}.plot-lane-svg-health-overlay{z-index:8;}.plot-line-svg-path{fill:none;stroke-width:3.5;stroke-linecap:round;opacity:0.72;}.plot-line-svg-segment-dormant{stroke-dasharray:9 8;opacity:0.48;}.plot-line-svg-connector{fill:none;stroke-width:3;stroke-linecap:round;opacity:0.58;}.plot-line-svg-path.plotline-state-resolved,.plot-line-svg-path.plotline-state-questionable{stroke:#8c9491;opacity:0.42;}.plot-line-svg-path.plotline-state-abandoned{stroke:#9b2f36;opacity:0.5;}.plot-event-svg-node.plotline-state-resolved,.plot-event-svg-node.plotline-state-questionable{opacity:0.88;}.plot-event-svg-node.plotline-state-abandoned{opacity:0.9;}.plot-event-svg-node.plotline-state-abandoned line{stroke:#ffffff;}.plotline-health-marker path,.plotline-health-marker circle{fill:#f4c430;stroke:#8a6712;stroke-width:1.5;}.plotline-health-marker{pointer-events:visiblePainted;}.plotline-health-marker line,.plotline-health-marker text{stroke:#5e4710;fill:#5e4710;stroke-width:1.6;stroke-linecap:round;}.plotline-health-marker text{font-size:11px;font-weight:800;stroke-width:0;pointer-events:none;}.plotline-health-count{fill:#ffffff;stroke:#8a6712;stroke-width:2;paint-order:stroke;}.plotline-health-marker-dangling path,.plotline-health-marker-dangling circle{fill:#f8df8f;}.plotline-health-marker-abandoned path,.plotline-health-marker-abandoned circle{fill:#d85c63;stroke:#8b1e2d;}.plotline-health-marker-abandoned line{stroke:#ffffff;}.plot-event-svg-node circle,.plot-event-svg-node ellipse,.plot-event-svg-node path{stroke:#ffffff;stroke-width:2;}.plot-event-svg-node line,.plot-event-svg-node path[fill="none"]{stroke:#8b1e2d;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round;}.plot-event-svg-node-reveal ellipse{stroke-width:2.4;}.plot-event-svg-label{font-size:9.5px;font-weight:900;font-family:system-ui,-apple-system,"Segoe UI",sans-serif;paint-order:stroke;stroke:rgba(30,37,43,0.22);stroke-width:0.8px;pointer-events:none;}.plot-event-svg-node-resolve path[fill="none"]{stroke:#ffffff;}.lane-board-heading,.metric-lane-board-heading,.plot-lane-board-heading{position:sticky;left:0;z-index:6;display:flex;align-items:center;justify-content:space-between;gap:14px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;margin-bottom:2px;border-radius:8px;padding:8px 10px;color:var(--plotline-accent-dark);background:rgba(255,255,255,0.92);font-weight:700;box-shadow:0 8px 16px rgba(30,37,43,0.05);}.lane-board-heading small,.metric-lane-board-heading small,.plot-lane-board-heading small{color:var(--plotline-muted);font-weight:500;white-space:nowrap;}.timeline-heading-with-help{display:inline-flex;align-items:center;gap:6px;min-width:0;}.plot-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.plot-lane-label{position:sticky;left:0;z-index:12;display:flex;align-items:center;gap:8px;min-height:46px;border:1px solid color-mix(in srgb,var(--plot-colour),#ffffff 55%);border-left:5px solid var(--plot-colour);border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.plot-lane-label:hover{color:var(--plotline-ink);border-color:var(--plot-colour);}.plot-lane-slots{display:contents;}.plot-lane-slot{display:flex;flex-wrap:wrap;align-content:center;align-items:center;justify-content:center;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(255,255,255,0.62);}.thread-marker{position:relative;z-index:5;display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:34px;height:30px;border:2px solid color-mix(in srgb,var(--plot-colour),#000000 20%);border-radius:999px;padding:0 8px;color:var(--plotline-ink);background:color-mix(in srgb,var(--plot-colour),#ffffff 66%);font-size:0.74rem;font-weight:900;text-decoration:none;box-shadow:0 3px 8px rgba(30,37,43,0.14);}.plot-lane-board [data-plot-event-node]{opacity:1;}.thread-marker:hover,.thread-marker:focus-visible{color:var(--plotline-ink);background:color-mix(in srgb,var(--plot-colour),#ffffff 48%);outline:3px solid rgba(47,111,99,0.22);outline-offset:2px;}.thread-marker.resolved{border-color:#5a8c60;background:#e6f4e7;color:#24512b;}.thread-marker.contradicted{border-color:#b45c5c;background:#fff0f0;color:#7a2222;}.thread-events-section{margin-top:16px;}.thread-event-list{display:grid;gap:8px;margin-bottom:12px;}.thread-event-item{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;border:1px solid color-mix(in srgb,var(--plot-colour),#ffffff 55%);border-left:4px solid var(--plot-colour);border-radius:8px;padding:8px;background:#fff;}.thread-event-item>div{display:grid;gap:3px;}.thread-event-marker{display:inline-flex;align-items:center;justify-content:center;width:fit-content;min-width:24px;height:22px;border-radius:999px;padding:0 7px;background:color-mix(in srgb,var(--plot-colour),#ffffff 72%);font-size:0.72rem;font-weight:800;}.thread-event-create{border-top:1px solid var(--plotline-line);padding-top:12px;}.asset-lane-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.asset-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.asset-lane-label{position:sticky;left:0;z-index:12;display:grid;gap:2px;min-height:46px;border:1px solid #d4d7df;border-left:5px solid #6b5b95;border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.asset-lane-label span{color:var(--plotline-muted);font-size:0.75rem;}.asset-lane-slots{display:contents;}.asset-lane-slot{display:flex;flex-wrap:wrap;align-content:flex-start;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(250,249,255,0.72);}.asset-marker,.asset-event-marker{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:24px;border:1px solid #7f70aa;border-radius:7px;padding:0 7px;color:#33284e;background:#eee9fb;font-size:0.72rem;font-weight:800;text-decoration:none;}.asset-marker:hover{color:#33284e;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;}.asset-event-list,.asset-mini-list{display:grid;gap:8px;margin-bottom:12px;}.asset-event-item,.asset-mini-item{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;border:1px solid #ded9ea;border-left:4px solid #6b5b95;border-radius:8px;padding:8px;background:#fff;}.asset-event-item>div,.asset-mini-item>div{display:grid;gap:3px;}.asset-create-form{border-top:1px solid var(--plotline-line);padding-top:12px;}.asset-card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px;}.asset-card{display:grid;gap:12px;border:1px solid var(--plotline-line);border-radius:8px;padding:14px;background:#fff;box-shadow:0 8px 18px rgba(30,37,43,0.04);}.asset-card h2{margin:0;font-size:1.1rem;}.asset-card-footer{display:flex;flex-wrap:wrap;align-items:center;gap:6px;}.asset-detail-grid{display:grid;grid-template-columns:minmax(260px,0.8fr) minmax(320px,1.2fr);gap:14px;}.character-lane-board{display:grid;gap:8px;width:max-content;min-width:100%;margin-top:14px;border-top:1px solid var(--plotline-line);padding-top:14px;}.character-lane-row{display:grid;grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);align-items:stretch;}.character-lane-label{position:sticky;left:0;z-index:12;display:grid;gap:2px;min-height:46px;border:1px solid #d7d4ce;border-left:5px solid #8a6f3d;border-radius:8px;padding:8px 10px;background:#fff;color:var(--plotline-ink);text-decoration:none;box-shadow:0 6px 14px rgba(30,37,43,0.04);}.character-lane-label span{color:var(--plotline-muted);font-size:0.75rem;}.character-lane-slots{display:contents;}.character-lane-slot{display:flex;flex-wrap:wrap;align-content:flex-start;gap:5px;min-height:46px;border:1px dashed #d8ddd8;border-radius:8px;padding:7px;background:rgba(255,252,246,0.72);}.character-marker{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:24px;border:1px solid #9a7a3f;border-radius:999px;padding:0 7px;color:#4f3810;background:#fff2d7;font-size:0.72rem;font-weight:800;text-decoration:none;}.character-card{border-left:4px solid #8a6f3d;}.character-section{margin-top:16px;}.character-item{border-left-color:#8a6f3d;}.character-appearance-card{display:grid;gap:8px;border:1px solid #d7d4ce;border-left:4px solid #8a6f3d;border-radius:8px;padding:10px;background:#fff;}.character-appearance-summary{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;}.character-appearance-summary>div:first-child{display:grid;gap:3px;}.character-appearance-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:6px;}.character-appearance-edit .asset-create-form{margin-top:8px;border-top:1px solid var(--plotline-line);}.form-helper-message{margin:0 0 8px;font-size:0.86rem;font-weight:700;}.scene-number,.time-label{color:var(--plotline-muted);font-size:0.82rem;}.location-pill,.location-badge{display:inline-flex;align-items:center;width:fit-content;border:1px solid rgba(47,111,99,0.18);border-radius:999px;padding:2px 7px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);font-size:0.74rem;font-weight:700;}.scene-summary{display:-webkit-box;overflow:hidden;color:var(--plotline-muted);font-size:0.88rem;-webkit-box-orient:vertical;-webkit-line-clamp:4;}.timeline-empty-scene{justify-content:center;color:var(--plotline-muted);background:rgba(255,255,255,0.58);}.form-control:focus,.form-select:focus,.form-check-input:focus{border-color:var(--plotline-accent);box-shadow:0 0 0 0.2rem rgba(47,111,99,0.16);}.scene-inspector-panel{position:sticky;top:76px;display:flex;flex-direction:column;max-height:calc(100vh - 96px);min-width:0;overflow:hidden;border:1px solid var(--plotline-line);border-radius:8px;background:#fff;box-shadow:0 14px 32px rgba(30,37,43,0.08);}.inspector-header{position:sticky;top:0;z-index:5;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;border-bottom:1px solid var(--plotline-line);padding:16px;background:#fff;}.scene-inspector-body{flex:1 1 auto;min-height:0;overflow:auto;padding:16px;}.inspector-header h2{margin:0;font-size:1.25rem;}.scene-inspector-form{display:grid;gap:14px;}.inspector-section{border-top:1px solid var(--plotline-line);padding-top:12px;}.inspector-section:first-of-type{border-top:0;padding-top:0;}.inspector-section h3{margin:0 0 10px;font-size:0.95rem;color:var(--plotline-accent-dark);}.location-helper{border:1px solid rgba(138,111,61,0.22);border-radius:8px;padding:10px;background:rgba(255,248,232,0.74);}.location-warning-list{margin:0;padding-left:18px;color:#6f5526;font-size:0.86rem;}.location-tree{display:grid;gap:8px;}.location-tree-row{display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--plotline-line);padding:10px 0 10px calc(var(--location-depth,0) * 22px);}.location-tree-row:last-child{border-bottom:0;}.location-tree-row>div:first-child{display:grid;gap:3px;}.compact-buttons{flex-wrap:nowrap;}.location-chip-list{display:flex;flex-wrap:wrap;gap:8px;}.location-chip{border:1px solid var(--plotline-line);border-radius:8px;padding:7px 10px;background:#fff;text-decoration:none;}.location-relationship-list{display:grid;gap:8px;}.location-relationship-card{display:flex;justify-content:space-between;gap:12px;border:1px solid var(--plotline-line);border-radius:8px;padding:10px;background:#fff;}.location-flags{display:flex;flex-wrap:wrap;gap:10px 16px;color:var(--plotline-muted);font-size:0.86rem;}.validation-summary,.warning-filter-panel{border:1px solid var(--plotline-line);border-radius:8px;margin-bottom:16px;padding:12px;background:#fff;}.validation-summary{display:flex;flex-wrap:wrap;gap:12px;color:var(--plotline-muted);}.warning-dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-bottom:18px;}.warning-count-row,.warning-card-title,.inspector-section-heading{display:flex;align-items:center;justify-content:space-between;gap:10px;}.warning-list,.warning-mini-list{display:grid;gap:10px;}.warning-card,.warning-mini-card{border:1px solid var(--plotline-line);border-radius:8px;padding:12px;background:#fff;}.warning-card{display:grid;grid-template-columns:1fr auto;gap:12px;}.warning-card p,.warning-mini-card p{margin:6px 0;}.warning-actions{display:flex;align-items:flex-start;flex-wrap:wrap;gap:6px;}.severity-pill{display:inline-flex;align-items:center;border-radius:999px;padding:2px 8px;font-size:0.74rem;font-weight:800;}.severity-pill.info{color:#365f7c;background:rgba(107,153,184,0.14);}.severity-pill.warning{color:#7a5527;background:rgba(205,154,72,0.17);}.severity-pill.error{color:#8a3434;background:rgba(190,83,83,0.15);}.warning-mini-card{background:rgba(255,255,255,0.76);}.dependency-columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;}.dependency-card{display:grid;gap:3px;border:1px solid var(--plotline-line);border-radius:8px;margin-bottom:8px;padding:9px;background:rgba(255,255,255,0.78);}.move-preview-panel{max-width:900px;}.focused-validation-summary{display:flex;flex-wrap:wrap;gap:10px;border:1px solid rgba(47,111,99,0.16);border-radius:8px;margin-top:12px;padding:10px;color:var(--plotline-muted);background:rgba(47,111,99,0.05);}.inspector-purpose-list{grid-template-columns:1fr;max-height:210px;}.metric-slider-stack{display:grid;gap:12px;}.metric-slider{display:grid;gap:4px;}.metric-slider-label{display:flex;justify-content:space-between;gap:10px;color:var(--plotline-muted);font-size:0.86rem;font-weight:700;}.metric-slider-label output{color:var(--plotline-accent-dark);}.metric-slider .form-range{accent-color:var(--plotline-accent);}.asset-importance-slider{border:1px solid var(--plotline-line);border-radius:8px;padding:10px 12px;background:rgba(47,111,99,0.05);}.story-asset-checkbox-field{margin-top:1.95rem;}.story-asset-event-item{justify-content:flex-start;gap:8px;}.story-asset-event-item .asset-event-marker{flex:0 0 auto;min-width:1.55rem;width:auto;}.story-asset-event-details{min-width:0;}.scene-inspector-root{display:grid;gap:12px;}.scene-overview-card{display:grid;gap:10px;border:1px solid rgba(47,111,99,0.18);border-radius:10px;padding:12px;background:linear-gradient(180deg,rgba(47,111,99,0.08),rgba(255,255,255,0.88));}.scene-overview-card h3{margin:0;font-size:1.05rem;}.scene-overview-card .muted{display:flex;flex-wrap:wrap;gap:7px;margin:0;}.overview-chip-grid,.context-nav,.breadcrumb-trail,.inspector-nav-links{display:flex;flex-wrap:wrap;gap:7px;}.overview-chip,.context-nav a,.breadcrumb-trail a,.breadcrumb-trail span{display:inline-flex;align-items:center;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-decoration:none;background:rgba(255,255,255,0.72);}.overview-chip.attention{color:#7a5527;border-color:rgba(205,154,72,0.35);background:rgba(205,154,72,0.14);}.overview-outcome{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;margin:0;color:var(--plotline-muted);}.inspector-quick-nav{position:sticky;top:0;z-index:5;display:grid;gap:8px;border:1px solid var(--plotline-line);border-radius:10px;padding:10px;background:rgba(255,255,255,0.94);box-shadow:0 10px 24px rgba(55,48,39,0.08);backdrop-filter:blur(8px);}.inspector-nav-links a{border:1px solid var(--plotline-line);border-radius:999px;padding:4px 8px;color:var(--plotline-muted);font-size:0.76rem;font-weight:800;text-decoration:none;}.inspector-nav-links a:hover,.inspector-nav-links a.active{color:var(--plotline-accent-dark);border-color:rgba(47,111,99,0.35);background:rgba(47,111,99,0.08);}.inspector-accordion-toggle{display:flex;align-items:center;justify-content:space-between;width:100%;border:0;padding:0;color:var(--plotline-ink);font-size:0.95rem;font-weight:900;text-align:left;background:transparent;}.inspector-accordion-toggle::before{content:"+";display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:999px;margin-right:7px;color:var(--plotline-accent-dark);background:rgba(47,111,99,0.09);}.inspector-section.is-open>.inspector-accordion-toggle::before{content:"-";}.inspector-accordion-toggle span:first-child{margin-right:auto;}.accordion-count{color:var(--plotline-muted);font-size:0.75rem;}.inspector-subheading{margin:14px 0 8px;color:var(--plotline-muted);font-size:0.88rem;font-weight:900;}.inspector-accordion-body{display:none;margin-top:12px;}.inspector-section.is-open>.inspector-accordion-body{display:block;}.inspector-section.is-filtered-out{display:none;}.breadcrumb-trail{margin-bottom:12px;}.breadcrumb-trail a:hover,.context-nav a:hover{color:var(--plotline-accent-dark);border-color:rgba(47,111,99,0.35);background:rgba(47,111,99,0.08);}.context-header,.working-context-banner{display:flex;align-items:center;justify-content:space-between;gap:14px;border:1px solid var(--plotline-line);border-radius:10px;margin-bottom:16px;padding:10px 12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.context-title{display:grid;gap:2px;}.context-title strong{color:var(--plotline-ink);}.health-kpi-grid,.analytics-grid-two,.analytics-grid-three{display:grid;gap:14px;margin:18px 0;}.health-kpi-grid{grid-template-columns:repeat(4,minmax(0,1fr));}.health-kpi-grid .plain-card{display:grid;gap:4px;}.health-kpi-grid strong{color:var(--plotline-ink);font-size:2rem;line-height:1;}.analytics-grid-two{grid-template-columns:repeat(2,minmax(0,1fr));}.analytics-grid-three{grid-template-columns:repeat(3,minmax(0,1fr));}.analytics-section{border:1px solid var(--plotline-line);border-radius:10px;margin:18px 0;padding:16px;background:rgba(255,255,255,0.84);box-shadow:0 14px 34px rgba(55,48,39,0.07);}.analytics-section-heading{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:14px;}.analytics-section-heading h2,.plain-card h3{margin:0;}.analytics-metric-stack{display:grid;gap:12px;overflow-x:auto;padding-bottom:4px;}.metric-shape-chart{display:grid;gap:12px;}.metric-shape-intro{max-width:760px;margin:0;color:var(--plotline-muted);}.metric-toggle-row{display:flex;flex-wrap:wrap;gap:8px;}.metric-toggle-pill{display:inline-flex;align-items:center;gap:6px;border:1px solid rgba(82,75,65,0.16);border-radius:999px;padding:5px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.78);cursor:pointer;}.metric-toggle-pill::before{content:"";width:10px;height:10px;border-radius:999px;background:var(--metric-colour);}.metric-toggle-pill input{margin:0;accent-color:var(--metric-colour);}.timeline-metric-edit-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:end;}.timeline-metric-edit-select{display:grid;gap:3px;min-width:180px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;}.timeline-metric-edit-status{align-self:center;border:1px solid rgba(47,111,99,0.18);border-radius:999px;padding:5px 9px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.72);}.timeline-metric-edit-hint{font-size:0.82rem;}.metric-chart-frame canvas.metric-curve-editing{cursor:ns-resize;}.metric-chart-frame{position:relative;min-height:320px;border:1px solid var(--plotline-line);border-radius:10px;padding:14px 12px 32px;background:linear-gradient(180deg,rgba(255,255,255,0.92),rgba(247,245,240,0.76));}.metric-timeline-frame{width:calc((var(--scene-count) * var(--timeline-scene-width))+((var(--scene-count) - 1) * var(--timeline-grid-gap)));}.metric-chart-frame canvas{width:100%;height:300px;}.metric-timeline-board .metric-graph-stack{width:max-content;min-width:100%;}.metric-timeline-board .metric-graph-row{grid-template-columns:var(--timeline-label-width) repeat(var(--scene-count),var(--timeline-scene-width));gap:var(--timeline-grid-gap);min-width:100%;}.metric-timeline-board .metric-graph-points{display:contents;}.metric-timeline-board .metric-point{border:1px solid rgba(47,111,99,0.12);border-radius:8px;background:rgba(255,255,255,0.62);}.metric-raw-details{border-top:1px solid var(--plotline-line);padding-top:8px;}.metric-raw-details summary{color:var(--plotline-muted);font-size:0.82rem;font-weight:800;cursor:pointer;}.timeline-control-panel{display:grid;gap:12px;border:1px solid var(--plotline-line);border-radius:10px;margin-bottom:16px;padding:12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.timeline-filter-drawer summary{color:var(--plotline-ink);font-weight:900;cursor:pointer;}.timeline-filter-grid{display:grid;grid-template-columns:repeat(6,minmax(130px,1fr));gap:10px;margin-top:12px;}.timeline-filter-checks,.timeline-filter-actions,.timeline-visibility-panel,.timeline-preset-panel,.preset-chip-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}.timeline-filter-checks{grid-column:span 3;color:var(--plotline-muted);font-size:0.82rem;font-weight:700;}.timeline-filter-actions{grid-column:span 3;justify-content:flex-end;}.timeline-visibility-panel label,.preset-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 8px;color:var(--plotline-muted);font-size:0.78rem;font-weight:800;background:rgba(255,255,255,0.76);}.timeline-preset-panel form{display:inline-flex;align-items:center;gap:6px;}.preset-chip a{color:var(--plotline-accent-dark);text-decoration:none;}.preset-chip button{border:0;color:var(--plotline-muted);background:transparent;font-weight:900;}.timeline-focus-banner{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid rgba(47,111,99,0.22);border-radius:10px;margin-bottom:16px;padding:10px 12px;background:rgba(47,111,99,0.08);}.thread-marker-icon{display:inline-flex;align-items:center;justify-content:center;min-width:16px;font-size:0.78rem;font-weight:900;}.thread-marker-type-start .thread-marker-icon,.thread-marker-type-resolve .thread-marker-icon,.thread-marker-type-abandon .thread-marker-icon,.thread-marker-type-twist .thread-marker-icon{font-size:0.9rem;}.thread-marker-type-start{border-radius:8px 999px 999px 8px;}.thread-marker-type-twist{border-color:#b8762b;background:#fff4dc;}.thread-marker-type-branch,.thread-marker-type-split,.thread-marker-type-merge{border-color:#6750a4;background:#f0ebff;}.thread-marker-type-reveal .thread-marker-icon{border:1px solid currentColor;border-radius:999px;font-size:0;}.thread-marker-type-reveal .thread-marker-icon::after{content:"";width:4px;height:4px;border-radius:999px;background:currentColor;}.timeline-navigation-card{display:grid;grid-template-areas:"icon copy" "icon actions";grid-template-columns:auto minmax(0,620px);gap:8px 14px;align-items:center;justify-content:center;border:1px solid rgba(47,111,99,0.42);border-left:5px solid var(--plotline-accent);border-radius:8px;margin:0 0 12px;padding:14px 16px;max-height:280px;overflow:hidden;color:var(--plotline-ink);background:linear-gradient(135deg,rgba(238,245,242,0.98),rgba(255,255,255,0.94));box-shadow:0 10px 26px rgba(30,37,43,0.08);opacity:1;transform:translateY(0);transition:opacity 1.15s ease,max-height 1.2s ease,margin 1.2s ease,padding 1.2s ease,transform 1.15s ease;}.timeline-navigation-card[hidden]{display:none;}.timeline-navigation-card.is-dismissing{margin-bottom:0;padding-top:0;padding-bottom:0;max-height:0;opacity:0;transform:translateY(-6px);}.timeline-navigation-card-icon{grid-area:icon;display:grid;place-items:center;width:42px;height:42px;border-radius:50%;color:#fff;background:var(--plotline-accent);font-size:1.25rem;font-weight:900;}.timeline-navigation-card-copy{grid-area:copy;text-align:center;}.timeline-navigation-card-copy h2{margin:0 0 6px;color:var(--plotline-accent-dark);font-size:1rem;font-weight:900;}.timeline-navigation-card-copy p{margin:2px 0;color:var(--plotline-ink);font-size:0.9rem;}.timeline-navigation-card-actions{grid-area:actions;display:flex;flex-wrap:wrap;gap:8px;justify-content:center;}.timeline-horizontal-overflow{transition:box-shadow 0.18s ease;}.timeline-horizontal-overflow.has-scroll-left{box-shadow:inset 18px 0 18px -20px rgba(30,37,43,0.55);}.timeline-horizontal-overflow.has-scroll-right{box-shadow:inset -18px 0 18px -20px rgba(30,37,43,0.55);}.timeline-horizontal-overflow.has-scroll-left.has-scroll-right{box-shadow:inset 18px 0 18px -20px rgba(30,37,43,0.55),inset -18px 0 18px -20px rgba(30,37,43,0.55);}[data-theme="dark"] .timeline-navigation-card{border-color:rgba(111,169,155,0.52);border-left-color:#6fa99b;color:#f4eadc;background:linear-gradient(135deg,rgba(34,83,74,0.72),rgba(32,31,34,0.96));box-shadow:0 12px 28px rgba(0,0,0,0.28);}[data-theme="dark"] .timeline-navigation-card-copy h2,[data-theme="dark"] .timeline-navigation-card-copy p{color:#f4eadc;}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-left{box-shadow:inset 18px 0 18px -20px rgba(244,234,220,0.55);}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-right{box-shadow:inset -18px 0 18px -20px rgba(244,234,220,0.55);}[data-theme="dark"] .timeline-horizontal-overflow.has-scroll-left.has-scroll-right{box-shadow:inset 18px 0 18px -20px rgba(244,234,220,0.55),inset -18px 0 18px -20px rgba(244,234,220,0.55);}@media (prefers-reduced-motion:reduce){.timeline-navigation-card{transition:opacity 0.12s ease;}}.timeline-scene-card.filter-dim,.timeline-scene-card.focus-dim,.lane-dim{opacity:0.35;}.timeline-scene-card.focus-match,.timeline-scene-card.filter-match.focus-match{outline:3px solid rgba(47,111,99,0.32);box-shadow:0 12px 26px rgba(47,111,99,0.16);}.timeline-section-hidden{display:none !important;}.hide-scene-cards .timeline-scene-card{display:none;}.timeline-control-panel{position:sticky;top:56px;z-index:18;}.timeline-control-select{padding-right:6px;}.timeline-control-select .form-select{width:auto;min-width:132px;border:0;padding-top:2px;padding-bottom:2px;background-color:transparent;color:var(--plotline-accent-dark);font-weight:800;}.timeline-jump-panel{display:grid;grid-template-columns:auto minmax(180px,1.2fr) minmax(180px,1fr) minmax(170px,0.9fr) minmax(180px,1fr) auto;gap:8px;align-items:center;width:100%;}.timeline-shortcut-hint{color:var(--plotline-muted);font-size:0.76rem;font-weight:700;white-space:nowrap;}.timeline-minimap{display:flex;align-items:stretch;gap:4px;margin:0 0 12px;padding:8px;max-width:100%;min-width:0;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-gutter:stable;border:1px solid rgba(47,111,99,0.18);border-radius:8px;background:rgba(255,255,255,0.72);}.timeline-minimap button{position:relative;flex:0 0 max(42px,calc(var(--chapter-scenes) * 18px));min-width:42px;min-height:34px;border:1px solid rgba(47,111,99,0.18);border-radius:7px;color:var(--plotline-accent-dark);background:linear-gradient(180deg,#f8fbf9 0%,#edf4f1 100%);font-size:0.72rem;font-weight:800;}.timeline-minimap button.is-active{border-color:var(--plotline-accent);color:#fff;background:linear-gradient(180deg,var(--plotline-accent) 0%,var(--plotline-accent-dark) 100%);box-shadow:0 0 0 2px rgba(47,111,99,0.14);}.timeline-minimap button::after{content:"";position:absolute;right:5px;bottom:5px;width:calc(var(--chapter-warnings) * 4px);max-width:28px;height:4px;border-radius:999px;background:#b45c5c;opacity:0.75;}.timeline-drag-palette,.drag-drop-panel{border:1px solid rgba(47,111,99,0.18);border-radius:10px;margin-bottom:12px;padding:12px;background:rgba(255,255,255,0.84);box-shadow:0 10px 24px rgba(55,48,39,0.05);}.timeline-drag-palette{display:grid;grid-template-columns:minmax(220px,0.35fr) minmax(0,1fr);gap:12px;align-items:center;}.drag-chip-group{display:flex;flex-wrap:wrap;gap:6px;max-height:104px;overflow:auto;padding-right:4px;}.drag-chip{display:inline-flex;align-items:center;border:1px solid var(--plotline-line);border-radius:999px;padding:4px 9px;background:#fff;color:var(--plotline-ink);font-size:0.78rem;font-weight:800;cursor:grab;}.drag-chip.character{border-color:#dacb9e;background:#fff8e8;}.drag-chip.asset{border-color:#ded9ea;background:#f4f0ff;}.drag-chip.location{border-color:rgba(47,111,99,0.18);background:#eef8f4;}.is-dragging{opacity:0.55;}.drop-target-active{outline:3px solid rgba(47,111,99,0.28);outline-offset:2px;}.timeline-chapter.chapter-drop-active,.timeline-scenes.drop-chapter-end{background:rgba(47,111,99,0.06);}.timeline-scenes.drop-chapter-end::after{content:"Drop scene at end of chapter";display:flex;align-items:center;justify-content:center;min-width:var(--timeline-scene-width);min-height:74px;border:2px dashed rgba(197,139,43,0.48);border-radius:12px;color:#7a5527;background:rgba(255,248,232,0.82);font-size:0.8rem;font-weight:900;}.timeline-scene-card.drop-before{box-shadow:inset 5px 0 0 #c58b2b,0 12px 26px rgba(197,139,43,0.16);}.timeline-scene-card.drop-after{box-shadow:inset -5px 0 0 #c58b2b,0 12px 26px rgba(197,139,43,0.16);}.drag-drop-panel{position:sticky;top:132px;z-index:19;}.drag-drop-panel-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;}.drag-drop-panel h2{margin:0;font-size:1.08rem;}.drag-drop-form{border-top:1px solid var(--plotline-line);margin-top:10px;padding-top:10px;}.scene-move-modal-content{border:1px solid rgba(47,111,99,0.18);border-radius:14px;background:var(--plotline-surface);color:var(--plotline-ink);box-shadow:0 24px 70px rgba(55,48,39,0.22);}.scene-move-modal-content .modal-header,.scene-move-modal-content .modal-footer{border-color:var(--plotline-line);}.scene-move-modal-content .modal-title{margin:0;color:var(--plotline-ink);font-size:1.2rem;font-weight:900;}.scene-move-summary{margin:0 0 12px;color:var(--plotline-ink);font-size:1rem;font-weight:800;}[data-theme="dark"] .scene-move-modal-content{background:#201f22;color:#f4eadc;border-color:rgba(244,234,220,0.16);box-shadow:0 24px 70px rgba(0,0,0,0.55);}[data-theme="dark"] .scene-move-modal-content .modal-title,[data-theme="dark"] .scene-move-summary{color:#f4eadc;}[data-theme="dark"] .scene-move-modal-content .modal-header,[data-theme="dark"] .scene-move-modal-content .modal-footer{border-color:rgba(244,234,220,0.14);}[data-theme="dark"] .scene-move-modal-content .btn-close{filter:invert(1) grayscale(100%);}.plain-preview{border:1px solid rgba(197,139,43,0.28);border-radius:8px;margin:10px 0 0;padding:8px 10px;color:#5e4518;background:#fff8e8;font-size:0.86rem;font-weight:800;}.drag-check-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 10px;color:var(--plotline-muted);font-size:0.82rem;font-weight:700;}.timeline-section-header,.lane-board-heading,.pacing-heading{position:sticky;left:0;z-index:6;}.timeline-section-header{display:flex;align-items:center;justify-content:space-between;gap:10px;width:calc(var(--timeline-label-width)+(var(--scene-count) * var(--timeline-scene-width))+(var(--scene-count) * var(--timeline-grid-gap)));min-width:100%;margin-bottom:10px;border-radius:8px;padding:8px 10px;background:rgba(255,255,255,0.92);box-shadow:0 8px 16px rgba(30,37,43,0.05);}.timeline-section-header button,.lane-board-heading button,.plot-lane-board-heading button,.pacing-heading button,.lane-group-heading{border:0;padding:0;color:var(--plotline-accent-dark);background:transparent;font:inherit;font-weight:900;text-align:left;}.timeline-section-header button::before,.lane-board-heading button::before,.plot-lane-board-heading button::before,.pacing-heading button::before,.lane-group-heading::before{content:"v";display:inline-block;margin-right:6px;color:var(--plotline-muted);font-size:0.72rem;}.timeline-section-header button.is-collapsed::before,.lane-board-heading button.is-collapsed::before,.plot-lane-board-heading button.is-collapsed::before,.pacing-heading button.is-collapsed::before,.lane-group-heading.is-collapsed::before{content:">";}.lane-group{display:grid;gap:7px;}.character-lane-group-body{display:grid;gap:7px;}.lane-group-heading{position:sticky;left:0;z-index:6;width:var(--timeline-label-width);border-top:1px solid rgba(47,111,99,0.12);padding:7px 8px 2px;color:var(--plotline-muted);background:rgba(247,250,248,0.96);font-size:0.78rem;text-transform:uppercase;}.timeline-section-collapsed{display:none !important;}.timeline-chapter-title{position:sticky;top:0;z-index:5;background:rgba(238,245,242,0.96);backdrop-filter:blur(6px);}.scene-pov-label,.metric-mini-summary{display:inline-flex;width:fit-content;border-radius:999px;padding:2px 7px;font-size:0.72rem;font-weight:800;}.scene-pov-label{color:#514018;background:#fff3d3;}.metric-mini-summary{color:var(--plotline-accent-dark);background:rgba(47,111,99,0.08);}.scene-overview-panel{display:none;gap:8px;margin-top:4px;}.scene-overview-section{display:grid;gap:4px;}.scene-overview-label{color:var(--plotline-muted);font-size:0.68rem;font-weight:900;letter-spacing:0.06em;text-transform:uppercase;}.scene-overview-chip-row{display:flex;flex-wrap:wrap;gap:5px;min-width:0;}.scene-overview-chip,.scene-overview-empty,.scene-overview-brief{display:inline-flex;width:fit-content;max-width:100%;border-radius:999px;padding:3px 8px;background:rgba(47,111,99,0.08);color:var(--plotline-ink);font-size:0.72rem;font-weight:750;line-height:1.25;overflow-wrap:anywhere;}.scene-overview-chip.is-pov{border:1px solid rgba(197,139,43,0.38);background:#fff3d3;}.scene-overview-chip.is-important{border:1px solid rgba(103,80,164,0.3);background:#f0edf8;}.scene-overview-chip.is-more,.scene-overview-empty{color:var(--plotline-muted);background:rgba(102,113,123,0.08);}.scene-overview-brief{display:block;width:auto;border-radius:8px;background:rgba(255,255,255,0.62);color:var(--plotline-muted);font-weight:600;}.timeline-scene-card.search-hit,.timeline-scene-card.keyboard-focus{outline:3px solid rgba(197,139,43,0.34);box-shadow:0 12px 26px rgba(197,139,43,0.16);}.timeline-scene-card.search-dim{opacity:0.28;}.thread-marker,.asset-marker,.character-marker{transition:transform 0.12s ease,box-shadow 0.12s ease;}.thread-marker:hover,.asset-marker:hover,.character-marker:hover{transform:translateY(-1px);box-shadow:0 6px 12px rgba(30,37,43,0.12);}.timeline-filtered-root.density-compact{--timeline-scene-width:170px;--timeline-grid-gap:6px;}.timeline-filtered-root.density-expanded{--timeline-scene-width:280px;--timeline-grid-gap:14px;}.timeline-filtered-root.density-compact .timeline-scene-card,.timeline-filtered-root.zoom-book .timeline-scene-card{gap:4px;padding:9px;}.timeline-filtered-root.density-compact .scene-summary,.timeline-filtered-root.density-compact .purpose-chip-row,.timeline-filtered-root.density-compact .metric-mini-summary,.timeline-filtered-root.zoom-book .scene-summary,.timeline-filtered-root.zoom-book .purpose-chip-row,.timeline-filtered-root.zoom-book .metric-mini-summary,.timeline-filtered-root.zoom-book .location-pill,.timeline-filtered-root.zoom-book .scene-pov-label{display:none;}.timeline-filtered-root.zoom-book{--timeline-scene-width:150px;--timeline-grid-gap:6px;}.timeline-filtered-root.zoom-scene-detail{--timeline-scene-width:300px;}.timeline-filtered-root.zoom-scene-detail .scene-summary{-webkit-line-clamp:7;}.timeline-filtered-root.zoom-scene-overview{--timeline-scene-width:380px;}.timeline-filtered-root.zoom-scene-overview .timeline-scenes{min-height:320px;}.timeline-filtered-root.zoom-scene-overview .timeline-scene-card{gap:8px;padding:14px;}.timeline-filtered-root.zoom-scene-overview .scene-summary{display:none;}.timeline-filtered-root.zoom-scene-overview .scene-overview-panel{display:grid;}.timeline-filtered-root.density-expanded .timeline-scenes{min-height:230px;}.timeline-control-panel{position:relative;top:auto;z-index:4;display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:10px;padding:8px;box-shadow:none;}.timeline-filter-drawer,.timeline-control-group{border:1px solid var(--plotline-line);border-radius:999px;background:rgba(255,255,255,0.82);}.timeline-filter-drawer[open],.timeline-control-group[open]{border-radius:10px;flex-basis:100%;}.timeline-filter-drawer summary,.timeline-control-group summary{min-width:max-content;padding:5px 10px;color:var(--plotline-accent-dark);font-size:0.82rem;font-weight:900;cursor:pointer;list-style:none;}.timeline-filter-drawer summary::-webkit-details-marker,.timeline-control-group summary::-webkit-details-marker,.timeline-drag-palette summary::-webkit-details-marker{display:none;}.timeline-filter-drawer summary::after,.timeline-control-group summary::after,.timeline-drag-palette summary::after{content:" v";color:var(--plotline-muted);font-size:0.72rem;}.timeline-filter-drawer[open] summary::after,.timeline-control-group[open] summary::after,.timeline-drag-palette[open] summary::after{content:" ^";}.timeline-filter-grid{grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;max-height:min(48vh,430px);overflow:auto;padding:0 10px 10px;}.timeline-filter-grid .form-label{margin-bottom:2px;font-size:0.72rem;font-weight:800;}.timeline-filter-checks,.timeline-filter-actions{grid-column:1 / -1;}.timeline-visibility-panel,.timeline-jump-panel,.timeline-preset-panel{padding:0 10px 10px;}.timeline-jump-panel{grid-template-columns:minmax(180px,1.5fr) repeat(3,minmax(150px,1fr));}.timeline-shortcut-hint{grid-column:1 / -1;}.timeline-preset-panel form{flex-wrap:nowrap;}.timeline-preset-panel .form-control{width:150px;}.timeline-preset-panel .btn,.timeline-filter-actions .btn{white-space:nowrap;}.timeline-drag-palette{display:block;margin-bottom:8px;padding:7px 9px;box-shadow:none;}.timeline-drag-palette summary{color:var(--plotline-accent-dark);font-size:0.82rem;font-weight:900;cursor:pointer;}.timeline-drag-palette .drag-chip-group{margin-top:8px;}.drag-drop-panel{position:relative;top:auto;z-index:9;box-shadow:0 12px 28px rgba(30,37,43,0.08);}.timeline-filtered-root,.timeline-filtered-root.density-compact,.timeline-filtered-root.zoom-book{--timeline-scene-width:220px;--timeline-grid-gap:10px;}.timeline-filtered-root.density-expanded,.timeline-filtered-root.zoom-scene-detail{--timeline-scene-width:290px;}.timeline-filtered-root.density-compact.zoom-book{--timeline-scene-width:200px;}.timeline-chapter,.timeline-scene-card,.timeline-empty-scene{overflow-wrap:normal;word-break:normal;}.timeline-scene-card strong,.timeline-chapter-title strong,.plot-lane-label strong,.asset-lane-label strong,.character-lane-label strong{min-width:0;white-space:normal;word-break:normal;overflow-wrap:break-word;}.timeline-scene-card{cursor:grab;}.timeline-scene-card:active,.drag-chip:active,[draggable="true"]:active{cursor:grabbing;}body.drag-active .timeline-scene-card,body.dragging-asset [data-asset-drop-target],body.dragging-location [data-drag-type="location"]{transition:outline-color 0.12s ease,box-shadow 0.12s ease,opacity 0.12s ease;}body.dragging-character .timeline-scene-card,body.dragging-asset .timeline-scene-card,body.dragging-scene .timeline-scene-card,body.dragging-scene .timeline-scenes[data-chapter-drop-target],body.dragging-asset [data-asset-drop-target],body.dragging-location [data-drag-type="location"]{outline:1px dashed rgba(47,111,99,0.22);outline-offset:2px;}.is-dragging{opacity:0.42;transform:scale(0.98);}.drop-target-active{outline:3px solid rgba(47,111,99,0.42) !important;outline-offset:3px;}.analytics-metric-row{display:grid;grid-template-columns:170px minmax(560px,1fr);gap:12px;align-items:stretch;}.analytics-metric-label{display:flex;align-items:center;border-right:1px solid var(--plotline-line);color:var(--plotline-muted);font-weight:800;}.analytics-sparkline{display:grid;grid-template-columns:repeat(var(--point-count),minmax(28px,1fr));align-items:end;gap:5px;min-height:88px;border-bottom:1px solid rgba(47,111,99,0.25);padding-top:10px;}.analytics-bar{position:relative;display:flex;align-items:end;justify-content:center;min-height:12px;height:max(12px,var(--bar-height));border-radius:6px 6px 2px 2px;color:var(--plotline-accent-dark);text-decoration:none;background:linear-gradient(180deg,rgba(47,111,99,0.58),rgba(47,111,99,0.18));}.analytics-bar:hover{background:linear-gradient(180deg,rgba(47,111,99,0.82),rgba(47,111,99,0.28));}.analytics-bar span{position:absolute;bottom:calc(100%+3px);color:var(--plotline-muted);font-size:0.68rem;font-weight:800;}.analytics-list-item,.analytics-link-row,.analytics-count-row,.purpose-stat-row{border-top:1px solid var(--plotline-line);padding:9px 0;}.analytics-list-item{display:grid;gap:3px;}.analytics-list-item p{margin:0;}.analytics-link-row,.analytics-count-row{display:flex;align-items:center;justify-content:space-between;gap:12px;}.analytics-link-row{color:inherit;text-decoration:none;}.analytics-link-row:hover{color:var(--plotline-accent-dark);}.analytics-link-row span,.analytics-link-row strong{min-width:0;}.purpose-stat-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(90px,1.5fr) 42px;align-items:center;gap:10px;}.purpose-stat-bar{overflow:hidden;height:8px;border-radius:999px;background:rgba(47,111,99,0.08);}.purpose-stat-bar span{display:block;height:100%;border-radius:inherit;background:var(--plotline-accent);}.inspector-actions{position:sticky;bottom:-16px;display:flex;gap:8px;border-top:1px solid var(--plotline-line);margin:2px -16px -16px;padding:12px 16px;background:rgba(255,255,255,0.95);backdrop-filter:blur(8px);}.story-bible-heading{align-items:end;}.story-bible-search{display:flex;gap:8px;min-width:min(100%,420px);}.story-bible-search .form-control{min-width:0;}.story-bible-nav{position:sticky;top:72px;z-index:4;display:flex;flex-wrap:wrap;gap:8px;margin:0 0 18px;padding:10px;border:1px solid var(--plotline-line);border-radius:12px;background:rgba(250,249,246,0.92);backdrop-filter:blur(10px);}.story-bible-nav a,.story-bible-actions a{display:inline-flex;align-items:center;border-radius:999px;padding:6px 10px;background:rgba(47,111,99,0.08);color:var(--plotline-ink);font-size:0.86rem;font-weight:650;text-decoration:none;}.story-bible-nav a:hover,.story-bible-actions a:hover{background:rgba(47,111,99,0.16);}.story-bible-section{margin:0 0 28px;}.story-bible-section-heading{display:flex;align-items:end;justify-content:space-between;gap:16px;margin-bottom:12px;}.story-bible-section-heading h2{margin:0;}.soft-count{color:var(--plotline-muted);font-size:0.9rem;font-weight:650;white-space:nowrap;}.story-bible-grid,.story-bible-search-results{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;}.story-bible-grid-compact{grid-template-columns:repeat(auto-fit,minmax(260px,1fr));}.story-bible-card{border:1px solid var(--plotline-line);border-radius:14px;padding:14px;background:rgba(255,255,255,0.86);box-shadow:0 14px 34px rgba(36,32,26,0.06);}.story-bible-card h3{margin:0 0 8px;font-size:1.05rem;}.story-bible-card h4{margin:14px 0 8px;font-size:0.96rem;}.story-bible-card p{color:var(--plotline-muted);}.story-bible-card-title{display:flex;align-items:start;justify-content:space-between;gap:10px;}.story-bible-card-title span{border:1px solid var(--plotline-line);border-radius:999px;padding:3px 8px;background:rgba(250,249,246,0.9);color:var(--plotline-muted);font-size:0.78rem;font-weight:700;white-space:nowrap;}.story-bible-meta{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0;}.story-bible-meta span{border-radius:999px;padding:4px 8px;background:rgba(36,32,26,0.05);color:var(--plotline-muted);font-size:0.78rem;font-weight:650;}.story-bible-facts{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 10px;margin:12px 0;}.story-bible-facts dt{color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-transform:uppercase;}.story-bible-facts dd{margin:0;min-width:0;overflow-wrap:anywhere;}.story-bible-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;}.story-bible-link-list{display:grid;gap:8px;margin:0;padding:0;list-style:none;}.story-bible-link-list li{display:grid;gap:2px;padding:8px 0;border-bottom:1px solid rgba(36,32,26,0.08);}.story-bible-link-list li:last-child{border-bottom:0;}.story-bible-link-list span{color:var(--plotline-muted);font-size:0.88rem;}.story-bible-timeline-summary{display:grid;gap:14px;}.story-bible-wide-card{max-width:none;}.story-bible-chapter-summary{border-top:1px solid var(--plotline-line);padding-top:8px;}.story-bible-scene-summary{display:grid;grid-template-columns:minmax(220px,1.5fr) repeat(3,minmax(120px,0.8fr));gap:8px;padding:9px 0;border-top:1px solid rgba(36,32,26,0.08);}.story-bible-scene-summary p{grid-column:1 / -1;margin:0;}.story-bible-scene-summary span{color:var(--plotline-muted);font-size:0.88rem;}.attention-list{display:grid;gap:10px;}.attention-list article{display:grid;grid-template-columns:max-content minmax(0,1fr) auto;align-items:center;gap:10px;border:1px solid var(--plotline-line);border-radius:12px;padding:10px 12px;background:rgba(255,255,255,0.82);}.attention-list p{grid-column:2 / -1;margin:0;color:var(--plotline-muted);}.writer-workspace-form,.writer-add-form,.writer-edit-form,.chapter-goal-form{display:grid;gap:10px;}.writer-checkbox-grid{display:flex;flex-wrap:wrap;gap:8px 14px;}.writer-checkbox-grid label{display:inline-flex;align-items:center;gap:6px;color:var(--plotline-muted);font-size:0.86rem;font-weight:650;}.writer-priority-control{display:grid;grid-template-columns:minmax(0,1fr) max-content;align-items:center;gap:12px;}.writer-priority-control .form-range{min-width:0;}.writer-note-list,.writer-queue-list{display:grid;gap:10px;}.writer-mini-card{border:1px solid var(--plotline-line);border-radius:12px;padding:10px;background:rgba(255,255,255,0.72);}.writer-mini-card summary{display:flex;align-items:center;gap:8px;cursor:pointer;}.writer-mini-card summary strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.attachment-card-list{display:grid;gap:10px;}.attachment-summary{align-items:center;}.attachment-kind{border-radius:999px;padding:3px 8px;background:rgba(47,111,99,0.1);color:var(--plotline-accent);font-size:0.76rem;font-weight:800;text-transform:uppercase;}.attachment-card-body{display:grid;gap:6px;margin-top:10px;}.attachment-card-body p{margin:0;}.attachment-add-card{margin-top:10px;}.writer-checklist{display:grid;gap:6px;}.writer-checklist-row,.writer-add-inline{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;}.writer-remove-inline{display:flex;justify-content:end;margin:-2px 0 4px;}.writer-dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin-bottom:26px;}.writer-dashboard-panel{border:1px solid var(--plotline-line);border-radius:14px;padding:14px;background:rgba(255,255,255,0.7);box-shadow:0 14px 34px rgba(36,32,26,0.05);}.writer-queue-card{border:1px solid var(--plotline-line);border-radius:12px;padding:12px;background:rgba(255,255,255,0.9);}.writer-queue-card h3{margin:0;font-size:1rem;}.writer-queue-card p{margin:8px 0 0;color:var(--plotline-muted);}.writer-queue-title{display:flex;align-items:start;justify-content:space-between;gap:12px;}.writer-kpi{display:block;color:var(--plotline-accent);font-size:2.2rem;line-height:1;}.export-action-row{margin:-8px 0 18px;}.dynamics-timeline{position:relative;min-height:128px;border:1px solid var(--plotline-line);border-radius:14px;background:linear-gradient(180deg,rgba(47,111,99,0.07),rgba(255,255,255,0.84));overflow:hidden;}.dynamics-timeline::before{content:"";position:absolute;left:12px;right:12px;top:64px;height:1px;background:rgba(36,32,26,0.18);}.dynamics-marker{position:absolute;bottom:18px;width:12px;height:86px;transform:translateX(-50%);display:flex;align-items:end;justify-content:center;}.dynamics-marker span{display:block;width:8px;min-height:12px;max-height:82px;border-radius:999px;background:var(--plotline-accent);box-shadow:0 8px 20px rgba(47,111,99,0.22);}.dynamics-marker.pov span{background:#8a4b2f;}.dynamics-timeline.relationship .dynamics-marker span{background:#7c5fb0;}.scenario-banner{display:flex;justify-content:space-between;gap:18px;align-items:flex-start;border:1px solid rgba(103,80,164,0.22);border-radius:12px;padding:16px;margin-bottom:16px;background:linear-gradient(135deg,rgba(103,80,164,0.10),rgba(255,255,255,0.86));box-shadow:0 12px 28px rgba(36,32,26,0.08);}.scenario-banner h1{margin:0 0 4px;}.scenario-banner p{margin:0;color:var(--plotline-muted);}.scenario-card{border-color:rgba(103,80,164,0.18);}.scenario-warning-strip{display:flex;gap:10px;align-items:center;border:1px solid var(--plotline-line);border-radius:10px;padding:10px 12px;margin-bottom:14px;background:rgba(255,255,255,0.76);color:var(--plotline-muted);}.scenario-warning-strip strong{color:var(--plotline-ink);}.scenario-board{border:1px solid var(--plotline-line);border-radius:12px;padding:12px;background:rgba(247,245,240,0.74);overflow:hidden;margin-bottom:18px;}.scenario-scroll{display:flex;gap:14px;overflow-x:auto;padding-bottom:8px;}.scenario-chapter{min-width:360px;max-width:520px;border:1px solid rgba(82,75,65,0.14);border-radius:10px;background:rgba(255,255,255,0.86);}.scenario-chapter header{display:grid;gap:2px;border-bottom:1px solid var(--plotline-line);padding:10px 12px;}.scenario-chapter header span{color:var(--plotline-muted);font-size:0.78rem;font-weight:800;text-transform:uppercase;}.scenario-scene-row{display:grid;gap:10px;padding:10px;}.scenario-scene-card{display:grid;gap:8px;border:1px solid rgba(82,75,65,0.12);border-radius:9px;padding:10px;background:white;}.scenario-scene-title{display:grid;gap:2px;}.scenario-scene-title span,.scenario-mini-data{color:var(--plotline-muted);font-size:0.78rem;}.scenario-mini-data{display:grid;gap:2px;}.scenario-move-actions,.scenario-chapter-form,.scenario-compare-list article{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}.scenario-chapter-form select{min-width:160px;width:auto;}.scenario-compare-list{display:grid;gap:10px;}.scenario-compare-list article{justify-content:space-between;border:1px solid var(--plotline-line);border-radius:9px;padding:10px;background:rgba(255,255,255,0.82);}.danger-zone{border-color:rgba(163,61,61,0.24);}.archive-filter-form{align-items:end;}.archive-item-list{display:grid;gap:10px;}.archive-item-card{display:flex;justify-content:space-between;gap:14px;align-items:center;border:1px solid var(--plotline-line);border-radius:10px;padding:12px;background:rgba(255,255,255,0.82);}.archive-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-items:end;}.delete-forever-form{display:inline-flex;margin:0;}.archive-item-card h3{margin:4px 0;}.archived-badge{display:inline-flex;border:1px solid rgba(82,75,65,0.16);border-radius:999px;padding:2px 8px;color:var(--plotline-muted);font-size:0.72rem;font-weight:800;text-transform:uppercase;background:rgba(247,245,240,0.86);}.restore-button{white-space:nowrap;}.archive-button-form{display:inline-flex;align-items:center;margin:0;}.acceptance-summary-grid{display:grid;grid-template-columns:repeat(3,minmax(160px,1fr));gap:12px;margin-bottom:16px;}.acceptance-summary{display:grid;gap:4px;padding:16px;}.acceptance-summary strong{font-size:2rem;line-height:1;}.acceptance-summary.pass{border-left:5px solid #4d7654;}.acceptance-summary.review{border-left:5px solid #b8762b;}.acceptance-summary.blocked{border-left:5px solid #963f36;}.acceptance-check-list{display:grid;gap:14px;}.acceptance-area{border:1px solid var(--plotline-line);border-radius:10px;padding:12px;background:rgba(255,255,255,0.62);}.acceptance-area h3{margin:0 0 10px;font-size:1.05rem;}.acceptance-check-items{display:grid;gap:8px;}.acceptance-check-item{display:grid;grid-template-columns:92px minmax(0,1fr);gap:10px;align-items:start;border:1px solid rgba(82,75,65,0.12);border-radius:8px;padding:10px;background:rgba(255,255,255,0.74);}.acceptance-check-item p{margin:2px 0 0;color:var(--plotline-muted);}.acceptance-status{display:inline-flex;justify-content:center;width:fit-content;min-width:74px;border-radius:999px;padding:3px 9px;font-size:0.72rem;font-weight:900;text-transform:uppercase;}.acceptance-check-item.pass .acceptance-status{color:#24512b;background:#e6f4e7;}.acceptance-check-item.review .acceptance-status{color:#7b4b13;background:#fbecd3;}.acceptance-check-item.blocked .acceptance-status{color:#7a2222;background:#fff0f0;}.plotline-confirm-modal .modal-title{color:var(--plotline-ink);}.plotline-confirm-modal .modal-body p{white-space:pre-line;}.delete-confirm-field{border:1px solid rgba(163,61,61,0.22);border-radius:8px;padding:12px;background:rgba(255,247,244,0.7);}@media print{header,.breadcrumb-trail,.context-header,.button-row,.story-bible-nav,.inspector-quick-nav{display:none !important;}.plotline-shell{max-width:none;padding:0;}}@media (max-width:760px){.plotline-shell{padding-left:14px;padding-right:14px;}.page-heading{display:block;}.page-heading .button-row,.timeline-filter{margin-top:14px;}.timeline-filter{align-items:stretch;flex-direction:column;}.timeline-navigation-card{grid-template-areas:"copy" "actions";grid-template-columns:1fr;}.timeline-navigation-card-icon{display:none;}.timeline-navigation-card-actions{justify-content:center;}.story-bible-search,.story-bible-section-heading{align-items:stretch;flex-direction:column;}.story-bible-scene-summary,.attention-list article{grid-template-columns:1fr;}.writer-dashboard-grid{grid-template-columns:1fr;}.writer-checklist-row,.writer-add-inline{grid-template-columns:1fr;}.trial-status-panel--signup,.trial-status-panel__heading,.trial-dashboard-banner{align-items:stretch;flex-direction:column;}.trial-dashboard-banner__actions,.trial-dashboard-banner__actions .btn,.trial-status-panel--signup .btn{width:100%;}.attention-list p{grid-column:auto;}}@media (max-width:900px){.workspace-layout,.workspace-layout.inspector-drawer-open{grid-template-columns:1fr;gap:14px;}.timeline-inspector-resizer{display:none;}.scene-inspector-panel{position:static;max-height:none;overflow:visible;}.scene-inspector-body{max-height:none;overflow:visible;}}@media (max-width:1100px){.metric-graph-row{grid-template-columns:1fr;}.health-kpi-grid,.analytics-grid-two,.analytics-grid-three{grid-template-columns:1fr;}.analytics-metric-row{grid-template-columns:1fr;}.analytics-metric-label{border-right:0;}}.floor-plan-list{display:grid;gap:12px;}.floor-plan-list-item{align-items:center;border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:flex;justify-content:space-between;gap:16px;padding:14px;}.floor-plan-list-item h2{font-size:1.05rem;margin:0 0 4px;}.floor-plan-list-item p{margin:0;}.floor-plan-tools{display:grid;gap:14px;}.floor-plan-meta-wide{max-width:none;}.floor-plan-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;}.floor-plan-tab{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:999px;color:inherit;padding:6px 12px;}.floor-plan-tab.active{background:var(--bs-primary,#2f6f63);border-color:var(--bs-primary,#2f6f63);color:#fff;}.floor-plan-layout{display:grid;gap:16px;grid-template-columns:minmax(0,1fr) minmax(320px,360px);}.floor-plan-editor-toolbar{align-items:center;background:rgba(255,255,255,.92);border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:grid;gap:12px;grid-template-columns:auto minmax(0,1fr) auto;margin-bottom:12px;padding:10px 12px;position:sticky;top:10px;z-index:20;}.floor-plan-editor-toolbar .muted{display:block;font-size:.76rem;line-height:1.1;}.floor-plan-toolbar-check,.floor-plan-reference-control{align-items:center;color:var(--muted-color,#6b756f);display:inline-flex;font-size:.82rem;font-weight:700;gap:6px;}.floor-plan-reference-control{align-items:flex-start;flex-direction:column;gap:2px;}.floor-plan-reference-control .form-select{min-width:180px;}.floor-plan-save-status{border:1px solid rgba(47,111,99,.2);border-radius:999px;color:var(--plotline-accent-dark,#22534a);background:rgba(47,111,99,.08);font-size:.78rem;font-weight:800;padding:4px 9px;}.floor-plan-save-status[data-save-state="dirty"]{border-color:rgba(184,118,43,.32);color:#7b4b12;background:rgba(251,236,211,.72);}.floor-plan-save-status[data-save-state="saving"]{border-color:rgba(51,117,155,.3);color:#245b78;background:rgba(233,243,248,.82);}.floor-plan-save-status[data-save-state="failed"]{border-color:rgba(163,61,61,.32);color:#8a3434;background:rgba(255,232,232,.9);}.floor-plan-floor{display:none;}.floor-plan-floor.active{display:block;}.floor-plan-stage{min-width:0;}.floor-plan-grid-wrap{max-width:100%;max-height:calc(100vh - 250px);min-height:min(58vh,520px);overflow:auto;padding-bottom:8px;}.floor-plan-grid{--cell-size:34px;background:linear-gradient(to right,rgba(93,111,101,.18) 1px,transparent 1px),linear-gradient(to bottom,rgba(93,111,101,.18) 1px,transparent 1px),var(--panel-bg,#fff);background-size:var(--cell-size) var(--cell-size),var(--cell-size) var(--cell-size),auto;border:1px solid var(--border-color,#d8ded9);border-radius:8px;height:calc(var(--grid-height) * var(--cell-size));min-width:calc(var(--grid-width) * var(--cell-size));position:relative;width:calc(var(--grid-width) * var(--cell-size));}.floor-plan-coordinate-label{color:rgba(33,61,55,.42);font-size:.62rem;font-weight:800;line-height:1;pointer-events:none;position:absolute;text-shadow:0 1px 0 rgba(255,255,255,.7);user-select:none;z-index:5;}.floor-plan-coordinate-label--column{left:calc(var(--coord-x) * var(--cell-size)+4px);top:3px;}.floor-plan-coordinate-label--row{left:4px;top:calc(var(--coord-y) * var(--cell-size)+4px);}.floor-plan-reference-overlay{inset:0;pointer-events:none;position:absolute;z-index:1;}.floor-plan-reference-block{align-items:center;background:rgba(47,111,99,.08);border:1px dashed rgba(47,111,99,.34);border-radius:2px;color:rgba(27,55,49,.46);display:flex;font-size:.62rem;font-weight:800;height:calc(var(--h) * var(--cell-size));justify-content:center;left:calc(var(--x) * var(--cell-size));line-height:1.05;overflow:hidden;padding:3px;position:absolute;text-align:center;top:calc(var(--y) * var(--cell-size));width:calc(var(--w) * var(--cell-size));}.floor-plan-reference-warning{background:rgba(251,236,211,.92);border:1px solid rgba(184,118,43,.34);border-radius:999px;color:#7b4b12;font-size:.76rem;font-weight:800;left:10px;padding:4px 10px;pointer-events:none;position:absolute;top:10px;z-index:6;}.floor-plan-background-image{height:auto;left:0;max-width:none;opacity:var(--bg-opacity,.35);pointer-events:none;position:absolute;top:0;transform:translate(var(--bg-offset-x,0),var(--bg-offset-y,0)) scale(var(--bg-scale,1));transform-origin:top left;user-select:none;width:100%;z-index:0;}.floor-plan-background-image.is-locked{pointer-events:none;}.floor-plan-block{align-items:center;--floor-plan-wall-color:rgba(44,84,75,.55);border:2px solid transparent;border-radius:2px;color:#12332c;cursor:grab;display:flex;font-size:.72rem;font-weight:700;height:calc(var(--h) * var(--cell-size));justify-content:center;left:calc(var(--x) * var(--cell-size));line-height:1.08;overflow:hidden;padding:4px;position:absolute;text-align:center;top:calc(var(--y) * var(--cell-size));touch-action:none;width:calc(var(--w) * var(--cell-size));z-index:2;}.floor-plan-wall-segment{background:var(--floor-plan-wall-color);pointer-events:none;position:absolute;z-index:2;}.floor-plan-wall-segment--north,.floor-plan-wall-segment--south{height:2px;left:var(--wall-start);width:var(--wall-length);}.floor-plan-wall-segment--north{top:0;}.floor-plan-wall-segment--south{bottom:0;}.floor-plan-wall-segment--east,.floor-plan-wall-segment--west{height:var(--wall-length);top:var(--wall-start);width:2px;}.floor-plan-wall-segment--east{right:0;}.floor-plan-wall-segment--west{left:0;}.floor-plan-block-label{display:-webkit-box;max-width:100%;overflow:hidden;overflow-wrap:normal;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:1;}.floor-plan-block[style*="--h:2"] .floor-plan-block-label,.floor-plan-block[style*="--h:3"] .floor-plan-block-label,.floor-plan-block[style*="--h:4"] .floor-plan-block-label,.floor-plan-block[style*="--h:5"] .floor-plan-block-label,.floor-plan-block[style*="--h:6"] .floor-plan-block-label,.floor-plan-block[style*="--h:7"] .floor-plan-block-label,.floor-plan-block[style*="--h:8"] .floor-plan-block-label{-webkit-line-clamp:2;}.floor-plan-block.selected{box-shadow:0 0 0 3px rgba(47,111,99,.28);outline:2px solid var(--bs-primary,#2f6f63);z-index:3;}.floor-plan-block.overlap{border-color:#b45544;box-shadow:inset 0 0 0 2px rgba(180,85,68,.18);}.floor-plan-block.is-hidden-location{background-image:repeating-linear-gradient(135deg,rgba(18,51,44,.08) 0,rgba(18,51,44,.08) 3px,transparent 3px,transparent 9px);box-shadow:inset 0 0 0 1px rgba(43,54,49,.18);}.floor-plan-block.is-hidden-location.selected{box-shadow:inset 0 0 0 1px rgba(43,54,49,.18),0 0 0 3px rgba(47,111,99,.28);}.floor-plan-block.is-hidden-location.overlap{box-shadow:inset 0 0 0 2px rgba(180,85,68,.18),inset 0 0 0 1px rgba(43,54,49,.18);}.floor-plan-secret-route{border-top:2px dashed rgba(69,55,42,.58);height:0;left:calc(var(--route-x,0) * var(--cell-size));opacity:.72;pointer-events:none;position:absolute;top:calc(var(--route-y,0) * var(--cell-size));transform:rotate(var(--route-angle,0));transform-origin:0 50%;width:calc(var(--route-length,0) * var(--cell-size));z-index:3;}.floor-plan-secret-route::after{background:rgba(255,250,242,.9);border:1px solid rgba(69,55,42,.5);border-radius:50%;content:"";height:7px;left:50%;position:absolute;top:-5px;transform:translateX(-50%);width:7px;}.floor-plan-transition-marker{align-items:center;--transition-marker-ink:#12332c;--transition-marker-window:#246f9f;--transition-marker-blocked:#9b342b;background:rgba(255,250,242,.98);border:1px solid rgba(47,111,99,.55);border-radius:50%;box-shadow:0 2px 6px rgba(31,37,34,.16);color:var(--transition-marker-ink);display:flex;font-size:.72rem;font-weight:900;height:21px;justify-content:center;left:calc(var(--transition-x,0) * var(--cell-size));line-height:1;pointer-events:none;position:absolute;top:calc(var(--transition-y,0) * var(--cell-size));transform:translate(-50%,-50%);width:21px;z-index:4;}.floor-plan-transition-marker svg{display:block;height:21px;overflow:visible;width:21px;}.floor-plan-transition-marker.is-vertical svg{transform:rotate(90deg);}.floor-plan-transition-marker .marker-line,.floor-plan-transition-marker .marker-arc,.floor-plan-transition-marker .marker-window,.floor-plan-transition-marker .marker-blocked{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.7;}.floor-plan-transition-marker .marker-arc{stroke-width:1.35;}.floor-plan-transition-marker .marker-window{stroke:var(--transition-marker-window);}.floor-plan-transition-marker .marker-dotted{opacity:.72;stroke-dasharray:1.4 2;}.floor-plan-transition-marker .marker-blocked{stroke:var(--transition-marker-blocked);stroke-width:1.8;}.floor-plan-transition-marker .marker-strong{stroke-width:2;}.floor-plan-transition-marker .marker-track{opacity:.72;}.floor-plan-transition-marker--window{background:rgba(239,249,255,.98);border-color:rgba(36,111,159,.48);}.floor-plan-transition-marker--sliding-door{background:rgba(248,252,249,.98);border-color:rgba(47,111,99,.58);}.floor-plan-transition-marker--french-door{background:rgba(255,252,246,.98);border-color:rgba(119,86,45,.5);}.floor-plan-transition-marker--secret-door{background:rgba(255,250,242,.88);border-style:dashed;}.floor-plan-transition-marker--ladder{background:rgba(246,248,245,.98);border-color:rgba(77,91,67,.55);}.floor-plan-transition-marker--blocked-door{background:rgba(255,244,241,.98);border-color:rgba(155,52,43,.52);}.floor-plan-transition-marker--exterior-door{border-width:2px;}.floor-plan-transition-marker.is-shared-edge{background:rgba(255,255,255,.98);border-color:rgba(47,111,99,.72);}.floor-plan-transition-marker--window.is-shared-edge{background:rgba(239,249,255,.98);border-color:rgba(36,111,159,.58);}.floor-plan-transition-marker--blocked-door.is-shared-edge{background:rgba(255,244,241,.98);border-color:rgba(155,52,43,.6);}.visual-card-heading{align-items:flex-start;display:flex;gap:12px;}.visual-card-heading>div{min-width:0;}.visual-avatar{align-items:center;aspect-ratio:1;background:linear-gradient(135deg,rgba(47,111,99,.16),rgba(212,154,98,.16));border:1px solid rgba(47,111,99,.22);border-radius:999px;color:var(--plotline-accent-dark,#22534a);display:inline-flex;flex:0 0 auto;font-weight:900;justify-content:center;letter-spacing:.02em;overflow:hidden;text-transform:uppercase;}.visual-avatar img{height:100%;object-fit:cover;width:100%;}.visual-avatar--sm{font-size:.72rem;width:32px;}.visual-avatar--md{font-size:.9rem;width:48px;}.visual-avatar--lg{font-size:1.3rem;width:96px;}.visual-avatar--xl{font-size:1.6rem;width:128px;}.visual-image-editor{align-items:center;background:rgba(47,111,99,.05);border:1px solid rgba(47,111,99,.14);border-radius:8px;display:flex;gap:18px;padding:14px;}.visual-image-editor__controls{flex:1 1 auto;min-width:220px;}.floor-plan-block--room{background:#d9eee7;}.floor-plan-block--corridor{background:#e7e2f4;}.floor-plan-block--openspace{background:#e5efd4;}.floor-plan-block--exterior{background:#d9ecf3;}.floor-plan-block--other{background:#ece9e1;}.floor-plan-resize-handle{border-bottom:10px solid rgba(18,51,44,.45);border-left:10px solid transparent;bottom:4px;height:0;position:absolute;right:4px;width:0;}.floor-plan-side-panel{align-self:start;position:sticky;top:82px;}.floor-plan-side-panel h2{font-size:1.05rem;margin-bottom:8px;}.floor-plan-side-panel h3{font-size:.92rem;margin:0 0 8px;}.floor-plan-toolbox{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:8px;display:grid;grid-template-rows:auto minmax(0,1fr);max-height:calc(100vh - 250px);min-height:min(58vh,520px);overflow:hidden;}.floor-plan-toolbox-tabs{border-bottom:1px solid var(--border-color,#d8ded9);display:flex;flex-wrap:wrap;gap:0;}.floor-plan-toolbox-tab{background:transparent;border:0;border-right:1px solid var(--border-color,#d8ded9);border-bottom:1px solid var(--border-color,#d8ded9);color:inherit;flex:1 1 118px;font-size:.82rem;font-weight:800;min-width:112px;padding:10px 8px;}.floor-plan-toolbox-tab:last-child,.floor-plan-toolbox-tab.active:last-child{border-right:0;}.floor-plan-toolbox-tab.active{background:rgba(47,111,99,.1);border-bottom-color:var(--plotline-accent,#2f6f63);color:var(--plotline-accent-dark,#22534a);}.floor-plan-toolbox-body{min-height:0;overflow:auto;}.floor-plan-tool-card{background:var(--panel-bg,#fff);border:1px solid var(--border-color,#d8ded9);border-radius:8px;padding:14px;}.floor-plan-toolbox .floor-plan-tool-card{background:transparent;border:0;border-radius:0;}.floor-plan-tool-card[hidden]{display:none;}.floor-plan-tool-card p{margin-bottom:10px;}.floor-plan-tool-subsection{border-top:1px solid var(--border-color,#d8ded9);margin-top:12px;padding-top:12px;}.floor-plan-tool-subsection:first-of-type{border-top:0;margin-top:0;padding-top:0;}.floor-plan-background-file{border:1px solid rgba(47,111,99,.16);border-radius:6px;font-size:.86rem;padding:8px 10px;}.floor-plan-background-range{align-items:center;display:grid;gap:10px;grid-template-columns:minmax(0,1fr) 44px;}.floor-plan-background-range span{color:var(--muted-text,#5d6f65);font-size:.8rem;font-variant-numeric:tabular-nums;text-align:right;}.floor-plan-transition-list{display:grid;gap:8px;}.floor-plan-transition-item{border:1px solid rgba(47,111,99,.14);border-radius:6px;display:grid;gap:8px;padding:8px;}.floor-plan-transition-item strong,.floor-plan-transition-item span{display:block;font-size:.84rem;}.floor-plan-transition-item span{color:var(--muted-text,#5d6f65);}.scene-occupancy-form{display:grid;gap:0.5rem;}.scene-occupancy-status{justify-self:start;border-radius:999px;padding:0.2rem 0.55rem;color:var(--plotline-muted);background:var(--plotline-soft);font-size:0.78rem;font-weight:700;}.scene-occupancy-status[data-save-state="saving"]{color:#7a4d08;background:#fff4d6;}.scene-occupancy-status[data-save-state="failed"]{color:#842029;background:#f8d7da;}.scene-occupancy-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem;}.scene-occupancy-grid h4{margin:0 0 0.5rem;font-size:0.95rem;}.scene-occupancy-row{display:grid;grid-template-columns:minmax(8rem,0.45fr) minmax(0,0.55fr);align-items:center;gap:0.5rem;margin-bottom:0.45rem;}.floor-plan-editor--occupancy .floor-plan-block{cursor:default;}.floor-plan-editor--occupancy .floor-plan-resize-handle{display:none;}.floor-plan-occupancy-tray{position:absolute;z-index:14;grid-column:calc(var(--x)+1) / span var(--w);grid-row:calc(var(--y)+1) / span var(--h);align-self:end;justify-self:center;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:0.18rem;margin:0 0 0.25rem;pointer-events:auto;}.floor-plan-occupancy-tray[hidden]{display:none;}.floor-plan-occupancy-token{display:grid;place-items:center;width:1.8rem;height:1.8rem;overflow:hidden;border:2px solid #fff;border-radius:999px;color:#fff;background:var(--plotline-accent);box-shadow:0 4px 12px rgba(30,37,43,0.18);font-size:0.68rem;font-weight:800;}.floor-plan-occupancy-token img{width:100%;height:100%;object-fit:cover;}.floor-plan-occupancy-token--asset{width:1.45rem;height:1.45rem;background:#805c15;font-size:0.58rem;}.floor-plan-occupancy-more{border-radius:999px;padding:0.15rem 0.36rem;color:var(--plotline-ink);background:rgba(255,255,255,0.92);box-shadow:0 4px 12px rgba(30,37,43,0.12);font-size:0.72rem;font-weight:800;}.floor-plan-transition-accordion .accordion-item{background:transparent;border-color:var(--border-color,#d8ded9);}.floor-plan-transition-accordion .accordion-button{background:rgba(47,111,99,.06);color:inherit;font-size:.88rem;font-weight:800;padding:10px 12px;}.floor-plan-transition-accordion .accordion-button:not(.collapsed){background:rgba(47,111,99,.12);color:var(--plotline-accent-dark,#22534a);box-shadow:inset 0 -1px 0 var(--border-color,#d8ded9);}.floor-plan-transition-accordion .accordion-body{padding:12px;}.floor-plan-checkbox{align-items:center;display:inline-flex;gap:6px;font-weight:700;margin-bottom:4px;}.floor-plan-choice-row{display:grid;gap:4px;margin-bottom:10px;}.floor-plan-choice-row label{align-items:center;display:flex;gap:6px;font-size:.88rem;}.floor-plan-overlap-warning{background:rgba(180,85,68,.12);border:1px solid rgba(180,85,68,.35);border-radius:6px;color:#8f3f31;margin-bottom:10px;padding:8px 10px;}[data-bs-theme="dark"] .floor-plan-grid,.dark .floor-plan-grid{background:linear-gradient(to right,rgba(214,224,218,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(214,224,218,.12) 1px,transparent 1px),#15201d;background-size:var(--cell-size) var(--cell-size),var(--cell-size) var(--cell-size),auto;}[data-bs-theme="dark"] .floor-plan-editor-toolbar,.dark .floor-plan-editor-toolbar,[data-bs-theme="dark"] .floor-plan-toolbox,.dark .floor-plan-toolbox,[data-bs-theme="dark"] .floor-plan-tool-card,.dark .floor-plan-tool-card{background:var(--panel-bg,#1f2522);}[data-bs-theme="dark"] .floor-plan-toolbox .floor-plan-tool-card,.dark .floor-plan-toolbox .floor-plan-tool-card{background:transparent;}[data-bs-theme="dark"] .floor-plan-toolbox-tab.active,.dark .floor-plan-toolbox-tab.active{background:rgba(212,154,98,.16);color:var(--plotline-accent-dark,#f0c99d);}[data-bs-theme="dark"] .floor-plan-block,.dark .floor-plan-block{--floor-plan-wall-color:rgba(212,154,98,.6);color:#f1f6f3;}[data-bs-theme="dark"] .floor-plan-block.is-hidden-location,.dark .floor-plan-block.is-hidden-location{background-image:repeating-linear-gradient(135deg,rgba(244,234,220,.09) 0,rgba(244,234,220,.09) 3px,transparent 3px,transparent 9px);box-shadow:inset 0 0 0 1px rgba(244,234,220,.2);}[data-bs-theme="dark"] .floor-plan-secret-route,.dark .floor-plan-secret-route{border-top-color:rgba(244,204,160,.58);opacity:.76;}[data-bs-theme="dark"] .floor-plan-secret-route::after,.dark .floor-plan-secret-route::after{background:rgba(42,35,30,.95);border-color:rgba(244,204,160,.55);}[data-bs-theme="dark"] .floor-plan-coordinate-label,.dark .floor-plan-coordinate-label{color:rgba(244,234,220,.46);text-shadow:0 1px 0 rgba(0,0,0,.55);}[data-bs-theme="dark"] .floor-plan-reference-block,.dark .floor-plan-reference-block{background:rgba(131,199,242,.08);border-color:rgba(131,199,242,.32);color:rgba(244,234,220,.46);}[data-bs-theme="dark"] .floor-plan-reference-warning,.dark .floor-plan-reference-warning{background:rgba(84,57,25,.92);border-color:rgba(244,177,100,.32);color:#ffd9a5;}[data-bs-theme="dark"] .floor-plan-transition-marker,.dark .floor-plan-transition-marker{--transition-marker-ink:#f4eadc;--transition-marker-window:#83c7f2;--transition-marker-blocked:#f08a78;background:rgba(42,35,30,.98);border-color:rgba(212,154,98,.6);}[data-bs-theme="dark"] .floor-plan-transition-marker.is-shared-edge,.dark .floor-plan-transition-marker.is-shared-edge{background:rgba(48,39,32,.98);border-color:rgba(212,154,98,.78);}[data-bs-theme="dark"] .floor-plan-transition-marker--window,.dark .floor-plan-transition-marker--window,[data-bs-theme="dark"] .floor-plan-transition-marker--window.is-shared-edge,.dark .floor-plan-transition-marker--window.is-shared-edge{background:rgba(24,45,58,.98);border-color:rgba(131,199,242,.66);}[data-bs-theme="dark"] .floor-plan-transition-marker--sliding-door,.dark .floor-plan-transition-marker--sliding-door,[data-bs-theme="dark"] .floor-plan-transition-marker--french-door,.dark .floor-plan-transition-marker--french-door,[data-bs-theme="dark"] .floor-plan-transition-marker--ladder,.dark .floor-plan-transition-marker--ladder{background:rgba(39,43,37,.98);border-color:rgba(212,154,98,.58);}[data-bs-theme="dark"] .floor-plan-transition-marker--blocked-door,.dark .floor-plan-transition-marker--blocked-door,[data-bs-theme="dark"] .floor-plan-transition-marker--blocked-door.is-shared-edge,.dark .floor-plan-transition-marker--blocked-door.is-shared-edge{background:rgba(58,33,28,.98);border-color:rgba(240,138,120,.66);}[data-bs-theme="dark"] .visual-avatar,.dark .visual-avatar{background:linear-gradient(135deg,rgba(131,199,242,.14),rgba(212,154,98,.18));border-color:rgba(244,234,220,.18);color:#f4eadc;}[data-bs-theme="dark"] .visual-image-editor,.dark .visual-image-editor{background:rgba(244,234,220,.04);border-color:rgba(244,234,220,.12);}[data-bs-theme="dark"] .floor-plan-transition-item,.dark .floor-plan-transition-item{border-color:rgba(212,154,98,.22);}[data-bs-theme="dark"] .scene-occupancy-status,.dark .scene-occupancy-status{color:#d9c8b8;background:rgba(212,154,98,.12);}[data-bs-theme="dark"] .floor-plan-occupancy-token,.dark .floor-plan-occupancy-token{border-color:#1f2630;box-shadow:0 4px 12px rgba(0,0,0,.28);}[data-bs-theme="dark"] .floor-plan-occupancy-more,.dark .floor-plan-occupancy-more{color:#f1e7dd;background:rgba(31,38,48,.92);}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-item,.dark .floor-plan-transition-accordion .accordion-item{border-color:rgba(212,154,98,.22);}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-button,.dark .floor-plan-transition-accordion .accordion-button{background:rgba(212,154,98,.08);color:#f4eadc;}[data-bs-theme="dark"] .floor-plan-transition-accordion .accordion-button:not(.collapsed),.dark .floor-plan-transition-accordion .accordion-button:not(.collapsed){background:rgba(212,154,98,.16);color:var(--plotline-accent-dark,#f0c99d);box-shadow:inset 0 -1px 0 rgba(212,154,98,.22);}[data-bs-theme="dark"] .floor-plan-block--room,.dark .floor-plan-block--room{background:#29584f;}[data-bs-theme="dark"] .floor-plan-block--corridor,.dark .floor-plan-block--corridor{background:#514876;}[data-bs-theme="dark"] .floor-plan-block--openspace,.dark .floor-plan-block--openspace{background:#4f6133;}[data-bs-theme="dark"] .floor-plan-block--exterior,.dark .floor-plan-block--exterior{background:#315d6f;}[data-bs-theme="dark"] .floor-plan-block--other,.dark .floor-plan-block--other{background:#5b564c;}@media (max-width:1100px){.floor-plan-layout,.floor-plan-editor-toolbar{grid-template-columns:1fr;}.floor-plan-grid-wrap{max-height:62vh;}.floor-plan-side-panel{position:static;}.floor-plan-toolbox{max-height:none;}} \ No newline at end of file diff --git a/PlotLine/wwwroot/js/site.js b/PlotLine/wwwroot/js/site.js index b32a0bf..eb4cfbf 100644 --- a/PlotLine/wwwroot/js/site.js +++ b/PlotLine/wwwroot/js/site.js @@ -91,6 +91,109 @@ }); })(); +(() => { + const roots = document.querySelectorAll(".scene-inspector-root"); + if (!roots.length) { + return; + } + + const setStatus = (form, text, state) => { + const status = form.querySelector("[data-scene-occupancy-status]"); + if (!status) { + return; + } + + status.textContent = text; + status.dataset.saveState = state || ""; + }; + + const replaceOccupancyForm = (form, html) => { + const wrapper = document.createElement("div"); + wrapper.innerHTML = html; + const nextForm = wrapper.querySelector("[data-scene-occupancy-form]"); + if (nextForm) { + form.replaceWith(nextForm); + const sceneForm = nextForm.closest(".scene-inspector-root")?.querySelector(".scene-inspector-form"); + const floorPlanInput = sceneForm?.querySelector("[name='FloorPlanID']"); + const initialFloorInput = sceneForm?.querySelector("[name='InitialFloorPlanFloorID']"); + const nextFloorPlan = nextForm.querySelector("[name='FloorPlanID']"); + const nextInitialFloor = nextForm.querySelector("[name='InitialFloorPlanFloorID']"); + if (floorPlanInput && nextFloorPlan) { + floorPlanInput.value = nextFloorPlan.value; + } + if (initialFloorInput && nextInitialFloor) { + initialFloorInput.value = nextInitialFloor.value; + } + } + }; + + roots.forEach((root) => { + root.addEventListener("change", async (event) => { + const planSelect = event.target.closest?.("[data-occupancy-plan-select]"); + if (!planSelect) { + return; + } + + const form = planSelect.closest("[data-scene-occupancy-form]"); + const sceneId = form?.querySelector("[name='SceneID']")?.value; + const editorUrl = form?.dataset.editorUrl; + if (!form || !sceneId || !editorUrl) { + return; + } + + setStatus(form, "Loading...", "saving"); + const url = new URL(editorUrl, window.location.origin); + url.searchParams.set("sceneId", sceneId); + if (planSelect.value) { + url.searchParams.set("floorPlanId", planSelect.value); + } + + try { + const response = await fetch(url, { headers: { "X-Requested-With": "XMLHttpRequest" } }); + if (!response.ok) { + throw new Error("The occupancy editor could not be refreshed."); + } + + replaceOccupancyForm(form, await response.text()); + } catch (error) { + setStatus(form, error.message || "Load failed", "failed"); + } + }); + + root.addEventListener("submit", async (event) => { + const form = event.target.closest?.("[data-scene-occupancy-form]"); + if (!form) { + return; + } + + event.preventDefault(); + setStatus(form, "Saving...", "saving"); + + try { + const response = await fetch(form.action, { + method: "POST", + body: new FormData(form), + headers: { "X-Requested-With": "XMLHttpRequest" } + }); + + if (!response.ok) { + let message = "Save failed"; + const contentType = response.headers.get("content-type") || ""; + if (contentType.includes("application/json")) { + const payload = await response.json(); + message = payload.message || message; + } + throw new Error(message); + } + + replaceOccupancyForm(form, await response.text()); + } catch (error) { + setStatus(form, error.message || "Save failed", "failed"); + } + }); + }); +})(); + (() => { const modalElement = document.getElementById("plotlineConfirmModal"); const modal = modalElement && window.bootstrap ? new bootstrap.Modal(modalElement) : null; diff --git a/PlotLine/wwwroot/js/site.min.js b/PlotLine/wwwroot/js/site.min.js index 08086aa..eeae91c 100644 --- a/PlotLine/wwwroot/js/site.min.js +++ b/PlotLine/wwwroot/js/site.min.js @@ -1 +1 @@ -(()=>{const e="plotline.theme",t=document.querySelectorAll("[data-theme-choice]"),n=n=>{const a="dark"===n?"dark":"light";document.documentElement.dataset.theme=a,document.documentElement.dataset.bsTheme=a,(t=>{try{localStorage.setItem(e,t)}catch{}})(a),t.forEach(e=>{const t=e.dataset.themeChoice===a;e.classList.toggle("active",t),e.setAttribute("aria-pressed",String(t))})};t.forEach(e=>{e.addEventListener("click",()=>n(e.dataset.themeChoice))}),n((()=>{try{return localStorage.getItem(e)}catch{return null}})()||"light")})(),(()=>{const e=document.querySelector("[data-trial-banner]");if(!e)return;const t=`plotline.trialBanner.dismissed.${e.dataset.trialBannerKey||"current"}`;try{if("true"===localStorage.getItem(t))return void(e.hidden=!0)}catch{}e.querySelector("[data-trial-banner-dismiss]")?.addEventListener("click",()=>{e.hidden=!0;try{localStorage.setItem(t,"true")}catch{}})})(),(()=>{const e=document.querySelectorAll(".scene-inspector-root");if(!e.length)return;e.forEach(e=>{e.addEventListener("submit",e=>{const t=e.target;if(!(t instanceof HTMLFormElement))return;let n=t.querySelector("input[name='ReturnUrl']");n||(n=document.createElement("input"),n.type="hidden",n.name="ReturnUrl",t.appendChild(n)),n.value=`${window.location.pathname}${window.location.search}${window.location.hash}`},!0)})})(),(()=>{const e=document.getElementById("plotlineConfirmModal"),t=e&&window.bootstrap?new bootstrap.Modal(e):null,n=e?.querySelector("#plotlineConfirmModalTitle"),a=e?.querySelector("#plotlineConfirmModalMessage"),r=e?.querySelector("[data-confirm-submit]"),o=e?.querySelector("[data-delete-confirm-field]"),s=e?.querySelector("[data-delete-confirm-input]");let i=null,l=null;e?.addEventListener("hidden.bs.modal",()=>{i=null,l=null,s&&(s.value=""),o?.classList.add("d-none"),r?.removeAttribute("disabled")}),s?.addEventListener("input",()=>{"true"===i?.dataset.requireDeleteText&&r&&(r.disabled="DELETE"!==s.value.trim())}),r?.addEventListener("click",()=>{if(i){if("true"===i.dataset.requireDeleteText){const e=i.querySelector("[data-delete-confirm-target], [name='confirmationText']");e&&(e.value=s?.value.trim()||"")}i.dataset.confirmed="true",t?.hide(),i.requestSubmit&&l?i.requestSubmit(l):i.requestSubmit?i.requestSubmit():i.submit()}}),document.addEventListener("submit",c=>{const d=c.target;if(!(d instanceof HTMLFormElement)||"true"===d.dataset.confirmed||"true"===d.dataset.confirmSkip||"true"===d.dataset.noDeleteConfirm)return;const p=d.dataset.confirmMessage,u=c.submitter instanceof HTMLElement?c.submitter:d.querySelector("button[type='submit']"),m=u?.textContent||"",h=d.getAttribute("action")||"",g=/restore/i.test(m)||/\/restore\b/i.test(h),f=/delete forever/i.test(m)||/\/deleteforever\b/i.test(h),v=!g&&!f&&(/archive/i.test(m)||/\/archive\b/i.test(h)),y=!f&&/(delete|remove)/i.test(m);if(!(p||v||g||y||f))return;const w=p||(v?"Archive this item?\n\nThis will hide it from active lists and timelines, but the data will be kept and can be restored later.":g?"Restore this item?\n\nThis will return it to active lists and timelines where applicable.":f?"Permanently delete this item?\n\nThis cannot be undone. Any linked planning data may also be removed or become unavailable. Only continue if you are certain.":"Remove this item?\n\nThis removes the link or supporting record. Major story items are archived instead of permanently deleted.");if(!(t&&e&&n&&a&&r))return;c.preventDefault();const L=(e=>{const t=e.split(/\n\s*\n/);return{title:t.shift()?.trim()||"Confirm action",body:t.join("\n\n").trim()}})(w);i=d,l=u,n.textContent=d.dataset.confirmTitle||L.title,a.textContent=d.dataset.confirmBody||L.body,r.textContent=d.dataset.confirmButtonText||m.trim()||"Confirm",r.className=`btn ${d.dataset.confirmButtonClass||(g?"btn-primary":"btn-danger")}`;const S="true"===d.dataset.requireDeleteText||f;o?.classList.toggle("d-none",!S),S&&r&&(r.disabled=!0,s?.focus()),t.show(),S&&window.setTimeout(()=>s?.focus(),200)})})(),(()=>{const e=document.querySelectorAll("[data-help-icon]");if(!e.length||!window.bootstrap)return;const t=new Map;let n=null;const a=e=>e.querySelector("[data-help-tooltip]")||e,r=e=>bootstrap.Tooltip.getInstance(a(e))?.hide(),o=(e=null)=>{n&&n!==e&&bootstrap.Popover.getInstance(n)?.hide()},s=()=>e.forEach(e=>r(e));e.forEach(e=>{const i=a(e),l=i.dataset.helpMicro||"Help article not found.",c=e.dataset.helpTitle||"Help unavailable",d=e.dataset.helpSummary||"Help content has not yet been written for this feature.";bootstrap.Tooltip.getOrCreateInstance(i,{title:l,trigger:"hover focus",placement:"top",container:"body"});const p=bootstrap.Popover.getOrCreateInstance(e,{title:c,trigger:"click",placement:"auto",container:"body",html:!0,customClass:"plotline-help-popover",content(){const t=document.createElement("div"),n=document.createElement("p");n.className="mb-2",n.textContent=d;const a=document.createElement("a");return a.href="#",a.textContent="More...",a.className="plotline-help-more",a.addEventListener("click",t=>{t.preventDefault(),o(),s(),e.dispatchEvent(new CustomEvent("plotline:help-more",{bubbles:!0,detail:{key:e.dataset.helpKey||""}}))}),t.append(n,a),t}});t.set(e,p),e.addEventListener("click",t=>{window.PlotLineHelpDrawer?.isActive?.()&&(t.preventDefault(),t.stopPropagation(),o(),r(e),window.PlotLineHelpPopovers?.hideAll(),window.PlotLineHelpDrawer.open(e.dataset.helpKey||""))}),e.addEventListener("show.bs.popover",t=>{window.PlotLineHelpDrawer?.isActive?.()?t.preventDefault():(o(e),r(e))}),e.addEventListener("shown.bs.popover",()=>{n=e,r(e)}),e.addEventListener("hidden.bs.popover",()=>{n===e&&(n=null)})}),document.addEventListener("click",e=>{const t=e.target instanceof Element?e.target:null;if(!t||!n)return;if(t.closest("[data-help-icon]"))return;const a=document.querySelector(`#${n.getAttribute("aria-describedby")}`);a?.contains(t)||o()}),document.addEventListener("keydown",e=>{"Escape"===e.key&&o()}),window.PlotLineHelpPopovers={hideAll(){t.forEach(e=>e.hide()),s(),n=null}}})(),(()=>{const e=document.querySelector("[data-help-layout]"),t=document.querySelector("[data-help-drawer]"),n=document.querySelector("[data-help-content]"),a=document.querySelector("[data-help-splitter]"),r=document.querySelector("[data-help-close]"),o=document.querySelector("[data-help-collapse]"),s=document.querySelector("[data-help-expand]"),i=document.querySelector("[data-help-pin]"),l=document.querySelector("[data-help-drawer-heading]");if(!e||!t||!n)return;const c="plotline.helpDrawer.width",d="plotline.helpDrawer.pinned",p="plotline.helpDrawer.key",u="plotline.helpDrawer.collapsed",m=e=>{try{return"true"===localStorage.getItem(e)}catch{return!1}},h=(e,t)=>{try{localStorage.setItem(e,t)}catch{}},g=t=>{const n=`${((e,t,n)=>Math.min(n,Math.max(t,e)))(Number.parseFloat(t)||25,20,50)}%`;e.style.setProperty("--help-drawer-width",n),h(c,n)},f=e=>{h(d,String(e)),i?.setAttribute("aria-pressed",String(e)),i&&(i.textContent=e?"Unpin":"Pin")},v=t=>{e.classList.toggle("help-collapsed",t),h(u,String(t)),o&&(o.textContent=t?"Expand":"Collapse")},y=async(t,a={})=>{const r=t||"";e.classList.add("help-open"),a.keepCollapsed||v(!1),h(p,r),l&&(l.textContent=r||"Help"),n.innerHTML='

Loading help...

';try{const e=await fetch(`/HelpDrawer/Article?key=${encodeURIComponent(r)}`,{headers:{"X-Requested-With":"XMLHttpRequest"}});n.innerHTML=e.ok?await e.text():'

Help for this feature has not yet been written.

';const t=n.querySelector(".help-drawer-article h2")?.textContent?.trim();l&&t&&(l.textContent=t)}catch{n.innerHTML='

Help for this feature has not yet been written.

'}};window.PlotLineHelpDrawer={isActive:()=>e.classList.contains("help-open"),open:e=>y(e)},g(localStorage.getItem(c)||"25%"),f(m(d)),v(m(u)),document.addEventListener("plotline:help-more",e=>{const t=e.detail?.key||e.target?.dataset?.helpKey||"";window.PlotLineHelpPopovers?.hideAll(),y(t)}),document.addEventListener("click",e=>{const t=e.target instanceof Element?e.target.closest("[data-help-open]"):null;t&&(e.preventDefault(),window.PlotLineHelpPopovers?.hideAll(),y(t.dataset.helpOpen||""))}),r?.addEventListener("click",()=>{e.classList.remove("help-open","help-collapsed"),f(!1)}),o?.addEventListener("click",()=>v(!e.classList.contains("help-collapsed"))),s?.addEventListener("click",()=>v(!1)),s?.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),v(!1))}),i?.addEventListener("click",()=>f(!m(d))),a?.addEventListener("pointerdown",t=>{if(!e.classList.contains("help-open")||e.classList.contains("help-collapsed"))return;t.preventDefault(),document.body.classList.add("help-resizing"),a.setPointerCapture?.(t.pointerId);const n=t=>{const n=e.getBoundingClientRect(),a=(n.right-t.clientX)/n.width*100;g(a)},r=()=>{document.body.classList.remove("help-resizing"),document.removeEventListener("pointermove",n),document.removeEventListener("pointerup",r)};document.addEventListener("pointermove",n),document.addEventListener("pointerup",r)});const w=(()=>{try{return localStorage.getItem(p)||""}catch{return""}})();m(d)&&w&&y(w,{keepCollapsed:!0})})(),(()=>{const e=document.querySelectorAll(".scene-inspector-root");if(!e.length)return;e.forEach(e=>{const t=`plotline.inspector.${e.dataset.sceneId||e.querySelector(".scene-inspector-form [name='SceneID']")?.value||"new"}.`,n=new Set(["overview","timing","characters"]),a=[...e.querySelectorAll(".inspector-section")],r=e.querySelector(".scene-inspector-form"),o=e.querySelector("[data-scene-time-editor]");if(r&&o&&"true"!==o.dataset.enhanced){o.dataset.enhanced="true";const e=r.querySelector("[name='TimeModeID']"),t=o.dataset.exactDatetimeModeId||"",n=o.dataset.exactDateModeId||"",a=[...o.querySelectorAll("[data-time-part-field]")],s={StartDateTime:o.querySelector("[data-date-part-for='StartDateTime']"),EndDateTime:o.querySelector("[data-date-part-for='EndDateTime']")},i={StartDateTime:o.querySelector("[data-time-part-for='StartDateTime']"),EndDateTime:o.querySelector("[data-time-part-for='EndDateTime']")},l={StartDateTime:r.querySelector("input[type='hidden'][name='StartDateTime']"),EndDateTime:r.querySelector("input[type='hidden'][name='EndDateTime']")},c=()=>e?.value===t,d=()=>e?.value===n,p=()=>{const e=c();a.forEach(t=>{t.hidden=!e,t.classList.toggle("d-none",!e)})},u=e=>{const t=l[e],n=s[e]?.value||"",a=i[e]?.value||"";if(!t)return;if(!n)return void(t.value="");if(c())return void(t.value=`${n}T${a||"00:00"}`);if(d())return void(t.value=n);const r=t.value.match(/^\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2})/)?.[1];t.value=r?`${n}T${r}`:n},m=()=>{u("StartDateTime"),u("EndDateTime")};e?.addEventListener("change",p),r.addEventListener("submit",m),p()}a.forEach(e=>{if("true"===e.dataset.enhanced)return;const a=e.querySelector("h3, h2"),r=e.dataset.sectionTitle||a?.textContent?.trim()||"Overview",o=r.toLowerCase().replace(/&/g,"and").replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");const s=e.dataset.sectionId||`inspector-${o}`,i=s.replace(/^inspector-/,"");e.id=s,e.dataset.searchText=`${r} ${e.textContent}`.toLowerCase(),e.dataset.enhanced="true";const l=document.createElement("div");for(l.className="inspector-accordion-body";e.firstChild;)l.appendChild(e.firstChild);const c=document.createElement("button");c.type="button",c.className="inspector-accordion-toggle",c.setAttribute("aria-expanded","false"),e.append(c,l);const d=l.querySelectorAll(".asset-event-item, .thread-event-item, .warning-mini-card, .dependency-card, .metric-slider").length;c.innerHTML=`${r}${d||""}`;const p=localStorage.getItem(`${t}${i}`),u=null===p?n.has(i):"open"===p;e.classList.toggle("is-open",u),c.setAttribute("aria-expanded",String(u)),c.addEventListener("click",()=>{const n=!e.classList.contains("is-open");e.classList.toggle("is-open",n),c.setAttribute("aria-expanded",String(n)),localStorage.setItem(`${t}${i}`,n?"open":"closed")})}),e.querySelectorAll(".inspector-nav-links a").forEach(t=>{t.addEventListener("click",n=>{const a=e.querySelector(t.getAttribute("href"));a&&(n.preventDefault(),a.classList.add("is-open"),a.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"),a.scrollIntoView({behavior:"smooth",block:"start"}))})});const s=e.querySelector("[data-inspector-search]");if(s?.addEventListener("input",()=>{const e=s.value.trim().toLowerCase();a.forEach(t=>{const n=!e||t.dataset.searchText.includes(e);t.classList.toggle("is-filtered-out",!n),n&&e&&(t.classList.add("is-open"),t.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"))})}),"IntersectionObserver"in window){const t=[...e.querySelectorAll(".inspector-nav-links a")],n=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting&&t.forEach(t=>{t.classList.toggle("active",t.getAttribute("href")===`#${e.target.id}`)})})},{root:e.closest(".scene-inspector-panel")||null,rootMargin:"-10% 0px -70% 0px"});a.forEach(e=>n.observe(e))}})})(),(()=>{const e=document.querySelectorAll("[data-metric-shape-chart]");if(!e.length)return;const t=["#2f6f63","#b35f3b","#6750a4","#c58b2b","#7d3f52","#33759b","#9c4d8f","#a33d3d","#6f8f3d","#d08a2f","#444b57"],n=new Set(["Overall Intensity","Tension","Emotional Weight","Action"]),a=[],r=()=>{window.requestAnimationFrame(()=>{a.forEach(e=>e.resize())})};window.PlotLineMetricCharts={resizeAll:r},window.addEventListener("plotline:timeline-layout-changed",r);const o={id:"plotlineChapterGuides",afterDraw(e){const t=e.config.options.plugins.plotlineScenes||[],{ctx:n,chartArea:a,scales:r}=e;if(!t.length||!r.x)return;n.save(),n.strokeStyle="rgba(47, 111, 99, 0.16)",n.fillStyle="rgba(82, 75, 65, 0.58)",n.lineWidth=1,n.font="700 10px system-ui, -apple-system, Segoe UI, sans-serif";const o=[];t.forEach((e,n)=>{n&&e.chapterLabel===t[n-1].chapterLabel||o.push({scene:e,index:n})});const s=o.filter(e=>!e.scene.isPlaceholder),i=s.length>40?5:s.length>24?4:s.length>14?2:1;s.forEach((e,t)=>{const{scene:o,index:l}=e,c=r.x.getPixelForValue(l+.5);n.beginPath(),n.moveTo(c,a.top),n.lineTo(c,a.bottom),n.stroke();const d=Number.parseInt(String(o.chapterLabel).replace(/[^0-9]/g,""),10);(0===t||t===s.length-1||1===i||Number.isFinite(d)&&d%i===0)&&n.fillText(o.chapterLabel,Math.min(c+4,a.right-70),a.bottom+22)}),n.restore()}};window.Chart&&Chart.register(o),e.forEach(e=>{const r=e.querySelector("script[type='application/json']"),o=e.querySelector("canvas"),s=e.querySelector("[data-metric-toggles]"),i=e.querySelector("[data-chart-fallback]"),l=e.querySelector("[data-timeline-metric-edit-toolbar]"),c=e.querySelector("[data-edit-metric-status]"),d=e.hasAttribute("data-timeline-metric-editor")&&l&&c;if(!r||!o)return;let p;try{p=JSON.parse(r.textContent||"{}")}catch{return void i?.classList.remove("d-none")}if(!window.Chart||!p.scenes?.length||!p.metrics?.length)return void i?.classList.remove("d-none");const u=new Set(p.defaultMetrics?.length?p.defaultMetrics:n),m=p.scenes.length,h=m>80?10:m>40?5:m>24?4:m>14?2:1,g=p.metrics.map((e,n)=>{const a=new Map(e.points.map(e=>[e.sceneId,e.value])),r=t[n%t.length];return{label:e.metricName,metricTypeId:e.metricTypeId,minValue:Number.isFinite(e.minValue)?e.minValue:1,maxValue:Number.isFinite(e.maxValue)?e.maxValue:10,data:p.scenes.map((e,t)=>{const n=a.get(e.sceneId);return null==n?{x:t+.5,y:null,sceneId:e.sceneId}:{x:t+.5,y:n,sceneId:e.sceneId}}),borderColor:r,backgroundColor:r,pointBackgroundColor:r,pointBorderColor:"#fff",pointBorderWidth:1.5,pointRadius:3,pointHoverRadius:5,borderWidth:2,tension:.35,spanGaps:!0,hidden:!u.has(e.metricName)}});let f=null,v=!1;const y=e=>{c&&(c.textContent=e)},w=()=>g.map((e,t)=>t).filter(e=>b?.isDatasetVisible(e)),L=()=>{const e=w();return 1===e.length?e[0]:-1},S=()=>{if(!d)return;const e=L();g.forEach((t,n)=>{t.pointRadius=n===e?5:3,t.pointHoverRadius=n===e?7:5,t.borderWidth=n===e?3:2});const t=w(),n=e>=0;o.classList.toggle("metric-curve-editing",n),c.classList.toggle("d-none",0===t.length),0===t.length?y(""):y(n?"Drag points up or down to edit this metric.":"Show only one metric line to edit its curve."),b?.update()};s.innerHTML="",g.forEach((e,t)=>{const n=`metric-toggle-${Math.random().toString(36).slice(2)}-${t}`,a=document.createElement("label");a.className="metric-toggle-pill",a.style.setProperty("--metric-colour",e.borderColor),a.innerHTML=`${e.label}`,s.appendChild(a),a.querySelector("input").addEventListener("change",e=>{b.setDatasetVisibility(t,e.target.checked),S(),b.update()})});const b=new Chart(o,{type:"line",data:{datasets:g},options:{responsive:!0,maintainAspectRatio:!1,interaction:{mode:"nearest",intersect:!1},scales:{y:{min:1,max:10,ticks:{stepSize:1},grid:{color:"rgba(82, 75, 65, 0.10)"}},x:{type:"linear",min:0,max:m,bounds:"ticks",ticks:{maxRotation:0,autoSkip:!1,maxTicksLimit:16,callback(e){const t=Math.floor(Number(e));if(t<0||t>=m)return"";const n=p.scenes[t];return 0!==t&&t!==m-1&&t%h!==0||n?.isPlaceholder?"":n?.axisLabel||""}},afterBuildTicks(e){e.ticks=p.scenes.map((e,t)=>({value:t+.5}))},grid:{display:!1}}},plugins:{legend:{display:!1},plotlineScenes:p.scenes,tooltip:{callbacks:{title(e){const t=Math.floor(e[0].parsed.x),n=p.scenes[t];return n.isPlaceholder?n.sceneTitle||"No scene":`${n.chapterLabel}, Scene ${n.sceneNumber}: ${n.sceneTitle}`},label:e=>`${e.dataset.label}: ${e.formattedValue}`,afterBody(e){const t=Math.floor(e[0].parsed.x),n=p.scenes[t],a=[];return n.characterPresence?a.push(n.characterPresence):void 0!==n.characterAppears&&a.push(n.characterAppears?"Character appears":"Character does not appear"),n.bookTitle&&a.push(n.bookTitle),a}}}}}});d&&(S(),o.addEventListener("pointerdown",e=>{f=(e=>{if(!d)return null;const t=L();if(t<0)return null;const n=b.getElementsAtEventForMode(e,"nearest",{intersect:!0},!0).find(e=>e.datasetIndex===t);if(!n)return null;const a=b.data.datasets[n.datasetIndex],r=a?.data?.[n.index];return r?.sceneId&&null!=r.y?{datasetIndex:n.datasetIndex,pointIndex:n.index,previousValue:r.y}:null})(e),f&&(e.preventDefault(),o.setPointerCapture?.(e.pointerId),v=!0)}),o.addEventListener("pointermove",e=>{if(!f)return;const t=b.data.datasets[f.datasetIndex],n=t?.data?.[f.pointIndex];t&&n&&(n.y=((e,t)=>{const n=b.scales.y.getValueForPixel(e.offsetY),a=Math.round(n);return Math.max(t.minValue,Math.min(t.maxValue,a))})(e,t),b.update("none"))}),o.addEventListener("pointerup",async t=>{if(!f)return;const n=f;f=null,o.releasePointerCapture?.(t.pointerId),await(async t=>{const n=b.data.datasets[t.datasetIndex],a=n?.data?.[t.pointIndex];if(!n||!a?.sceneId)return;const r=l?.querySelector("input[name='__RequestVerificationToken']")?.value||"";y("Saving...");try{const t=await fetch(e.dataset.updateUrl||"/SceneMetrics/UpdateSceneMetricValue",{method:"POST",headers:{"Content-Type":"application/json",RequestVerificationToken:r},body:JSON.stringify({sceneId:Number(a.sceneId),metricId:Number(n.metricTypeId),value:Number(a.y)})}),o=await t.json().catch(()=>({}));if(!t.ok||!o.success)throw new Error(o.message||"Save failed");a.y=o.value,y("Saved"),b.update()}catch{a.y=t.previousValue,y("Save failed"),b.update()}})(n),window.setTimeout(()=>{v=!1},0)}),o.addEventListener("pointercancel",e=>{if(!f)return;const t=b.data.datasets[f.datasetIndex],n=t?.data?.[f.pointIndex];n&&(n.y=f.previousValue),f=null,o.releasePointerCapture?.(e.pointerId),v=!1,b.update()})),o.addEventListener("click",e=>{if(v)return void e.preventDefault();const t=b.getElementsAtEventForMode(e,"nearest",{intersect:!0},!0);if(!t.length)return;const n=b.data.datasets[t[0].datasetIndex]?.data?.[t[0].index],a=n?Math.floor(n.x):t[0].index,r=p.scenes[a];r?.timelineUrl&&(window.PlotLineTimelineScroll?.save(),window.location.href=r.timelineUrl)}),a.push(b);const E=window.ResizeObserver?new ResizeObserver(()=>b.resize()):null;E&&(E.observe(e),E.observe(e.querySelector(".metric-chart-frame")||e))})})(),(()=>{const e=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-timeline-controls]");if(!e||!t)return;const n="plotline.timeline.visibility",a={"scene-cards":!0,"plot-lines":!0,assets:!0,characters:!0,locations:!0,warnings:!0,metrics:!0},r=t=>{Object.entries(t).forEach(([t,n])=>{e.classList.toggle(`hide-${t}`,!n),document.querySelectorAll(`[data-timeline-section='${t}']`).forEach(e=>{e.classList.toggle("timeline-section-hidden",!n)})}),document.querySelectorAll("[data-location-marker]").forEach(e=>{e.classList.toggle("timeline-section-hidden",!t.locations)}),document.querySelectorAll("[data-warning-marker]").forEach(e=>{e.classList.toggle("timeline-section-hidden",!t.warnings)}),document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(t))},o=(()=>{try{return{...a,...JSON.parse(localStorage.getItem(n)||"{}")}}catch{return{...a}}})();t.querySelectorAll("[data-timeline-toggle]").forEach(e=>{const t=e.dataset.timelineToggle;e.checked=o[t]??!0,e.addEventListener("change",()=>{o[t]=e.checked,localStorage.setItem(n,JSON.stringify(o)),r(o)})}),t.querySelector("[data-timeline-preset-form]")?.addEventListener("submit",()=>{document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(o))}),r(o)})(),(()=>{const e=document.querySelector("[data-timeline-root]");if(!e)return;const t=e.querySelector(".timeline-workspace")||e,n=document.querySelector("[data-timeline-density]"),a=document.querySelector("[data-timeline-zoom]"),r=document.querySelector("[data-timeline-search]"),o=e.querySelector("[data-timeline-minimap]"),s=document.querySelectorAll("[data-timeline-jump], [data-timeline-warning-jump], [data-timeline-entity-jump]"),i=[...e.querySelectorAll(".timeline-scene-card[data-scene-id]")],l="plotline.timeline.collapsed",c="plotline.timeline.density",d="plotline.timeline.zoom",p="plotline.timeline.pending-scroll",u="plotdirector.timelineNavigationDiscovered",m="plotline.timeline.inspectorWidth",h=[".timeline-shell",".plot-lane-board",".asset-lane-board",".character-lane-board",".metric-graph-stack","[data-timeline-minimap]"].join(","),g=["compact","comfortable","expanded"],f=["book","chapter","scene-detail"],v=e.querySelector("[data-inspector-drawer]"),y=e.querySelector("[data-inspector-resizer]"),w=e.querySelector("[data-inspector-close]"),L=null!==localStorage.getItem(l),S=(e=>{try{return new Set(JSON.parse(localStorage.getItem(e)||"[]"))}catch{return new Set}})(l),b=()=>[...e.querySelectorAll(h)],E=t=>{if(!v)return;const{minimum:n,maximum:a,defaultWidth:r}=(()=>{const t=e.getBoundingClientRect().width||window.innerWidth,n=Math.min(420,Math.max(320,t-360)),a=Math.max(n,Math.min(.65*t,t-420));return{minimum:n,maximum:a,defaultWidth:Math.max(n,Math.min(a,.4*t))}})(),o=Math.max(n,Math.min(a,Number(t)||r));e.style.setProperty("--timeline-inspector-width",`${Math.round(o)}px`)};v&&(E(localStorage.getItem(m)),window.addEventListener("resize",()=>E(localStorage.getItem(m)))),(()=>{const r=e.querySelector("[data-timeline-navigation-card]");if(!r)return;const o=r.querySelector("[data-timeline-navigation-dismiss]"),s=r.querySelector("[data-timeline-navigation-demo]"),i=()=>e.querySelector(".timeline-shell"),l=e=>Boolean(e&&e.scrollWidth>e.clientWidth+8),c=e=>Math.max(0,e.scrollWidth-e.clientWidth),d=()=>[t,...b()].filter((e,t,n)=>e&&n.indexOf(e)===t);let p=!1,m=!1,h=!1,g=null;const f=new WeakMap,v=e=>f.set(e,e.scrollLeft),y=(e=!1)=>{if(window.clearTimeout(g),!e||window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches||r.hidden)return r.classList.remove("is-dismissing"),void(r.hidden=!0);r.classList.add("is-dismissing"),g=window.setTimeout(()=>{r.hidden=!0,r.classList.remove("is-dismissing")},1300)},w=e=>{const t=l(e),n=c(e);e.classList.toggle("timeline-horizontal-overflow",t),e.classList.toggle("has-scroll-left",t&&e.scrollLeft>8),e.classList.toggle("has-scroll-right",t&&e.scrollLeft{l(i())&&!(()=>{try{return"true"===localStorage.getItem(u)}catch{return!1}})()&&!p?(window.clearTimeout(g),r.hidden=!1,r.classList.remove("is-dismissing")):r.classList.contains("is-dismissing")||y(!1),d().forEach(w)},S=()=>{p=!0,y(!0);try{localStorage.setItem(u,"true")}catch{}};d().forEach(e=>{v(e),e.addEventListener("wheel",t=>{if(!t.defaultPrevented&&t.shiftKey&&Math.abs(t.deltaY)>Math.abs(t.deltaX)&&l(e)){const n=e.scrollLeft;t.preventDefault(),e.scrollLeft+=t.deltaY,window.requestAnimationFrame(()=>{w(e),!m&&Math.abs(e.scrollLeft-n)>4&&S(),v(e)})}},{passive:!1}),e.addEventListener("scroll",()=>(e=>{if(w(e),!h||m)return void v(e);const t=f.get(e)??e.scrollLeft;Math.abs(e.scrollLeft-t)>4&&l(e)?S():v(e)})(e),{passive:!0})}),o?.addEventListener("click",S),s?.addEventListener("click",()=>{const e=i();if(!l(e))return void L();const t=e.scrollLeft,n=c(e)-t;let a=Math.min(220,n),r=1;a<24&&t>0&&(a=Math.min(220,t),r=-1),a<4||(m=!0,e.scrollTo({left:t+a*r,behavior:"smooth"}),window.setTimeout(()=>{e.scrollTo({left:t,behavior:"smooth"})},420),window.setTimeout(()=>{m=!1,d().forEach(e=>{v(e),w(e)}),L()},950))}),window.setTimeout(()=>{h=!0,d().forEach(v)},800),window.requestAnimationFrame(L),window.addEventListener("resize",L),window.addEventListener("plotline:timeline-layout-changed",L),n?.addEventListener("change",()=>window.requestAnimationFrame(L)),a?.addEventListener("change",()=>window.requestAnimationFrame(L))})(),y?.addEventListener("pointerdown",t=>{t.preventDefault(),document.body.classList.add("timeline-inspector-resizing"),y.setPointerCapture(t.pointerId);const n=t=>{const n=e.getBoundingClientRect().right-t.clientX;E(n)},a=()=>{document.body.classList.remove("timeline-inspector-resizing");const e=Math.round(v?.getBoundingClientRect().width||0);e>0&&localStorage.setItem(m,String(e)),window.dispatchEvent(new Event("plotline:timeline-layout-changed")),y.removeEventListener("pointermove",n),y.removeEventListener("pointerup",a),y.removeEventListener("pointercancel",a)};y.addEventListener("pointermove",n),y.addEventListener("pointerup",a),y.addEventListener("pointercancel",a)}),w?.addEventListener("click",e=>{e.preventDefault();const t=new URL(window.location.href),n=t.searchParams.get("FocusType")||t.searchParams.get("focusType");t.searchParams.delete("SelectedSceneID"),t.searchParams.delete("selectedSceneId"),t.searchParams.delete("selectedsceneid"),n&&"scene"!==n.toLowerCase()||(t.searchParams.delete("FocusType"),t.searchParams.delete("focusType"),t.searchParams.delete("FocusID"),t.searchParams.delete("focusId")),x(),window.location.href=t.toString()});const x=()=>{try{sessionStorage.setItem(p,JSON.stringify({path:window.location.pathname,top:window.scrollY,left:window.scrollX,workspaceLeft:t.scrollLeft,workspaceTop:t.scrollTop,containers:b().map((e,t)=>({index:t,left:e.scrollLeft,top:e.scrollTop}))}))}catch{}};window.PlotLineTimelineScroll={save:x};const q=(t,n,a)=>{a.forEach(n=>e.classList.remove(`${t}-${n}`)),e.classList.add(`${t}-${n}`)},I=e=>{const t=g.includes(e)?e:"comfortable";q("density",t,g),n&&(n.value=t),localStorage.setItem(c,t),window.requestAnimationFrame(k)},C=e=>{const t=f.includes(e)?e:"chapter";q("zoom",t,f),a&&(a.value=t),localStorage.setItem(d,t),window.requestAnimationFrame(k)},T=(t,n=!0)=>{const a=(t=>e.querySelector(`[data-scene-id='${CSS.escape(String(t))}']`))(t);a&&(a.classList.add("keyboard-focus"),a.scrollIntoView({behavior:"smooth",block:"center",inline:"center"}),n&&a.focus({preventScroll:!0}),window.setTimeout(()=>a.classList.remove("keyboard-focus"),1800))},k=()=>{e.querySelectorAll("[data-plot-line-svg-board]").forEach(e=>{const t=e.querySelector("[data-plot-line-svg]");if(!t)return;let n=e.querySelector("[data-plot-line-health-svg]");n||(n=document.createElementNS("http://www.w3.org/2000/svg","svg"),n.setAttribute("class","plot-lane-svg-overlay plot-lane-svg-health-overlay"),n.setAttribute("data-plot-line-health-svg",""),n.setAttribute("aria-hidden","true"),t.after(n)),t.replaceChildren(),n.replaceChildren();const a=e.getBoundingClientRect(),r=Math.max(e.scrollWidth,a.width),o=Math.max(e.scrollHeight,a.height);[t,n].forEach(e=>{e.setAttribute("viewBox",`0 0 ${r} ${o}`),e.setAttribute("width",String(r)),e.setAttribute("height",String(o))});const s=(e,t={})=>{const n=document.createElementNS("http://www.w3.org/2000/svg",e);return Object.entries(t).forEach(([e,t])=>n.setAttribute(e,String(t))),n},i=[...new Set([...e.querySelectorAll("[data-plot-line-slot]")].map(e=>{const t=e.getBoundingClientRect();return Math.round(t.left-a.left+t.width/2)}))].sort((e,t)=>e-t),l=Math.max(i.length-1,0),c=new Map;e.querySelectorAll("[data-plot-line-row]").forEach(e=>{e.dataset.plotLineId&&c.set(e.dataset.plotLineId,e)});const d=[...c.values()].map(e=>({row:e,plotLineId:e.dataset.plotLineId,colour:e.dataset.plotColour||"#2f6f63",points:[...e.querySelectorAll("[data-plot-event-node]")].map(e=>((e,t)=>{const n=t.closest("[data-plot-line-slot]");if(!n)return null;const r=n.getBoundingClientRect(),o=t.getBoundingClientRect();return{x:o.left-a.left+o.width/2,y:o.top-a.top+o.height/2,sceneX:r.left-a.left+r.width/2,radius:Math.max(o.width,o.height)/2,sceneIndex:0,type:(t.dataset.plotEventType||"Progress").toLowerCase(),targetPlotLineId:t.dataset.targetPlotLineId||"",targetPlotLineIds:(t.dataset.targetPlotLineIds||"").split(",").map(e=>e.trim()).filter(Boolean)}})(0,e)).filter(Boolean).map(e=>({...e,sceneIndex:Math.max(0,i.findIndex(t=>t===Math.round(e.sceneX)))})).sort((e,t)=>e.x-t.x),incomingStartXs:[]})),p=new Map(d.map(e=>[e.plotLineId,e])),u=(e,n,r,o)=>{if(!n)return void(window.console?.warn&&window.console.warn(`Plot line ${o} connector skipped because target plot line data is missing.`));e.x;const i=(e=>{const t=e.getBoundingClientRect();return t.top-a.top+t.height/2})(n),l=Math.max(28,Math.min(46,.28*Math.abs(i-e.y))),c=Math.max(8,e.radius||12),d=e.x+c,p=d+l,u=d+l/2;t.append(s("path",{class:`plot-line-svg-connector plot-line-svg-connector-${o}`,d:`M ${d} ${e.y} C ${u} ${e.y}, ${u} ${i}, ${p} ${i}`,stroke:r}))};d.forEach(e=>{e.points.forEach(e=>{"branch"===e.type&&e.targetPlotLineId&&p.get(e.targetPlotLineId)?.incomingStartXs.push(e.x),"split"===e.type&&e.targetPlotLineIds.forEach(t=>{p.get(t)?.incomingStartXs.push(e.x)})})}),d.forEach(e=>{e.health=(e=>{const t=e.some(e=>"resolve"===e.type),n=e.some(e=>"abandon"===e.type),a=e.find(e=>"resolve"===e.type),r=e.find(e=>"abandon"===e.type),o=e.some(e=>"merge"===e.type&&e.targetPlotLineId),s=e.some(e=>"split"===e.type&&e.targetPlotLineIds.length>=2),i=Boolean(a)&&e.some(e=>"branch"===e.type&&e.targetPlotLineId&&e.sceneIndex>=a.sceneIndex),c=e.reduce((e,t)=>Math.max(e,t.sceneIndex),0),d=!t&&!n&&l-c>=10,p=t&&!o&&!s&&!i;let u="active";return n?u="abandoned":t?u=p?"questionable":"resolved":d&&(u="neglected"),{state:u,isNeglected:d,isDangling:!t&&!n&&!o&&!s&&l>=c,isQuestionable:p,isAbandoned:n,resolvePoint:a,abandonPoint:r}})(e.points),e.state=e.health.state}),d.forEach(e=>{const{colour:n,points:a,incomingStartXs:r,state:o}=e;if(a.length>0){const i=a.find(e=>"start"===e.type),l=r.length?Math.min(...r):null,c=a.find(e=>"split"===e.type||"merge"===e.type),d=a[0],p=a[a.length-1],u=((null===l||i&&i.xe.x-t.x),h=c?m.indexOf(c):-1,g=h>=0?m.slice(0,h+1):m;null!==l&&l{const r=g[a+1];if(!r||r.x<=e.x)return;const i=Math.abs(r.sceneIndex-e.sceneIndex)>=f;t.append(s("path",{class:`plot-line-svg-path plot-line-svg-segment ${i?"plot-line-svg-segment-dormant":""} plotline-state-${o}`,d:`M ${e.x} ${e.y} L ${r.x} ${r.y}`,stroke:n}))})}}),d.forEach(({points:e,colour:t})=>{e.forEach(e=>{"branch"!==e.type&&"merge"!==e.type||u(e,c.get(e.targetPlotLineId),t,e.type),"split"===e.type&&e.targetPlotLineIds.length>=2?e.targetPlotLineIds.forEach(n=>{u(e,c.get(n),t,e.type)}):"split"===e.type&&e.targetPlotLineIds.length>0&&window.console?.warn&&window.console.warn("Plot line split connector skipped because fewer than two targets are available.")})}),d.forEach(e=>{const t=e.lineEndPoint||e.points[e.points.length-1],a=[];e.health?.isNeglected&&t&&a.push({point:t,kind:"neglected",label:"Dormant Thread",reason:"No activity for 10+ scenes.",action:"Add a Progress, Reveal or Resolve event."}),e.health?.isDangling&&t&&a.push({point:t,kind:"dangling",label:"Unresolved Thread",reason:"Thread contains no Resolve or Abandon event by the end of the current timeline.",action:"Review ending scenes and add Resolve or Abandon where appropriate."}),e.health?.isQuestionable&&e.health.resolvePoint&&a.push({point:e.health.resolvePoint,kind:"questionable",label:"Missing Closure",reason:"Resolved without merge, split, or branch.",action:"Verify this thread has sufficient payoff."}),e.health?.isAbandoned&&e.health.abandonPoint&&a.push({point:e.health.abandonPoint,kind:"abandoned",label:"Abandoned Thread",reason:"This plot line was abandoned.",action:"Check this is intentional."});const r=new Map;a.forEach(e=>{const t=`${Math.round(e.point.x)}:${Math.round(e.point.y)}`;r.has(t)||r.set(t,{point:e.point,warnings:[]}),r.get(t).warnings.push(e)}),r.forEach(({point:e,warnings:t})=>((e,t)=>{const a=Math.max(18,(e.radius||12)+8),r=t[0]?.kind||"warning",o=s("g",{class:`plotline-health-marker plotline-health-marker-${r}`}),i=s("title");i.textContent=(e=>e.map(e=>[`Warning: ${e.label}`,`Reason: ${e.reason}`,`Suggested Action: ${e.action}`].join("\n")).join("\n\n"))(t),o.append(i);const l=e.x+a,c=e.y-13;if("questionable"===r){o.append(s("circle",{cx:l,cy:c,r:9}));const e=s("text",{x:l,y:c+4,"text-anchor":"middle"});e.textContent=t.length>1?String(t.length):"?",o.append(e)}else if(o.append(s("circle",{cx:l,cy:c,r:10})),o.append(s("path",{d:`M ${l} ${c-6} L ${l+6} ${c+5} L ${l-6} ${c+5} Z`})),o.append(s("line",{x1:l,y1:c-2,x2:l,y2:c+2.5})),o.append(s("circle",{cx:l,cy:c+5.3,r:1.2})),t.length>1){const e=s("text",{x:l+11,y:c-6,"text-anchor":"middle",class:"plotline-health-count"});e.textContent=String(t.length),o.append(e)}n.append(o)})(e,t))})})},A=(e,t)=>{document.querySelectorAll(`[data-collapse-body='${CSS.escape(e)}']`).forEach(e=>{e.classList.toggle("timeline-section-collapsed",t)}),document.querySelectorAll(`[data-collapse-toggle='${CSS.escape(e)}']`).forEach(e=>{e.classList.toggle("is-collapsed",t),e.setAttribute("aria-expanded",String(!t))})};document.querySelectorAll("[data-collapse-toggle]").forEach(e=>{const t=e.dataset.collapseToggle;L||"collapsed"!==e.dataset.collapseDefault||S.add(t);const n=S.has(t);A(t,n),e.addEventListener("click",()=>{const e=!S.has(t);e?S.add(t):S.delete(t),A(t,e),localStorage.setItem(l,JSON.stringify([...S])),k(),window.dispatchEvent(new Event("plotline:timeline-layout-changed"))})}),n?.addEventListener("change",()=>I(n.value)),a?.addEventListener("change",()=>C(a.value)),I(localStorage.getItem(c)||"comfortable"),C(localStorage.getItem(d)||"chapter");const $=(()=>{try{return null!==sessionStorage.getItem(p)}catch{return!1}})();window.requestAnimationFrame(()=>{k(),((e="auto")=>{const t=o?.querySelector("[data-active-chapter='true']");if(!o||!t)return;const n=o.getBoundingClientRect(),a=t.getBoundingClientRect(),r=a.left+a.width/2,s=n.left+n.width/2;(a.leftn.right)&&o.scrollBy({left:r-s,behavior:e})})("auto"),$&&(()=>{let e=null;try{e=JSON.parse(sessionStorage.getItem(p)||"null"),sessionStorage.removeItem(p)}catch{try{sessionStorage.removeItem(p)}catch{}return}e&&e.path===window.location.pathname&&window.requestAnimationFrame(()=>{t.scrollLeft=Number(e.workspaceLeft)||0,t.scrollTop=Number(e.workspaceTop)||0;const n=b();(e.containers||[]).forEach(e=>{const t=n[e.index];t&&(t.scrollLeft=Number(e.left)||0,t.scrollTop=Number(e.top)||0)}),window.scrollTo(Number(e.left)||0,Number(e.top)||0)})})()}),window.addEventListener("resize",k),window.addEventListener("plotline:timeline-layout-changed",k);e.addEventListener("click",t=>{if(0!==t.button||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;const n=t.target instanceof Element?t.target:null,a=n?.closest("a[href]");if(!a||!e.contains(a))return;[...new URL(a.href,window.location.href).searchParams.keys()].some(e=>"selectedsceneid"===e.toLowerCase())&&x()},{capture:!0});const M=()=>{const e=r?.value.trim().toLowerCase()||"";let t=null;return i.forEach(n=>{const a=!e||(n.dataset.timelineSearchText||"").toLowerCase().includes(e);n.classList.toggle("search-hit",Boolean(e&&a)),n.classList.toggle("search-dim",Boolean(e&&!a)),!t&&e&&a&&(t=n)}),t};r?.addEventListener("input",M),r?.addEventListener("keydown",e=>{if("Enter"!==e.key)return;const t=M();t&&(e.preventDefault(),T(t.dataset.sceneId))}),s.forEach(e=>{e.addEventListener("change",()=>{e.value&&T(e.value)})}),document.querySelectorAll("[data-jump-scene]").forEach(e=>{e.addEventListener("click",()=>{e.dataset.jumpScene&&T(e.dataset.jumpScene)})}),document.addEventListener("keydown",e=>{const n=document.activeElement?.tagName?.toLowerCase(),o=["input","select","textarea"].includes(n)||document.activeElement?.isContentEditable;if((e.ctrlKey||e.metaKey)&&"f"===e.key.toLowerCase()&&r)return e.preventDefault(),r.focus(),void r.select();if("Escape"===e.key){const e=new URL(window.location.href),t=e.searchParams.has("FocusType")||e.searchParams.has("FocusID");return e.searchParams.delete("FocusType"),e.searchParams.delete("FocusID"),void(t?window.location.href=e.toString():r?.value&&(r.value="",M()))}if(!o){if("ArrowLeft"===e.key||"ArrowRight"===e.key)return e.preventDefault(),void t.scrollBy({left:"ArrowLeft"===e.key?-260:260,behavior:"smooth"});if("+"===e.key||"="===e.key||"-"===e.key){const t=f.indexOf(a?.value||"chapter"),n="-"===e.key?-1:1,r=Math.min(f.length-1,Math.max(0,t+n));C(f[r])}}})})(),(()=>{const e=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-drag-drop-panel]");if(!t)return;const n=new Map([...document.querySelectorAll("[data-drag-form]")].map(e=>[e.dataset.dragForm,e])),a=t.querySelector("[data-drag-panel-title]"),r=t.querySelector("[data-drag-panel-kicker]"),o=t.querySelector("[data-drag-panel-summary]"),s=document.querySelector("[data-scene-move-modal]"),i=s&&window.bootstrap?.Modal?window.bootstrap.Modal.getOrCreateInstance(s):null,l=s?.querySelector("[data-scene-move-title]"),c=s?.querySelector("[data-scene-move-summary]"),d=s?.querySelector("[data-scene-move-submit]"),p="plotline.timeline.scroll";let u=null,m=0;const h=(e,t,n)=>{const a=e?.querySelector(`[name='${CSS.escape(t)}']`);a&&(a.value=n??"")},g=e=>e?.selectedOptions?.[0]?.textContent?.trim()||"",f=e=>`“${e||"this scene"}”`,v=(e,t,n,a,r)=>t&&n&&t===n?`Move ${f(e.label)} to this new position within ${n}?`:t&&n?`Move ${f(e.label)} from ${t} to ${n}?`:`Move ${f(e.label)} ${a.toLowerCase()} ${r}?`,y=(e,s,p,u)=>{if("scene"===e)return t.classList.add("d-none"),t.querySelectorAll("[data-drag-form]").forEach(e=>e.classList.add("d-none")),n.get("scene")?.classList.remove("d-none"),l&&(l.textContent=s),c&&(c.textContent=p),d&&d.classList.toggle("d-none",s.toLowerCase().startsWith("cannot")||s.toLowerCase().startsWith("scene already")),void(i?i.show():t.classList.remove("d-none"));n.forEach((t,n)=>t.classList.toggle("d-none",n!==e)),t.classList.remove("d-none"),a.textContent=s,r.textContent=u,o.textContent=p,t.scrollIntoView({behavior:"smooth",block:"center"})},w=()=>{t.classList.add("d-none"),n.forEach(e=>e.classList.add("d-none"))},L=()=>{document.querySelectorAll(".drop-target-active, .drop-before, .drop-after, .chapter-drop-active, .drop-chapter-end").forEach(e=>e.classList.remove("drop-target-active","drop-before","drop-after","chapter-drop-active","drop-chapter-end"))};try{const t=JSON.parse(sessionStorage.getItem(p)||"null");t&&(sessionStorage.removeItem(p),requestAnimationFrame(()=>{const n=e?.querySelector(".timeline-shell");n&&(n.scrollLeft=t.left||0),window.scrollTo({top:t.top||0})}))}catch{sessionStorage.removeItem(p)}const S=e=>{try{const t=JSON.parse(e.dataTransfer.getData("application/json")||"{}");return t.type?t:u||{}}catch{return u||{}}};document.querySelectorAll("[data-drag-type][draggable='true']").forEach(e=>{e.addEventListener("dragstart",t=>((e,t)=>{const n={type:t.dataset.dragType,id:t.dataset.dragId,label:t.dataset.dragLabel||t.textContent.trim()};e.dataTransfer.effectAllowed="copyMove",e.dataTransfer.setData("application/json",JSON.stringify(n)),e.dataTransfer.setData("text/plain",`${n.type}:${n.id}`),u=n,document.body.classList.add("drag-active",`dragging-${n.type}`),t.classList.add("is-dragging")})(t,e)),e.addEventListener("dragend",()=>{e.classList.remove("is-dragging"),document.body.classList.remove("drag-active","dragging-scene","dragging-character","dragging-asset","dragging-location"),u=null,L()})}),t.querySelectorAll("[data-drag-cancel]").forEach(e=>e.addEventListener("click",w)),n.get("scene")?.addEventListener("submit",()=>{const t=e?.querySelector(".timeline-shell");try{sessionStorage.setItem(p,JSON.stringify({left:t?.scrollLeft||0,top:window.scrollY||0}))}catch{}}),e?.querySelectorAll(".timeline-scene-card[data-scene-id]").forEach(t=>{t.addEventListener("click",e=>{Date.now(){const n=S(e);["scene","character","asset"].includes(n.type)&&(e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect="scene"===n.type?"move":"copy",t.classList.add("drop-target-active"),t.classList.toggle("drop-before","scene"===n.type&&e.offsetX=t.clientWidth/2))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active","drop-before","drop-after")),t.addEventListener("drop",a=>{const r=S(a);if(!["scene","character","asset"].includes(r.type))return;a.preventDefault(),a.stopPropagation(),m=Date.now()+800,t.classList.remove("drop-target-active","drop-before","drop-after");const o=t.dataset.sceneId;if("scene"===r.type){if(r.id===o)return void y("scene","Cannot move scene","Drop a scene before or after a different scene.","Scene move");const s=n.get("scene"),i=a.offsetX{const a=t.closest("[data-chapter-drop-target]"),r=t.dataset.chapterId||a?.dataset.chapterId,o=t.dataset.chapterLabel||a?.dataset.chapterLabel||"this chapter";t.addEventListener("dragover",e=>{"scene"===S(e).type&&r&&(e.target.closest(".timeline-scene-card[data-scene-id]")||(e.preventDefault(),e.dataTransfer.dropEffect="move",t.classList.add("drop-target-active","drop-chapter-end"),a?.classList.add("chapter-drop-active")))}),t.addEventListener("dragleave",e=>{t.contains(e.relatedTarget)||(t.classList.remove("drop-target-active","drop-chapter-end"),a?.classList.remove("chapter-drop-active"))}),t.addEventListener("drop",a=>{const s=S(a);if("scene"!==s.type||!r)return;if(a.target.closest(".timeline-scene-card[data-scene-id]"))return;a.preventDefault(),a.stopPropagation(),m=Date.now()+800,L();const i=e.querySelector(`.timeline-scene-card[data-scene-id='${CSS.escape(s.id)}']`);if(i?.dataset.chapterId===r&&t.lastElementChild?.dataset?.sceneId===s.id)return void y("scene","Scene already here",`${s.label} is already at the end of ${o}.`,"Scene move");const l=n.get("scene");h(l,"SceneID",s.id),h(l,"AnchorSceneID",""),h(l,"TargetChapterID",r),h(l,"Position","End"),y("scene","Move Scene?",v(s,i?.dataset.chapterLabel||"",o,"After",o),"Scene move")})});const b=n.get("asset-dependency"),E=()=>{const e=b?.dataset.sourceLabel||"Source asset",n=b?.dataset.targetLabel||"Target asset",a=g(b?.querySelector("[name='AssetDependencyTypeID']"))||"Requires",r=g(b?.querySelector("[name='SourceRequiredStateID']"))||"the required state",o=g(b?.querySelector("[name='TargetBlockedStateID']"))||"the blocked state",s=t.querySelector("[data-asset-dependency-preview]");s&&(s.textContent=`${e} ${a.toLowerCase()} ${n}. ${e} should be ${r} before ${n} can be ${o}.`)};b?.querySelectorAll("select").forEach(e=>e.addEventListener("change",E)),document.querySelectorAll("[data-asset-drop-target], .drag-chip.asset").forEach(e=>{e.addEventListener("dragover",t=>{"asset"===S(t).type&&(t.preventDefault(),t.dataTransfer.dropEffect="copy",e.classList.add("drop-target-active"))}),e.addEventListener("dragleave",()=>e.classList.remove("drop-target-active")),e.addEventListener("drop",t=>{const n=S(t),a=e.dataset.assetId||e.dataset.dragId,r=e.dataset.assetLabel||e.dataset.dragLabel||e.textContent.trim();"asset"===n.type&&a&&(t.preventDefault(),e.classList.remove("drop-target-active"),n.id!==a?(h(b,"SourceAssetID",n.id),h(b,"TargetAssetID",a),b.dataset.sourceLabel=n.label,b.dataset.targetLabel=r,E(),y("asset-dependency","Create asset dependency",`${n.label} -> ${r}`,"Asset dependency")):y("asset-dependency","Cannot create dependency","Drop one asset onto a different asset.","Asset dependency"))})}),document.querySelectorAll("[data-drag-type='location']").forEach(e=>{e.addEventListener("dragover",t=>{"location"===S(t).type&&(t.preventDefault(),t.dataTransfer.dropEffect="copy",e.classList.add("drop-target-active"))}),e.addEventListener("dragleave",()=>e.classList.remove("drop-target-active")),e.addEventListener("drop",t=>{const a=S(t),r=e.dataset.dragId,o=e.dataset.dragLabel||e.textContent.trim();if("location"!==a.type)return;if(t.preventDefault(),e.classList.remove("drop-target-active"),a.id===r)return void y("location-relationship","Cannot create relationship","Drop one location onto a different location.","Location relationship");const s=n.get("location-relationship");h(s,"FromLocationID",a.id),h(s,"ToLocationID",r),y("location-relationship","Create location relationship",`${a.label} -> ${o}`,"Location drop")})})})(); \ No newline at end of file +(()=>{const n="plotline.theme",t=document.querySelectorAll("[data-theme-choice]"),r=()=>{try{return localStorage.getItem(n)}catch{return null}},u=t=>{try{localStorage.setItem(n,t)}catch{}},i=n=>{const i=n==="dark"?"dark":"light";document.documentElement.dataset.theme=i;document.documentElement.dataset.bsTheme=i;u(i);t.forEach(n=>{const t=n.dataset.themeChoice===i;n.classList.toggle("active",t);n.setAttribute("aria-pressed",String(t))})};t.forEach(n=>{n.addEventListener("click",()=>i(n.dataset.themeChoice))});i(r()||"light")})();(()=>{const n=document.querySelector("[data-trial-banner]");if(n){const t=`plotline.trialBanner.dismissed.${n.dataset.trialBannerKey||"current"}`;try{if(localStorage.getItem(t)==="true"){n.hidden=!0;return}}catch{}n.querySelector("[data-trial-banner-dismiss]")?.addEventListener("click",()=>{n.hidden=!0;try{localStorage.setItem(t,"true")}catch{}})}})();(()=>{const n=document.querySelectorAll(".scene-inspector-root");if(n.length){const t=()=>`${window.location.pathname}${window.location.search}${window.location.hash}`;n.forEach(n=>{n.addEventListener("submit",n=>{const r=n.target;if(r instanceof HTMLFormElement){let i=r.querySelector("input[name='ReturnUrl']");i||(i=document.createElement("input"),i.type="hidden",i.name="ReturnUrl",r.appendChild(i));i.value=t()}},!0)})}})();(()=>{const t=document.querySelectorAll(".scene-inspector-root");if(t.length){const n=(n,t,i)=>{const r=n.querySelector("[data-scene-occupancy-status]");r&&(r.textContent=t,r.dataset.saveState=i||"")},i=(n,t)=>{const r=document.createElement("div");r.innerHTML=t;const i=r.querySelector("[data-scene-occupancy-form]");if(i){n.replaceWith(i);const t=i.closest(".scene-inspector-root")?.querySelector(".scene-inspector-form"),r=t?.querySelector("[name='FloorPlanID']"),u=t?.querySelector("[name='InitialFloorPlanFloorID']"),f=i.querySelector("[name='FloorPlanID']"),e=i.querySelector("[name='InitialFloorPlanFloorID']");r&&f&&(r.value=f.value);u&&e&&(u.value=e.value)}};t.forEach(t=>{t.addEventListener("change",async t=>{const u=t.target.closest?.("[data-occupancy-plan-select]");if(u){const r=u.closest("[data-scene-occupancy-form]"),e=r?.querySelector("[name='SceneID']")?.value,o=r?.dataset.editorUrl;if(r&&e&&o){n(r,"Loading...","saving");const f=new URL(o,window.location.origin);f.searchParams.set("sceneId",e);u.value&&f.searchParams.set("floorPlanId",u.value);try{const n=await fetch(f,{headers:{"X-Requested-With":"XMLHttpRequest"}});if(!n.ok)throw new Error("The occupancy editor could not be refreshed.");i(r,await n.text())}catch(s){n(r,s.message||"Load failed","failed")}}}}),t.addEventListener("submit",async t=>{const r=t.target.closest?.("[data-scene-occupancy-form]");if(r){t.preventDefault();n(r,"Saving...","saving");try{const n=await fetch(r.action,{method:"POST",body:new FormData(r),headers:{"X-Requested-With":"XMLHttpRequest"}});if(!n.ok){let t="Save failed";const i=n.headers.get("content-type")||"";if(i.includes("application/json")){const i=await n.json();t=i.message||t}throw new Error(t);}i(r,await n.text())}catch(u){n(r,u.message||"Save failed","failed")}}})})}})();(()=>{const t=document.getElementById("plotlineConfirmModal"),f=t&&window.bootstrap?new bootstrap.Modal(t):null,e=t?.querySelector("#plotlineConfirmModalTitle"),o=t?.querySelector("#plotlineConfirmModalMessage"),i=t?.querySelector("[data-confirm-submit]"),s=t?.querySelector("[data-delete-confirm-field]"),r=t?.querySelector("[data-delete-confirm-input]");let n=null,u=null;const h=n=>{const t=n.split(/\n\s*\n/);return{title:t.shift()?.trim()||"Confirm action",body:t.join("\n\n").trim()}},c=()=>{n=null,u=null,r&&(r.value=""),s?.classList.add("d-none"),i?.removeAttribute("disabled")};t?.addEventListener("hidden.bs.modal",c);r?.addEventListener("input",()=>{n?.dataset.requireDeleteText==="true"&&i&&(i.disabled=r.value.trim()!=="DELETE")});i?.addEventListener("click",()=>{if(n){if(n.dataset.requireDeleteText==="true"){const t=n.querySelector("[data-delete-confirm-target], [name='confirmationText']");t&&(t.value=r?.value.trim()||"")}n.dataset.confirmed="true";f?.hide();n.requestSubmit&&u?n.requestSubmit(u):n.requestSubmit?n.requestSubmit():n.submit()}});document.addEventListener("submit",c=>{const l=c.target;if(l instanceof HTMLFormElement&&l.dataset.confirmed!=="true"&&l.dataset.confirmSkip!=="true"&&l.dataset.noDeleteConfirm!=="true"){const b=l.dataset.confirmMessage,k=c.submitter instanceof HTMLElement?c.submitter:l.querySelector("button[type='submit']"),a=k?.textContent||"",p=l.getAttribute("action")||"",y=/restore/i.test(a)||/\/restore\b/i.test(p),v=/delete forever/i.test(a)||/\/deleteforever\b/i.test(p),d=!y&&!v&&(/archive/i.test(a)||/\/archive\b/i.test(p)),nt=!v&&/(delete|remove)/i.test(a);if(b||d||y||nt||v){const tt=b||(d?"Archive this item?\n\nThis will hide it from active lists and timelines, but the data will be kept and can be restored later.":y?"Restore this item?\n\nThis will return it to active lists and timelines where applicable.":v?"Permanently delete this item?\n\nThis cannot be undone. Any linked planning data may also be removed or become unavailable. Only continue if you are certain.":"Remove this item?\n\nThis removes the link or supporting record. Major story items are archived instead of permanently deleted.");if(f&&t&&e&&o&&i){c.preventDefault();const g=h(tt);n=l;u=k;e.textContent=l.dataset.confirmTitle||g.title;o.textContent=l.dataset.confirmBody||g.body;i.textContent=l.dataset.confirmButtonText||a.trim()||"Confirm";i.className=`btn ${l.dataset.confirmButtonClass||(y?"btn-primary":"btn-danger")}`;const w=l.dataset.requireDeleteText==="true"||v;s?.classList.toggle("d-none",!w);w&&i&&(i.disabled=!0,r?.focus());f.show();w&&window.setTimeout(()=>r?.focus(),200)}}}})})();(()=>{const r=document.querySelectorAll("[data-help-icon]");if(r.length&&window.bootstrap){const u=new Map;let n=null;const f=n=>n.querySelector("[data-help-tooltip]")||n,i=n=>bootstrap.Tooltip.getInstance(f(n))?.hide(),t=(t=null)=>{n&&n!==t&&bootstrap.Popover.getInstance(n)?.hide()},e=()=>r.forEach(n=>i(n));r.forEach(r=>{const o=f(r),s=o.dataset.helpMicro||"Help article not found.",h=r.dataset.helpTitle||"Help unavailable",c=r.dataset.helpSummary||"Help content has not yet been written for this feature.";bootstrap.Tooltip.getOrCreateInstance(o,{title:s,trigger:"hover focus",placement:"top",container:"body"});const l=bootstrap.Popover.getOrCreateInstance(r,{title:h,trigger:"click",placement:"auto",container:"body",html:!0,customClass:"plotline-help-popover",content(){const u=document.createElement("div"),i=document.createElement("p");i.className="mb-2";i.textContent=c;const n=document.createElement("a");return n.href="#",n.textContent="More...",n.className="plotline-help-more",n.addEventListener("click",n=>{n.preventDefault(),t(),e(),r.dispatchEvent(new CustomEvent("plotline:help-more",{bubbles:!0,detail:{key:r.dataset.helpKey||""}}))}),u.append(i,n),u}});u.set(r,l);r.addEventListener("click",n=>{window.PlotLineHelpDrawer?.isActive?.()&&(n.preventDefault(),n.stopPropagation(),t(),i(r),window.PlotLineHelpPopovers?.hideAll(),window.PlotLineHelpDrawer.open(r.dataset.helpKey||""))});r.addEventListener("show.bs.popover",n=>{if(window.PlotLineHelpDrawer?.isActive?.()){n.preventDefault();return}t(r);i(r)});r.addEventListener("shown.bs.popover",()=>{n=r,i(r)});r.addEventListener("hidden.bs.popover",()=>{n===r&&(n=null)})});document.addEventListener("click",i=>{const r=i.target instanceof Element?i.target:null;if(r&&n&&!r.closest("[data-help-icon]")){const u=document.querySelector(`#${n.getAttribute("aria-describedby")}`);u?.contains(r)||t()}});document.addEventListener("keydown",n=>{n.key==="Escape"&&t()});window.PlotLineHelpPopovers={hideAll(){u.forEach(n=>n.hide());e();n=null}}}})();(()=>{const n=document.querySelector("[data-help-layout]"),p=document.querySelector("[data-help-drawer]"),i=document.querySelector("[data-help-content]"),l=document.querySelector("[data-help-splitter]"),w=document.querySelector("[data-help-close]"),h=document.querySelector("[data-help-collapse]"),a=document.querySelector("[data-help-expand]"),u=document.querySelector("[data-help-pin]"),f=document.querySelector("[data-help-drawer-heading]");if(n&&p&&i){const t={width:"plotline.helpDrawer.width",pinned:"plotline.helpDrawer.pinned",key:"plotline.helpDrawer.key",collapsed:"plotline.helpDrawer.collapsed"},b=(n,t,i)=>Math.min(i,Math.max(t,n)),e=n=>{try{return localStorage.getItem(n)==="true"}catch{return!1}},o=(n,t)=>{try{localStorage.setItem(n,t)}catch{}},v=i=>{const r=`${b(Number.parseFloat(i)||25,20,50)}%`;n.style.setProperty("--help-drawer-width",r);o(t.width,r)},c=n=>{o(t.pinned,String(n)),u?.setAttribute("aria-pressed",String(n)),u&&(u.textContent=n?"Unpin":"Pin")},r=i=>{n.classList.toggle("help-collapsed",i),o(t.collapsed,String(i)),h&&(h.textContent=i?"Expand":"Collapse")},s=async(u,e={})=>{const s=u||"";n.classList.add("help-open");e.keepCollapsed||r(!1);o(t.key,s);f&&(f.textContent=s||"Help");i.innerHTML='

Loading help...<\/p>';try{const n=await fetch(`/HelpDrawer/Article?key=${encodeURIComponent(s)}`,{headers:{"X-Requested-With":"XMLHttpRequest"}});i.innerHTML=n.ok?await n.text():'

Help for this feature has not yet been written.<\/p>';const t=i.querySelector(".help-drawer-article h2")?.textContent?.trim();f&&t&&(f.textContent=t)}catch{i.innerHTML='

Help for this feature has not yet been written.<\/p>'}},k=()=>{n.classList.remove("help-open","help-collapsed"),c(!1)};window.PlotLineHelpDrawer={isActive(){return n.classList.contains("help-open")},open(n){return s(n)}};v(localStorage.getItem(t.width)||"25%");c(e(t.pinned));r(e(t.collapsed));document.addEventListener("plotline:help-more",n=>{const t=n.detail?.key||n.target?.dataset?.helpKey||"";window.PlotLineHelpPopovers?.hideAll();s(t)});document.addEventListener("click",n=>{const t=n.target instanceof Element?n.target.closest("[data-help-open]"):null;t&&(n.preventDefault(),window.PlotLineHelpPopovers?.hideAll(),s(t.dataset.helpOpen||""))});w?.addEventListener("click",k);h?.addEventListener("click",()=>r(!n.classList.contains("help-collapsed")));a?.addEventListener("click",()=>r(!1));a?.addEventListener("keydown",n=>{(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),r(!1))});u?.addEventListener("click",()=>c(!e(t.pinned)));l?.addEventListener("pointerdown",t=>{if(n.classList.contains("help-open")&&!n.classList.contains("help-collapsed")){t.preventDefault();document.body.classList.add("help-resizing");l.setPointerCapture?.(t.pointerId);const i=t=>{const i=n.getBoundingClientRect(),r=(i.right-t.clientX)/i.width*100;v(r)},r=()=>{document.body.classList.remove("help-resizing"),document.removeEventListener("pointermove",i),document.removeEventListener("pointerup",r)};document.addEventListener("pointermove",i);document.addEventListener("pointerup",r)}});const y=(()=>{try{return localStorage.getItem(t.key)||""}catch{return""}})();e(t.pinned)&&y&&s(y,{keepCollapsed:!0})}})();(()=>{const n=document.querySelectorAll(".scene-inspector-root");if(n.length){const t=n=>n.toLowerCase().replace(/&/g,"and").replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");n.forEach(n=>{const o=n.dataset.sceneId||n.querySelector(".scene-inspector-form [name='SceneID']")?.value||"new",f=`plotline.inspector.${o}.`,s=new Set(["overview","timing","characters"]),u=[...n.querySelectorAll(".inspector-section")],r=n.querySelector(".scene-inspector-form"),i=n.querySelector("[data-scene-time-editor]");if(r&&i&&i.dataset.enhanced!=="true"){i.dataset.enhanced="true";const n=r.querySelector("[name='TimeModeID']"),e=i.dataset.exactDatetimeModeId||"",o=i.dataset.exactDateModeId||"",s=[...i.querySelectorAll("[data-time-part-field]")],h={StartDateTime:i.querySelector("[data-date-part-for='StartDateTime']"),EndDateTime:i.querySelector("[data-date-part-for='EndDateTime']")},c={StartDateTime:i.querySelector("[data-time-part-for='StartDateTime']"),EndDateTime:i.querySelector("[data-time-part-for='EndDateTime']")},l={StartDateTime:r.querySelector("input[type='hidden'][name='StartDateTime']"),EndDateTime:r.querySelector("input[type='hidden'][name='EndDateTime']")},t=()=>n?.value===e,a=()=>n?.value===o,u=()=>{const n=t();s.forEach(t=>{t.hidden=!n,t.classList.toggle("d-none",!n)})},f=n=>{const i=l[n],r=h[n]?.value||"",f=c[n]?.value||"";if(i){if(!r){i.value="";return}if(t()){i.value=`${r}T${f||"00:00"}`;return}if(a()){i.value=r;return}const u=i.value.match(/^\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2})/)?.[1];i.value=u?`${r}T${u}`:r}},v=()=>{f("StartDateTime"),f("EndDateTime")};n?.addEventListener("change",u);r.addEventListener("submit",v);u()}u.forEach(n=>{if(n.dataset.enhanced!=="true"){const l=n.querySelector("h3, h2"),u=n.dataset.sectionTitle||l?.textContent?.trim()||"Overview",a=t(u),o=n.dataset.sectionId||`inspector-${a}`,e=o.replace(/^inspector-/,"");n.id=o;n.dataset.searchText=`${u} ${n.textContent}`.toLowerCase();n.dataset.enhanced="true";const r=document.createElement("div");for(r.className="inspector-accordion-body";n.firstChild;)r.appendChild(n.firstChild);const i=document.createElement("button");i.type="button";i.className="inspector-accordion-toggle";i.setAttribute("aria-expanded","false");n.append(i,r);const v=r.querySelectorAll(".asset-event-item, .thread-event-item, .warning-mini-card, .dependency-card, .metric-slider").length;i.innerHTML=`${u}${v||""}`;const h=localStorage.getItem(`${f}${e}`),c=h===null?s.has(e):h==="open";n.classList.toggle("is-open",c);i.setAttribute("aria-expanded",String(c));i.addEventListener("click",()=>{const t=!n.classList.contains("is-open");n.classList.toggle("is-open",t);i.setAttribute("aria-expanded",String(t));localStorage.setItem(`${f}${e}`,t?"open":"closed")})}});n.querySelectorAll(".inspector-nav-links a").forEach(t=>{t.addEventListener("click",i=>{const r=n.querySelector(t.getAttribute("href"));r&&(i.preventDefault(),r.classList.add("is-open"),r.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"),r.scrollIntoView({behavior:"smooth",block:"start"}))})});const e=n.querySelector("[data-inspector-search]");if(e?.addEventListener("input",()=>{const n=e.value.trim().toLowerCase();u.forEach(t=>{const i=!n||t.dataset.searchText.includes(n);t.classList.toggle("is-filtered-out",!i);i&&n&&(t.classList.add("is-open"),t.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"))})}),"IntersectionObserver"in window){const t=[...n.querySelectorAll(".inspector-nav-links a")],i=new IntersectionObserver(n=>{n.forEach(n=>{n.isIntersecting&&t.forEach(t=>{t.classList.toggle("active",t.getAttribute("href")===`#${n.target.id}`)})})},{root:n.closest(".scene-inspector-panel")||null,rootMargin:"-10% 0px -70% 0px"});u.forEach(n=>i.observe(n))}})}})();(()=>{const n=document.querySelectorAll("[data-metric-shape-chart]");if(n.length){const t=["#2f6f63","#b35f3b","#6750a4","#c58b2b","#7d3f52","#33759b","#9c4d8f","#a33d3d","#6f8f3d","#d08a2f","#444b57"],u=new Set(["Overall Intensity","Tension","Emotional Weight","Action"]),i=[],r=()=>{window.requestAnimationFrame(()=>{i.forEach(n=>n.resize())})};window.PlotLineMetricCharts={resizeAll:r};window.addEventListener("plotline:timeline-layout-changed",r);const f={id:"plotlineChapterGuides",afterDraw(n){const u=n.config.options.plugins.plotlineScenes||[],{ctx:t,chartArea:r,scales:f}=n;if(u.length&&f.x){t.save();t.strokeStyle="rgba(47, 111, 99, 0.16)";t.fillStyle="rgba(82, 75, 65, 0.58)";t.lineWidth=1;t.font="700 10px system-ui, -apple-system, Segoe UI, sans-serif";const e=[];u.forEach((n,t)=>{t&&n.chapterLabel===u[t-1].chapterLabel||e.push({scene:n,index:t})});const i=e.filter(n=>!n.scene.isPlaceholder),o=i.length>40?5:i.length>24?4:i.length>14?2:1;i.forEach((n,u)=>{const{scene:s,index:c}=n,e=f.x.getPixelForValue(c+.5);t.beginPath();t.moveTo(e,r.top);t.lineTo(e,r.bottom);t.stroke();const h=Number.parseInt(String(s.chapterLabel).replace(/[^0-9]/g,""),10),l=u===0||u===i.length-1||o===1||Number.isFinite(h)&&h%o==0;l&&t.fillText(s.chapterLabel,Math.min(e+4,r.right-70),r.bottom+22)});t.restore()}}};window.Chart&&Chart.register(f);n.forEach(n=>{const p=n.querySelector("script[type='application/json']"),o=n.querySelector("canvas"),w=n.querySelector("[data-metric-toggles]"),b=n.querySelector("[data-chart-fallback]"),k=n.querySelector("[data-timeline-metric-edit-toolbar]"),c=n.querySelector("[data-edit-metric-status]"),v=n.hasAttribute("data-timeline-metric-editor")&&k&&c;if(p&&o){let f;try{f=JSON.parse(p.textContent||"{}")}catch{b?.classList.remove("d-none");return}if(!window.Chart||!f.scenes?.length||!f.metrics?.length){b?.classList.remove("d-none");return}const tt=new Set(f.defaultMetrics?.length?f.defaultMetrics:u),s=f.scenes.length,it=s>80?10:s>40?5:s>24?4:s>14?2:1,l=f.metrics.map((n,i)=>{const u=new Map(n.points.map(n=>[n.sceneId,n.value])),r=t[i%t.length];return{label:n.metricName,metricTypeId:n.metricTypeId,minValue:Number.isFinite(n.minValue)?n.minValue:1,maxValue:Number.isFinite(n.maxValue)?n.maxValue:10,data:f.scenes.map((n,t)=>{const i=u.get(n.sceneId);return i==null?{x:t+.5,y:null,sceneId:n.sceneId}:{x:t+.5,y:i,sceneId:n.sceneId}}),borderColor:r,backgroundColor:r,pointBackgroundColor:r,pointBorderColor:"#fff",pointBorderWidth:1.5,pointRadius:3,pointHoverRadius:5,borderWidth:2,tension:.35,spanGaps:!0,hidden:!tt.has(n.metricName)}});let e=null,a=!1;const h=n=>{c&&(c.textContent=n)},d=()=>l.map((n,t)=>t).filter(n=>r?.isDatasetVisible(n)),g=()=>{const n=d();return n.length===1?n[0]:-1},nt=()=>{if(v){const n=g();l.forEach((t,i)=>{t.pointRadius=i===n?5:3,t.pointHoverRadius=i===n?7:5,t.borderWidth=i===n?3:2});const t=d(),i=n>=0;o.classList.toggle("metric-curve-editing",i);c.classList.toggle("d-none",t.length===0);t.length===0?h(""):i?h("Drag points up or down to edit this metric."):h("Show only one metric line to edit its curve.");r?.update()}};w.innerHTML="";l.forEach((n,t)=>{const u=`metric-toggle-${Math.random().toString(36).slice(2)}-${t}`,i=document.createElement("label");i.className="metric-toggle-pill";i.style.setProperty("--metric-colour",n.borderColor);i.innerHTML=`${n.label}`;w.appendChild(i);i.querySelector("input").addEventListener("change",n=>{r.setDatasetVisibility(t,n.target.checked),nt(),r.update()})});const r=new Chart(o,{type:"line",data:{datasets:l},options:{responsive:!0,maintainAspectRatio:!1,interaction:{mode:"nearest",intersect:!1},scales:{y:{min:1,max:10,ticks:{stepSize:1},grid:{color:"rgba(82, 75, 65, 0.10)"}},x:{type:"linear",min:0,max:s,bounds:"ticks",ticks:{maxRotation:0,autoSkip:!1,maxTicksLimit:16,callback(n){const t=Math.floor(Number(n));if(t<0||t>=s)return"";const i=f.scenes[t];return t!==0&&t!==s-1&&t%it!=0?"":i?.isPlaceholder?"":i?.axisLabel||""}},afterBuildTicks(n){n.ticks=f.scenes.map((n,t)=>({value:t+.5}))},grid:{display:!1}}},plugins:{legend:{display:!1},plotlineScenes:f.scenes,tooltip:{callbacks:{title(n){const i=Math.floor(n[0].parsed.x),t=f.scenes[i];return t.isPlaceholder?t.sceneTitle||"No scene":`${t.chapterLabel}, Scene ${t.sceneNumber}: ${t.sceneTitle}`},label(n){return`${n.dataset.label}: ${n.formattedValue}`},afterBody(n){const r=Math.floor(n[0].parsed.x),t=f.scenes[r],i=[];return t.characterPresence?i.push(t.characterPresence):t.characterAppears!==undefined&&i.push(t.characterAppears?"Character appears":"Character does not appear"),t.bookTitle&&i.push(t.bookTitle),i}}}}}}),rt=n=>{if(!v)return null;const u=g();if(u<0)return null;const f=r.getElementsAtEventForMode(n,"nearest",{intersect:!0},!0),t=f.find(n=>n.datasetIndex===u);if(!t)return null;const e=r.data.datasets[t.datasetIndex],i=e?.data?.[t.index];return!i?.sceneId||i.y==null?null:{datasetIndex:t.datasetIndex,pointIndex:t.index,previousValue:i.y}},ut=(n,t)=>{const i=r.scales.y.getValueForPixel(n.offsetY),u=Math.round(i);return Math.max(t.minValue,Math.min(t.maxValue,u))},ft=async t=>{const u=r.data.datasets[t.datasetIndex],i=u?.data?.[t.pointIndex];if(u&&i?.sceneId){const f=k?.querySelector("input[name='__RequestVerificationToken']")?.value||"";h("Saving...");try{const e=await fetch(n.dataset.updateUrl||"/SceneMetrics/UpdateSceneMetricValue",{method:"POST",headers:{"Content-Type":"application/json",RequestVerificationToken:f},body:JSON.stringify({sceneId:Number(i.sceneId),metricId:Number(u.metricTypeId),value:Number(i.y)})}),t=await e.json().catch(()=>({}));if(!e.ok||!t.success)throw new Error(t.message||"Save failed");i.y=t.value;h("Saved");r.update()}catch{i.y=t.previousValue;h("Save failed");r.update()}}};v&&(nt(),o.addEventListener("pointerdown",n=>{(e=rt(n),e)&&(n.preventDefault(),o.setPointerCapture?.(n.pointerId),a=!0)}),o.addEventListener("pointermove",n=>{if(e){const t=r.data.datasets[e.datasetIndex],i=t?.data?.[e.pointIndex];t&&i&&(i.y=ut(n,t),r.update("none"))}}),o.addEventListener("pointerup",async n=>{if(e){const t=e;e=null;o.releasePointerCapture?.(n.pointerId);await ft(t);window.setTimeout(()=>{a=!1},0)}}),o.addEventListener("pointercancel",n=>{if(e){const i=r.data.datasets[e.datasetIndex],t=i?.data?.[e.pointIndex];t&&(t.y=e.previousValue);e=null;o.releasePointerCapture?.(n.pointerId);a=!1;r.update()}}));o.addEventListener("click",n=>{if(a){n.preventDefault();return}const t=r.getElementsAtEventForMode(n,"nearest",{intersect:!0},!0);if(t.length){const i=r.data.datasets[t[0].datasetIndex]?.data?.[t[0].index],e=i?Math.floor(i.x):t[0].index,u=f.scenes[e];u?.timelineUrl&&(window.PlotLineTimelineScroll?.save(),window.location.href=u.timelineUrl)}});i.push(r);const y=window.ResizeObserver?new ResizeObserver(()=>r.resize()):null;y&&(y.observe(n),y.observe(n.querySelector(".metric-chart-frame")||n))}})}})();(()=>{const i=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-timeline-controls]");if(i&&t){const r="plotline.timeline.visibility",u={"scene-cards":!0,"plot-lines":!0,assets:!0,characters:!0,locations:!0,warnings:!0,metrics:!0},e=()=>{try{return{...u,...JSON.parse(localStorage.getItem(r)||"{}")}}catch{return{...u}}},f=n=>{Object.entries(n).forEach(([n,t])=>{i.classList.toggle(`hide-${n}`,!t),document.querySelectorAll(`[data-timeline-section='${n}']`).forEach(n=>{n.classList.toggle("timeline-section-hidden",!t)})}),document.querySelectorAll("[data-location-marker]").forEach(t=>{t.classList.toggle("timeline-section-hidden",!n.locations)}),document.querySelectorAll("[data-warning-marker]").forEach(t=>{t.classList.toggle("timeline-section-hidden",!n.warnings)}),document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(n))},n=e();t.querySelectorAll("[data-timeline-toggle]").forEach(t=>{const i=t.dataset.timelineToggle;t.checked=n[i]??!0;t.addEventListener("change",()=>{n[i]=t.checked,localStorage.setItem(r,JSON.stringify(n)),f(n)})});t.querySelector("[data-timeline-preset-form]")?.addEventListener("submit",()=>{document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(n))});f(n)}})();(()=>{const n=document.querySelector("[data-timeline-root]");if(n){const r=n.querySelector(".timeline-workspace")||n,o=document.querySelector("[data-timeline-density]"),u=document.querySelector("[data-timeline-zoom]"),t=document.querySelector("[data-timeline-search]"),c=n.querySelector("[data-timeline-minimap]"),ot=document.querySelectorAll("[data-timeline-jump], [data-timeline-warning-jump], [data-timeline-entity-jump]"),st=[...n.querySelectorAll(".timeline-scene-card[data-scene-id]")],l="plotline.timeline.collapsed",nt="plotline.timeline.density",tt="plotline.timeline.zoom",s="plotline.timeline.pending-scroll",it="plotdirector.timelineNavigationDiscovered",a="plotline.timeline.inspectorWidth",v=8,ht=".timeline-shell,.plot-lane-board,.asset-lane-board,.character-lane-board,.metric-graph-stack,[data-timeline-minimap]",rt=["compact","comfortable","expanded"],h=["book","chapter","scene-detail","scene-overview"],y=n.querySelector("[data-inspector-drawer]"),i=n.querySelector("[data-inspector-resizer]"),ct=n.querySelector("[data-inspector-close]"),lt=n=>{try{return new Set(JSON.parse(localStorage.getItem(n)||"[]"))}catch{return new Set}},at=localStorage.getItem(l)!==null,f=lt(l),p=()=>[...n.querySelectorAll(ht)],vt=()=>{const t=n.querySelector("[data-timeline-navigation-card]");if(t){const nt=t.querySelector("[data-timeline-navigation-dismiss]"),tt=t.querySelector("[data-timeline-navigation-demo]"),rt=()=>{try{return localStorage.getItem(it)==="true"}catch{return!1}},y=()=>n.querySelector(".timeline-shell"),e=n=>Boolean(n&&n.scrollWidth>n.clientWidth+v),w=n=>Math.max(0,n.scrollWidth-n.clientWidth),s=()=>[r,...p()].filter((n,t,i)=>n&&i.indexOf(n)===t);let b=!1,h=!1,k=!1,l=null;const d=new WeakMap,f=n=>d.set(n,n.scrollLeft),ut=()=>window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches,ft=()=>{window.clearTimeout(l),t.hidden=!1,t.classList.remove("is-dismissing")},g=(n=false)=>{if(window.clearTimeout(l),!n||ut()||t.hidden){t.classList.remove("is-dismissing");t.hidden=!0;return}t.classList.add("is-dismissing");l=window.setTimeout(()=>{t.hidden=!0,t.classList.remove("is-dismissing")},1300)},c=n=>{const t=e(n),i=w(n);n.classList.toggle("timeline-horizontal-overflow",t);n.classList.toggle("has-scroll-left",t&&n.scrollLeft>v);n.classList.toggle("has-scroll-right",t&&n.scrollLeft{const n=e(y())&&!rt()&&!b;n?ft():t.classList.contains("is-dismissing")||g(!1);s().forEach(c)},a=()=>{b=!0;g(!0);try{localStorage.setItem(it,"true")}catch{}},et=n=>{if(c(n),!k||h){f(n);return}const t=d.get(n)??n.scrollLeft;if(Math.abs(n.scrollLeft-t)>4&&e(n)){a();return}f(n)},ot=s();ot.forEach(n=>{f(n),n.addEventListener("wheel",t=>{if(!t.defaultPrevented&&t.shiftKey&&Math.abs(t.deltaY)>Math.abs(t.deltaX)&&e(n)){const i=n.scrollLeft;t.preventDefault();n.scrollLeft+=t.deltaY;window.requestAnimationFrame(()=>{c(n),!h&&Math.abs(n.scrollLeft-i)>4&&a(),f(n)})}},{passive:!1}),n.addEventListener("scroll",()=>et(n),{passive:!0})});nt?.addEventListener("click",a);tt?.addEventListener("click",()=>{const n=y();if(!e(n)){i();return}const t=n.scrollLeft,o=w(n)-t;let r=Math.min(220,o),u=1;(r<24&&t>0&&(r=Math.min(220,t),u=-1),r<4)||(h=!0,n.scrollTo({left:t+r*u,behavior:"smooth"}),window.setTimeout(()=>{n.scrollTo({left:t,behavior:"smooth"})},420),window.setTimeout(()=>{h=!1,s().forEach(n=>{f(n),c(n)}),i()},950))});window.setTimeout(()=>{k=!0,s().forEach(f)},800);window.requestAnimationFrame(i);window.addEventListener("resize",i);window.addEventListener("plotline:timeline-layout-changed",i);o?.addEventListener("change",()=>window.requestAnimationFrame(i));u?.addEventListener("change",()=>window.requestAnimationFrame(i))}},yt=()=>{const t=n.getBoundingClientRect().width||window.innerWidth,i=Math.min(420,Math.max(320,t-360)),r=Math.max(i,Math.min(t*.65,t-420));return{minimum:i,maximum:r,defaultWidth:Math.max(i,Math.min(r,t*.4))}},w=t=>{if(y){const{minimum:i,maximum:r,defaultWidth:u}=yt(),f=Math.max(i,Math.min(r,Number(t)||u));n.style.setProperty("--timeline-inspector-width",`${Math.round(f)}px`)}};y&&(w(localStorage.getItem(a)),window.addEventListener("resize",()=>w(localStorage.getItem(a))));vt();i?.addEventListener("pointerdown",t=>{t.preventDefault();document.body.classList.add("timeline-inspector-resizing");i.setPointerCapture(t.pointerId);const u=t=>{const i=n.getBoundingClientRect().right,r=i-t.clientX;w(r)},r=()=>{document.body.classList.remove("timeline-inspector-resizing");const n=Math.round(y?.getBoundingClientRect().width||0);n>0&&localStorage.setItem(a,String(n));window.dispatchEvent(new Event("plotline:timeline-layout-changed"));i.removeEventListener("pointermove",u);i.removeEventListener("pointerup",r);i.removeEventListener("pointercancel",r)};i.addEventListener("pointermove",u);i.addEventListener("pointerup",r);i.addEventListener("pointercancel",r)});ct?.addEventListener("click",n=>{n.preventDefault();const t=new URL(window.location.href),i=t.searchParams.get("FocusType")||t.searchParams.get("focusType");t.searchParams.delete("SelectedSceneID");t.searchParams.delete("selectedSceneId");t.searchParams.delete("selectedsceneid");i&&i.toLowerCase()!=="scene"||(t.searchParams.delete("FocusType"),t.searchParams.delete("focusType"),t.searchParams.delete("FocusID"),t.searchParams.delete("focusId"));b();window.location.href=t.toString()});const b=()=>{try{sessionStorage.setItem(s,JSON.stringify({path:window.location.pathname,top:window.scrollY,left:window.scrollX,workspaceLeft:r.scrollLeft,workspaceTop:r.scrollTop,containers:p().map((n,t)=>({index:t,left:n.scrollLeft,top:n.scrollTop}))}))}catch{}},pt=()=>{let n=null;try{n=JSON.parse(sessionStorage.getItem(s)||"null");sessionStorage.removeItem(s)}catch{try{sessionStorage.removeItem(s)}catch{}return}n&&n.path===window.location.pathname&&window.requestAnimationFrame(()=>{r.scrollLeft=Number(n.workspaceLeft)||0;r.scrollTop=Number(n.workspaceTop)||0;const t=p();(n.containers||[]).forEach(n=>{const i=t[n.index];i&&(i.scrollLeft=Number(n.left)||0,i.scrollTop=Number(n.top)||0)});window.scrollTo(Number(n.left)||0,Number(n.top)||0)})};window.PlotLineTimelineScroll={save:b};const ut=(t,i,r)=>{r.forEach(i=>n.classList.remove(`${t}-${i}`)),n.classList.add(`${t}-${i}`)},ft=n=>{const t=rt.includes(n)?n:"comfortable";ut("density",t,rt);o&&(o.value=t);localStorage.setItem(nt,t);window.requestAnimationFrame(e)},k=n=>{const t=h.includes(n)?n:"chapter";ut("zoom",t,h);u&&(u.value=t);localStorage.setItem(tt,t);window.requestAnimationFrame(e)},wt=t=>n.querySelector(`[data-scene-id='${CSS.escape(String(t))}']`),d=(n,t=true)=>{const i=wt(n);i&&(i.classList.add("keyboard-focus"),i.scrollIntoView({behavior:"smooth",block:"center",inline:"center"}),t&&i.focus({preventScroll:!0}),window.setTimeout(()=>i.classList.remove("keyboard-focus"),1800))},bt=(n="auto")=>{const r=c?.querySelector("[data-active-chapter='true']");if(c&&r){const t=c.getBoundingClientRect(),i=r.getBoundingClientRect(),u=i.left+i.width/2,f=t.left+t.width/2;(i.leftt.right)&&c.scrollBy({left:u-f,behavior:n})}},kt=()=>localStorage.setItem(l,JSON.stringify([...f])),e=()=>{n.querySelectorAll("[data-plot-line-svg-board]").forEach(n=>{const u=n.querySelector("[data-plot-line-svg]");if(u){let i=n.querySelector("[data-plot-line-health-svg]");i||(i=document.createElementNS("http://www.w3.org/2000/svg","svg"),i.setAttribute("class","plot-lane-svg-overlay plot-lane-svg-health-overlay"),i.setAttribute("data-plot-line-health-svg",""),i.setAttribute("aria-hidden","true"),u.after(i));u.replaceChildren();i.replaceChildren();const r=n.getBoundingClientRect(),o=Math.max(n.scrollWidth,r.width),s=Math.max(n.scrollHeight,r.height);[u,i].forEach(n=>{n.setAttribute("viewBox",`0 0 ${o} ${s}`),n.setAttribute("width",String(o)),n.setAttribute("height",String(s))});const t=(n,t={})=>{const i=document.createElementNS("http://www.w3.org/2000/svg",n);return Object.entries(t).forEach(([n,t])=>i.setAttribute(n,String(t))),i},v=n=>{const t=n.getBoundingClientRect();return t.top-r.top+t.height/2},y=(n,t)=>{const u=t.closest("[data-plot-line-slot]");if(!u)return null;const f=u.getBoundingClientRect(),i=t.getBoundingClientRect(),e=i.left-r.left+i.width/2,o=i.top-r.top+i.height/2;return{x:e,y:o,sceneX:f.left-r.left+f.width/2,radius:Math.max(i.width,i.height)/2,sceneIndex:0,type:(t.dataset.plotEventType||"Progress").toLowerCase(),targetPlotLineId:t.dataset.targetPlotLineId||"",targetPlotLineIds:(t.dataset.targetPlotLineIds||"").split(",").map(n=>n.trim()).filter(Boolean)}},h=[...new Set([...n.querySelectorAll("[data-plot-line-slot]")].map(n=>{const t=n.getBoundingClientRect();return Math.round(t.left-r.left+t.width/2)}))].sort((n,t)=>n-t),c=Math.max(h.length-1,0),e=new Map;n.querySelectorAll("[data-plot-line-row]").forEach(n=>{n.dataset.plotLineId&&e.set(n.dataset.plotLineId,n)});const f=[...e.values()].map(n=>({row:n,plotLineId:n.dataset.plotLineId,colour:n.dataset.plotColour||"#2f6f63",points:[...n.querySelectorAll("[data-plot-event-node]")].map(t=>y(n,t)).filter(Boolean).map(n=>({...n,sceneIndex:Math.max(0,h.findIndex(t=>t===Math.round(n.sceneX)))})).sort((n,t)=>n.x-t.x),incomingStartXs:[]})),l=new Map(f.map(n=>[n.plotLineId,n])),p=n=>{const t=n.some(n=>n.type==="resolve"),i=n.some(n=>n.type==="abandon"),u=n.find(n=>n.type==="resolve"),l=n.find(n=>n.type==="abandon"),f=n.some(n=>n.type==="merge"&&n.targetPlotLineId),e=n.some(n=>n.type==="split"&&n.targetPlotLineIds.length>=2),a=Boolean(u)&&n.some(n=>n.type==="branch"&&n.targetPlotLineId&&n.sceneIndex>=u.sceneIndex),o=n.reduce((n,t)=>Math.max(n,t.sceneIndex),0),s=!t&&!i&&c-o>=10,v=!t&&!i&&!f&&!e&&c>=o,h=t&&!f&&!e&&!a;let r="active";return i?r="abandoned":t?r=h?"questionable":"resolved":s&&(r="neglected"),{state:r,isNeglected:s,isDangling:v,isQuestionable:h,isAbandoned:i,resolvePoint:u,abandonPoint:l}},w=n=>n.map(n=>[`Warning: ${n.label}`,`Reason: ${n.reason}`,`Suggested Action: ${n.action}`].join("\n")).join("\n\n"),b=(n,r)=>{const h=Math.max(18,(n.radius||12)+8),o=r[0]?.kind||"warning",e=t("g",{"class":`plotline-health-marker plotline-health-marker-${o}`}),s=t("title");s.textContent=w(r);e.append(s);const u=n.x+h,f=n.y-13;if(o==="questionable"){e.append(t("circle",{cx:u,cy:f,r:9}));const n=t("text",{x:u,y:f+4,"text-anchor":"middle"});n.textContent=r.length>1?String(r.length):"?";e.append(n)}else if(e.append(t("circle",{cx:u,cy:f,r:10})),e.append(t("path",{d:`M ${u} ${f-6} L ${u+6} ${f+5} L ${u-6} ${f+5} Z`})),e.append(t("line",{x1:u,y1:f-2,x2:u,y2:f+2.5})),e.append(t("circle",{cx:u,cy:f+5.3,r:1.2})),r.length>1){const n=t("text",{x:u+11,y:f-6,"text-anchor":"middle","class":"plotline-health-count"});n.textContent=String(r.length);e.append(n)}i.append(e)},a=(n,i,r,f)=>{if(!i){window.console?.warn&&window.console.warn(`Plot line ${f} connector skipped because target plot line data is missing.`);return}const e={x:n.x,y:v(i)},s=Math.max(28,Math.min(46,Math.abs(e.y-n.y)*.28)),c=Math.max(8,n.radius||12),o=n.x+c,l=o+s,h=o+s/2;u.append(t("path",{"class":`plot-line-svg-connector plot-line-svg-connector-${f}`,d:`M ${o} ${n.y} C ${h} ${n.y}, ${h} ${e.y}, ${l} ${e.y}`,stroke:r}))};f.forEach(n=>{n.points.forEach(n=>{n.type==="branch"&&n.targetPlotLineId&&l.get(n.targetPlotLineId)?.incomingStartXs.push(n.x),n.type==="split"&&n.targetPlotLineIds.forEach(t=>{l.get(t)?.incomingStartXs.push(n.x)})})});f.forEach(n=>{n.health=p(n.points),n.state=n.health.state});f.forEach(n=>{const{colour:f,points:i,incomingStartXs:r,state:e}=n;if(i.length>0){const l=i.find(n=>n.type==="start"),o=r.length?Math.min(...r):null,h=i.find(n=>n.type==="split"||n.type==="merge"),a=i[0],y=i[i.length-1],b=o!==null&&!(l&&l.xn.x-t.x),v=h?c.indexOf(h):-1,s=v>=0?c.slice(0,v+1):c;o!==null&&o{const r=s[i+1];if(r&&!(r.x<=n.x)){const o=Math.abs(r.sceneIndex-n.sceneIndex)>=w;u.append(t("path",{"class":`plot-line-svg-path plot-line-svg-segment ${o?"plot-line-svg-segment-dormant":""} plotline-state-${e}`,d:`M ${n.x} ${n.y} L ${r.x} ${r.y}`,stroke:f}))}})}});f.forEach(({points:t,colour:n})=>{t.forEach(t=>{(t.type==="branch"||t.type==="merge")&&a(t,e.get(t.targetPlotLineId),n,t.type),t.type==="split"&&t.targetPlotLineIds.length>=2?t.targetPlotLineIds.forEach(i=>{a(t,e.get(i),n,t.type)}):t.type==="split"&&t.targetPlotLineIds.length>0&&window.console?.warn&&window.console.warn("Plot line split connector skipped because fewer than two targets are available.")})});f.forEach(n=>{const i=n.lineEndPoint||n.points[n.points.length-1],t=[];n.health?.isNeglected&&i&&t.push({point:i,kind:"neglected",label:"Dormant Thread",reason:"No activity for 10+ scenes.",action:"Add a Progress, Reveal or Resolve event."});n.health?.isDangling&&i&&t.push({point:i,kind:"dangling",label:"Unresolved Thread",reason:"Thread contains no Resolve or Abandon event by the end of the current timeline.",action:"Review ending scenes and add Resolve or Abandon where appropriate."});n.health?.isQuestionable&&n.health.resolvePoint&&t.push({point:n.health.resolvePoint,kind:"questionable",label:"Missing Closure",reason:"Resolved without merge, split, or branch.",action:"Verify this thread has sufficient payoff."});n.health?.isAbandoned&&n.health.abandonPoint&&t.push({point:n.health.abandonPoint,kind:"abandoned",label:"Abandoned Thread",reason:"This plot line was abandoned.",action:"Check this is intentional."});const r=new Map;t.forEach(n=>{const t=`${Math.round(n.point.x)}:${Math.round(n.point.y)}`;r.has(t)||r.set(t,{point:n.point,warnings:[]});r.get(t).warnings.push(n)});r.forEach(({point:n,warnings:t})=>b(n,t))})}})},et=(n,t)=>{document.querySelectorAll(`[data-collapse-body='${CSS.escape(n)}']`).forEach(n=>{n.classList.toggle("timeline-section-collapsed",t)}),document.querySelectorAll(`[data-collapse-toggle='${CSS.escape(n)}']`).forEach(n=>{n.classList.toggle("is-collapsed",t),n.setAttribute("aria-expanded",String(!t))})};document.querySelectorAll("[data-collapse-toggle]").forEach(n=>{const t=n.dataset.collapseToggle;at||n.dataset.collapseDefault!=="collapsed"||f.add(t);const i=f.has(t);et(t,i);n.addEventListener("click",()=>{const n=!f.has(t);n?f.add(t):f.delete(t);et(t,n);kt();e();window.dispatchEvent(new Event("plotline:timeline-layout-changed"))})});o?.addEventListener("change",()=>ft(o.value));u?.addEventListener("change",()=>k(u.value));ft(localStorage.getItem(nt)||"comfortable");k(localStorage.getItem(tt)||"chapter");const dt=(()=>{try{return sessionStorage.getItem(s)!==null}catch{return!1}})();window.requestAnimationFrame(()=>{e(),bt("auto"),dt&&pt()});window.addEventListener("resize",e);window.addEventListener("plotline:timeline-layout-changed",e);const gt=t=>{if(t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey){const r=t.target instanceof Element?t.target:null,i=r?.closest("a[href]");if(i&&n.contains(i)){const u=new URL(i.href,window.location.href);[...u.searchParams.keys()].some(n=>n.toLowerCase()==="selectedsceneid")&&b()}}};n.addEventListener("click",gt,{capture:!0});const g=()=>{const n=t?.value.trim().toLowerCase()||"";let i=null;return st.forEach(t=>{const r=!n||(t.dataset.timelineSearchText||"").toLowerCase().includes(n);t.classList.toggle("search-hit",Boolean(n&&r));t.classList.toggle("search-dim",Boolean(n&&!r));!i&&n&&r&&(i=t)}),i};t?.addEventListener("input",g);t?.addEventListener("keydown",n=>{if(n.key==="Enter"){const t=g();t&&(n.preventDefault(),d(t.dataset.sceneId))}});ot.forEach(n=>{n.addEventListener("change",()=>{n.value&&d(n.value)})});document.querySelectorAll("[data-jump-scene]").forEach(n=>{n.addEventListener("click",()=>{n.dataset.jumpScene&&d(n.dataset.jumpScene)})});document.addEventListener("keydown",n=>{const i=document.activeElement?.tagName?.toLowerCase(),f=["input","select","textarea"].includes(i)||document.activeElement?.isContentEditable;if((n.ctrlKey||n.metaKey)&&n.key.toLowerCase()==="f"&&t){n.preventDefault();t.focus();t.select();return}if(n.key==="Escape"){const n=new URL(window.location.href),i=n.searchParams.has("FocusType")||n.searchParams.has("FocusID");n.searchParams.delete("FocusType");n.searchParams.delete("FocusID");i?window.location.href=n.toString():t?.value&&(t.value="",g());return}if(!f){if(n.key==="ArrowLeft"||n.key==="ArrowRight"){n.preventDefault();r.scrollBy({left:n.key==="ArrowLeft"?-260:260,behavior:"smooth"});return}if(n.key==="+"||n.key==="="||n.key==="-"){const t=h.indexOf(u?.value||"chapter"),i=n.key==="-"?-1:1,r=Math.min(h.length-1,Math.max(0,t+i));k(h[r])}}})}})();(()=>{const e=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-drag-drop-panel]");if(t){const i=new Map([...document.querySelectorAll("[data-drag-form]")].map(n=>[n.dataset.dragForm,n])),g=t.querySelector("[data-drag-panel-title]"),nt=t.querySelector("[data-drag-panel-kicker]"),tt=t.querySelector("[data-drag-panel-summary]"),o=document.querySelector("[data-scene-move-modal]"),v=o&&window.bootstrap?.Modal?window.bootstrap.Modal.getOrCreateInstance(o):null,y=o?.querySelector("[data-scene-move-title]"),p=o?.querySelector("[data-scene-move-summary]"),w=o?.querySelector("[data-scene-move-submit]"),s="plotline.timeline.scroll";let h=null,c=0;const n=(n,t,i)=>{const r=n?.querySelector(`[name='${CSS.escape(t)}']`);r&&(r.value=i??"")},l=n=>n?.selectedOptions?.[0]?.textContent?.trim()||"",a=n=>`“${n||"this scene"}”`,b=(n,t,i,r,u)=>t&&i&&t===i?`Move ${a(n.label)} to this new position within ${i}?`:t&&i?`Move ${a(n.label)} from ${t} to ${i}?`:`Move ${a(n.label)} ${r.toLowerCase()} ${u}?`,r=(n,r,u,f)=>{if(n==="scene"){t.classList.add("d-none");t.querySelectorAll("[data-drag-form]").forEach(n=>n.classList.add("d-none"));i.get("scene")?.classList.remove("d-none");y&&(y.textContent=r);p&&(p.textContent=u);w&&w.classList.toggle("d-none",r.toLowerCase().startsWith("cannot")||r.toLowerCase().startsWith("scene already"));v?v.show():t.classList.remove("d-none");return}i.forEach((t,i)=>t.classList.toggle("d-none",i!==n));t.classList.remove("d-none");g.textContent=r;nt.textContent=f;tt.textContent=u;t.scrollIntoView({behavior:"smooth",block:"center"})},it=()=>{t.classList.add("d-none"),i.forEach(n=>n.classList.add("d-none"))},k=()=>{document.querySelectorAll(".drop-target-active, .drop-before, .drop-after, .chapter-drop-active, .drop-chapter-end").forEach(n=>n.classList.remove("drop-target-active","drop-before","drop-after","chapter-drop-active","drop-chapter-end"))},rt=()=>{const n=e?.querySelector(".timeline-shell");try{sessionStorage.setItem(s,JSON.stringify({left:n?.scrollLeft||0,top:window.scrollY||0}))}catch{}};try{const n=JSON.parse(sessionStorage.getItem(s)||"null");n&&(sessionStorage.removeItem(s),requestAnimationFrame(()=>{const t=e?.querySelector(".timeline-shell");t&&(t.scrollLeft=n.left||0);window.scrollTo({top:n.top||0})}))}catch{sessionStorage.removeItem(s)}const f=n=>{try{const t=JSON.parse(n.dataTransfer.getData("application/json")||"{}");return t.type?t:h||{}}catch{return h||{}}},ut=(n,t)=>{const i={type:t.dataset.dragType,id:t.dataset.dragId,label:t.dataset.dragLabel||t.textContent.trim()};n.dataTransfer.effectAllowed="copyMove";n.dataTransfer.setData("application/json",JSON.stringify(i));n.dataTransfer.setData("text/plain",`${i.type}:${i.id}`);h=i;document.body.classList.add("drag-active",`dragging-${i.type}`);t.classList.add("is-dragging")};document.querySelectorAll("[data-drag-type][draggable='true']").forEach(n=>{n.addEventListener("dragstart",t=>ut(t,n)),n.addEventListener("dragend",()=>{n.classList.remove("is-dragging"),document.body.classList.remove("drag-active","dragging-scene","dragging-character","dragging-asset","dragging-location"),h=null,k()})});t.querySelectorAll("[data-drag-cancel]").forEach(n=>n.addEventListener("click",it));i.get("scene")?.addEventListener("submit",rt);e?.querySelectorAll(".timeline-scene-card[data-scene-id]").forEach(t=>{t.addEventListener("click",n=>{Date.now(){const i=f(n);["scene","character","asset"].includes(i.type)&&(n.preventDefault(),n.stopPropagation(),n.dataTransfer.dropEffect=i.type==="scene"?"move":"copy",t.classList.add("drop-target-active"),t.classList.toggle("drop-before",i.type==="scene"&&n.offsetX=t.clientWidth/2))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active","drop-before","drop-after")),t.addEventListener("drop",u=>{const o=f(u);if(["scene","character","asset"].includes(o.type)){u.preventDefault();u.stopPropagation();c=Date.now()+800;t.classList.remove("drop-target-active","drop-before","drop-after");const s=t.dataset.sceneId;if(o.type==="scene"){if(o.id===s){r("scene","Cannot move scene","Drop a scene before or after a different scene.","Scene move");return}const f=i.get("scene"),h=u.offsetX{const u=t.closest("[data-chapter-drop-target]"),o=t.dataset.chapterId||u?.dataset.chapterId,s=t.dataset.chapterLabel||u?.dataset.chapterLabel||"this chapter";t.addEventListener("dragover",n=>{const i=f(n);i.type==="scene"&&o&&(n.target.closest(".timeline-scene-card[data-scene-id]")||(n.preventDefault(),n.dataTransfer.dropEffect="move",t.classList.add("drop-target-active","drop-chapter-end"),u?.classList.add("chapter-drop-active")))});t.addEventListener("dragleave",n=>{t.contains(n.relatedTarget)||(t.classList.remove("drop-target-active","drop-chapter-end"),u?.classList.remove("chapter-drop-active"))});t.addEventListener("drop",u=>{const h=f(u);if(h.type==="scene"&&o&&!u.target.closest(".timeline-scene-card[data-scene-id]")){u.preventDefault();u.stopPropagation();c=Date.now()+800;k();const a=e.querySelector(`.timeline-scene-card[data-scene-id='${CSS.escape(h.id)}']`);if(a?.dataset.chapterId===o&&t.lastElementChild?.dataset?.sceneId===h.id){r("scene","Scene already here",`${h.label} is already at the end of ${s}.`,"Scene move");return}const l=i.get("scene");n(l,"SceneID",h.id);n(l,"AnchorSceneID","");n(l,"TargetChapterID",o);n(l,"Position","End");r("scene","Move Scene?",b(h,a?.dataset.chapterLabel||"",s,"After",s),"Scene move")}})});const u=i.get("asset-dependency"),d=()=>{const n=u?.dataset.sourceLabel||"Source asset",i=u?.dataset.targetLabel||"Target asset",f=l(u?.querySelector("[name='AssetDependencyTypeID']"))||"Requires",e=l(u?.querySelector("[name='SourceRequiredStateID']"))||"the required state",o=l(u?.querySelector("[name='TargetBlockedStateID']"))||"the blocked state",r=t.querySelector("[data-asset-dependency-preview]");r&&(r.textContent=`${n} ${f.toLowerCase()} ${i}. ${n} should be ${e} before ${i} can be ${o}.`)};u?.querySelectorAll("select").forEach(n=>n.addEventListener("change",d));document.querySelectorAll("[data-asset-drop-target], .drag-chip.asset").forEach(t=>{t.addEventListener("dragover",n=>{const i=f(n);i.type==="asset"&&(n.preventDefault(),n.dataTransfer.dropEffect="copy",t.classList.add("drop-target-active"))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active")),t.addEventListener("drop",i=>{const e=f(i),o=t.dataset.assetId||t.dataset.dragId,s=t.dataset.assetLabel||t.dataset.dragLabel||t.textContent.trim();if(e.type==="asset"&&o){if(i.preventDefault(),t.classList.remove("drop-target-active"),e.id===o){r("asset-dependency","Cannot create dependency","Drop one asset onto a different asset.","Asset dependency");return}n(u,"SourceAssetID",e.id);n(u,"TargetAssetID",o);u.dataset.sourceLabel=e.label;u.dataset.targetLabel=s;d();r("asset-dependency","Create asset dependency",`${e.label} -> ${s}`,"Asset dependency")}})});document.querySelectorAll("[data-drag-type='location']").forEach(t=>{t.addEventListener("dragover",n=>{const i=f(n);i.type==="location"&&(n.preventDefault(),n.dataTransfer.dropEffect="copy",t.classList.add("drop-target-active"))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active")),t.addEventListener("drop",u=>{const e=f(u),o=t.dataset.dragId,h=t.dataset.dragLabel||t.textContent.trim();if(e.type==="location"){if(u.preventDefault(),t.classList.remove("drop-target-active"),e.id===o){r("location-relationship","Cannot create relationship","Drop one location onto a different location.","Location relationship");return}const s=i.get("location-relationship");n(s,"FromLocationID",e.id);n(s,"ToLocationID",o);r("location-relationship","Create location relationship",`${e.label} -> ${h}`,"Location drop")}})})}})(); \ No newline at end of file