@musnows/scriverse 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ export type BackgroundTaskSummary = {
2
+ id?: unknown;
3
+ status?: unknown;
4
+ taskType?: unknown;
5
+ [key: string]: unknown;
6
+ };
7
+
8
+ export type BackgroundTaskTransition = {
9
+ task: BackgroundTaskSummary;
10
+ previousStatus: string;
11
+ status: string;
12
+ };
13
+
14
+ export function backgroundTaskActivityCount(
15
+ taskPage: { stats?: { pendingCount?: unknown; runningCount?: unknown } } | null | undefined,
16
+ relationshipIndex: { status?: unknown; queuedSourceCount?: unknown } | null | undefined
17
+ ): number;
18
+
19
+ export function collectBackgroundTaskTransitions(
20
+ previousSnapshots: Map<string, string>,
21
+ tasks: BackgroundTaskSummary[] | null | undefined,
22
+ initialized: boolean
23
+ ): {
24
+ snapshots: Map<string, string>;
25
+ transitions: BackgroundTaskTransition[];
26
+ };
27
+
28
+ export function backgroundTaskPollDelay(activityCount: unknown, dialogOpen?: boolean): number;
@@ -0,0 +1,30 @@
1
+ const activeTaskStatuses = new Set(["pending", "running"]);
2
+ const terminalTaskStatuses = new Set(["review", "completed", "partial", "expired", "cancelled"]);
3
+
4
+ export function backgroundTaskActivityCount(taskPage, relationshipIndex) {
5
+ const pendingCount = Number(taskPage?.stats?.pendingCount ?? 0);
6
+ const runningCount = Number(taskPage?.stats?.runningCount ?? 0);
7
+ const indexActive = ["queued", "building"].includes(String(relationshipIndex?.status))
8
+ || Number(relationshipIndex?.queuedSourceCount ?? 0) > 0;
9
+ return Math.max(0, pendingCount) + Math.max(0, runningCount) + (indexActive ? 1 : 0);
10
+ }
11
+
12
+ export function collectBackgroundTaskTransitions(previousSnapshots, tasks, initialized) {
13
+ const snapshots = new Map(previousSnapshots instanceof Map ? previousSnapshots : []);
14
+ const transitions = [];
15
+ for (const task of Array.isArray(tasks) ? tasks : []) {
16
+ const taskId = String(task?.id ?? "");
17
+ if (!taskId) continue;
18
+ const status = String(task?.status ?? "");
19
+ const previousStatus = snapshots.get(taskId);
20
+ if (initialized && activeTaskStatuses.has(previousStatus) && terminalTaskStatuses.has(status)) {
21
+ transitions.push({ task, previousStatus, status });
22
+ }
23
+ snapshots.set(taskId, status);
24
+ }
25
+ return { snapshots, transitions };
26
+ }
27
+
28
+ export function backgroundTaskPollDelay(activityCount, dialogOpen = false) {
29
+ return dialogOpen || Number(activityCount) > 0 ? 5_000 : 15_000;
30
+ }
@@ -10,6 +10,7 @@ export function reviewStatusLabel(value: unknown): string;
10
10
  export function taskScopeLabel(value: unknown): string;
11
11
  export function providerStatusLabel(value: unknown): string;
12
12
  export function providerConnectionLabel(value: unknown): string;
13
+ export function providerProtocolLabel(value: unknown): string;
13
14
  export function chapterVersionSourceLabel(value: unknown): string;
14
15
  export function occurrenceRoleLabel(value: unknown): string;
15
16
  export function searchResultTypeLabel(value: unknown): string;
@@ -65,6 +65,13 @@ export function providerConnectionLabel(value) {
65
65
  return enumLabel({ unchecked: "未测试", success: "连接正常", failed: "连接失败" }, value, "未知连接状态");
66
66
  }
67
67
 
68
+ export function providerProtocolLabel(value) {
69
+ return enumLabel({
70
+ "openai-chat-completions": "OpenAI Chat Completions",
71
+ "anthropic-messages": "Anthropic Messages"
72
+ }, value, "未知接口协议");
73
+ }
74
+
68
75
  export function chapterVersionSourceLabel(value) {
69
76
  return enumLabel({ manual: "人工保存", auto: "自动保存", "ai-suggestion": "AI 建议", restore: "历史恢复", import: "文件导入", create: "初始版本" }, value, "其他来源");
70
77
  }
@@ -10,7 +10,7 @@
10
10
  <link rel="icon" href="/icon.svg?v=20260712" type="image/svg+xml">
11
11
  <link rel="manifest" href="/site.webmanifest">
12
12
  <link rel="stylesheet" href="/vendor/vditor/dist/index.css?v=3.11.2">
13
- <link rel="stylesheet" href="/styles.css?v=20260726-settings-select-spacing-v1">
13
+ <link rel="stylesheet" href="/styles.css?v=20260727-inline-save-spacing-v2">
14
14
  </head>
15
15
  <body class="auth-pending">
16
16
  <section id="auth-view" class="auth-view hidden" aria-labelledby="auth-title">
@@ -88,6 +88,10 @@
88
88
  <button id="account-settings-button" type="button" role="menuitem">账户设置</button>
89
89
  <button id="logout-button" type="button" role="menuitem">退出登录</button>
90
90
  </div>
91
+ <button id="background-task-button" class="topbar-icon-button background-task-button hidden" type="button" aria-label="后台任务中心" title="后台任务中心" aria-haspopup="dialog" aria-controls="background-task-dialog">
92
+ <svg class="topbar-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7.5h16M4 12h16M4 16.5h10"/><circle cx="18" cy="16.5" r="2.5"/></svg>
93
+ <span id="background-task-count" class="background-task-count hidden" aria-hidden="true">0</span>
94
+ </button>
91
95
  <button id="top-search-button" class="topbar-icon-button" type="button" aria-label="全文检索" title="全文检索(Command/Ctrl+F)" disabled>
92
96
  <svg class="topbar-icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="m16.2 16.2 4.3 4.3"/></svg>
93
97
  </button>
@@ -167,6 +171,17 @@
167
171
  <div id="platform-ai-content" class="module-content"></div>
168
172
  </section>
169
173
 
174
+ <section id="platform-usage-view" class="shelf-view hidden" aria-labelledby="platform-usage-title">
175
+ <div class="shelf-header">
176
+ <div><span class="eyebrow">平台统计</span><h1 id="platform-usage-title">Token 用量</h1><p>查看工作台迄今的 AI Token 消耗、缓存命中率与各作品用量。</p></div>
177
+ <div class="settings-detail-actions">
178
+ <button id="platform-usage-return" class="ghost-button settings-parent-button" type="button">返回设置</button>
179
+ <button id="platform-usage-refresh" class="ghost-button" type="button">刷新</button>
180
+ </div>
181
+ </div>
182
+ <div id="platform-usage-content" class="module-content usage-page-content"></div>
183
+ </section>
184
+
170
185
  <section id="settings-hub-view" class="shelf-view hidden" aria-labelledby="settings-hub-title">
171
186
  <div class="shelf-header settings-hub-header">
172
187
  <div><span class="eyebrow">工作台配置</span><h1 id="settings-hub-title">设置</h1><p>集中管理 AI、显示偏好、内容检索与作品导出。</p></div>
@@ -174,6 +189,7 @@
174
189
  </div>
175
190
  <div class="settings-hub-grid">
176
191
  <button id="platform-ai-button" class="settings-hub-card hidden" type="button" data-settings-action="ai"><span class="settings-card-mark">AI</span><strong>AI 管理</strong><small>供应商、模型、上下文与全局提示词</small></button>
192
+ <button id="platform-usage-button" class="settings-hub-card hidden" type="button"><span class="settings-card-mark">T</span><strong>Token 用量</strong><small>总消耗、缓存命中率、每日网格与作品明细</small></button>
177
193
  <button id="user-management-button" class="settings-hub-card hidden" type="button"><span class="settings-card-mark">人</span><strong>用户管理</strong><small>管理员、普通用户与账户状态</small></button>
178
194
  <button id="platform-ui-settings-button" class="settings-hub-card hidden" type="button"><span class="settings-card-mark">界</span><strong>界面与分页</strong><small>设置通知位置及各模块的单页数量</small></button>
179
195
  <button id="collaboration-button" class="settings-hub-card" type="button"><span class="settings-card-mark">协</span><strong>作品协作</strong><small>邀请注册用户共同编辑当前作品</small></button>
@@ -205,7 +221,7 @@
205
221
  <input id="chapter-title" class="chapter-title" aria-label="章节标题" placeholder="章节标题">
206
222
  <div class="editor-actions">
207
223
  <span id="chapter-stats" class="chapter-stats">0 字 · v0</span>
208
- <button id="insight-button" class="ghost-button" type="button">章节概览</button>
224
+ <button id="insight-button" class="ghost-button" type="button" aria-controls="chapter-insight-toast" aria-expanded="false">章节概览</button>
209
225
  <button id="versions-button" class="ghost-button" type="button">版本</button>
210
226
  <button id="chapter-edit-button" class="primary-button hidden" type="button">编辑</button>
211
227
  <button id="tidy-blank-lines-button" class="ghost-button" type="button">整理空行</button>
@@ -213,7 +229,6 @@
213
229
  </div>
214
230
  </div>
215
231
  <div class="editor-body">
216
- <div id="chapter-insight" class="chapter-insight hidden"></div>
217
232
  <div class="chapter-editor-frame">
218
233
  <aside id="chapter-line-numbers" class="chapter-line-numbers" aria-label="正文行号,可拖拽引用多行"><div id="chapter-line-numbers-inner"></div></aside>
219
234
  <textarea id="chapter-content" class="chapter-content" aria-label="章节正文" placeholder="在这里开始你的故事……"></textarea>
@@ -314,6 +329,21 @@
314
329
  <input id="cover-file" class="hidden" type="file" accept="image/png,image/jpeg,image/webp">
315
330
  <input id="avatar-file" class="hidden" type="file" accept="image/png,image/jpeg,image/webp">
316
331
 
332
+ <dialog id="background-task-dialog" class="dialog wide-dialog background-task-dialog" aria-labelledby="background-task-dialog-title">
333
+ <form method="dialog">
334
+ <div class="dialog-header">
335
+ <div><span class="eyebrow">全局进度</span><h2 id="background-task-dialog-title">后台任务中心</h2><p id="background-task-dialog-meta" class="dialog-header-meta">当前作品的分析任务与索引队列</p></div>
336
+ <button class="dialog-close" value="cancel" aria-label="关闭后台任务中心" type="submit">×</button>
337
+ </div>
338
+ <div id="background-task-content" class="background-task-content" role="region" aria-label="后台任务状态"></div>
339
+ <div class="dialog-actions background-task-actions">
340
+ <button id="background-task-open-analysis" class="ghost-button" type="button">前往 AI 分析中心</button>
341
+ <button id="background-task-refresh" class="primary-button" type="button">刷新状态</button>
342
+ <button class="ghost-button" value="cancel" type="submit">关闭</button>
343
+ </div>
344
+ </form>
345
+ </dialog>
346
+
317
347
  <dialog id="onboarding-dialog" class="onboarding-dialog" aria-labelledby="onboarding-dialog-title" aria-describedby="onboarding-dialog-description" data-testid="first-use-onboarding">
318
348
  <div id="onboarding-spotlight" class="onboarding-spotlight" aria-hidden="true"></div>
319
349
  <section id="onboarding-popover" class="onboarding-popover" data-placement="bottom">
@@ -594,7 +624,14 @@
594
624
  <legend>各模块单页数量</legend>
595
625
  <small>每个模块独立设置,允许 10–100 条;默认均为 30 条。</small>
596
626
  <div class="pagination-settings-grid">
627
+ <label>设定库<input id="page-size-settings" name="pageSizeSettings" type="number" min="10" max="100" step="1" required aria-label="设定库单页数量"></label>
597
628
  <label>角色列表<input id="page-size-characters" name="pageSizeCharacters" type="number" min="10" max="100" step="1" required aria-label="角色列表单页数量"></label>
629
+ <label>种族列表<input id="page-size-races" name="pageSizeRaces" type="number" min="10" max="100" step="1" required aria-label="种族列表单页数量"></label>
630
+ <label>组织列表<input id="page-size-organizations" name="pageSizeOrganizations" type="number" min="10" max="100" step="1" required aria-label="组织列表单页数量"></label>
631
+ <label>时间线事件<input id="page-size-timeline" name="pageSizeTimeline" type="number" min="10" max="100" step="1" required aria-label="时间线事件单页数量"></label>
632
+ <label>大纲与伏笔<input id="page-size-outlines" name="pageSizeOutlines" type="number" min="10" max="100" step="1" required aria-label="大纲与伏笔单页数量"></label>
633
+ <label>人物关系列表<input id="page-size-relationships" name="pageSizeRelationships" type="number" min="10" max="100" step="1" required aria-label="人物关系列表单页数量"></label>
634
+ <label>审核列表<input id="page-size-reviews" name="pageSizeReviews" type="number" min="10" max="100" step="1" required aria-label="审核列表单页数量"></label>
598
635
  <label>AI 分析任务<input id="page-size-analysis-tasks" name="pageSizeAnalysisTasks" type="number" min="10" max="100" step="1" required aria-label="AI 分析任务单页数量"></label>
599
636
  <label>正文导入历史<input id="page-size-file-versions" name="pageSizeFileVersions" type="number" min="10" max="100" step="1" required aria-label="正文导入历史单页数量"></label>
600
637
  </div>
@@ -751,6 +788,6 @@
751
788
  <div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
752
789
  <script id="vditorIconScript" src="/vendor/vditor/dist/js/icons/ant.js?v=3.11.2"></script>
753
790
  <script src="/vendor/vditor/dist/index.min.js?v=3.11.2"></script>
754
- <script type="module" src="/app.js?v=20260726-relationship-pinyin-v10"></script>
791
+ <script type="module" src="/app.js?v=20260727-race-tree-pagination-v1"></script>
755
792
  </body>
756
793
  </html>
@@ -51,7 +51,7 @@ export function serializePageRoute(route = {}) {
51
51
  } else if (view === "welcome" && workId) {
52
52
  params.set("view", "welcome");
53
53
  params.set("work", workId);
54
- } else if (view === "settings" || view === "platform-ai") {
54
+ } else if (view === "settings" || view === "platform-ai" || view === "platform-usage") {
55
55
  params.set("view", view);
56
56
  if (workId) params.set("work", workId);
57
57
  appendReturnContext(params, route);
@@ -85,7 +85,7 @@ export function parsePageRoute(hash = "") {
85
85
  return { view, workId, entity, entityId: entityId || null, entityMode };
86
86
  }
87
87
  if (view === "welcome" && workId) return { view, workId };
88
- if (view === "settings" || view === "platform-ai") {
88
+ if (view === "settings" || view === "platform-ai" || view === "platform-usage") {
89
89
  const route = { view, workId: workId || null };
90
90
  const returnView = value(params, "from");
91
91
  if (returnViewSet.has(returnView)) route.returnView = returnView;
@@ -83,3 +83,38 @@ export function buildRaceForest(races) {
83
83
  };
84
84
  return sort(roots);
85
85
  }
86
+
87
+ export function paginateRaceForest(races, page, limit) {
88
+ const safeLimit = Math.max(1, Math.floor(Number(limit) || 1));
89
+ const forest = buildRaceForest(races);
90
+ const pages = [];
91
+ let currentItems = [];
92
+ let currentItemCount = 0;
93
+ const subtreeSize = (node) => 1 + node.children.reduce((total, child) => total + subtreeSize(child), 0);
94
+
95
+ for (const root of forest) {
96
+ const rootItemCount = subtreeSize(root);
97
+ if (currentItems.length && currentItemCount + rootItemCount > safeLimit) {
98
+ pages.push({ items: currentItems, itemCount: currentItemCount });
99
+ currentItems = [];
100
+ currentItemCount = 0;
101
+ }
102
+ currentItems.push(root);
103
+ currentItemCount += rootItemCount;
104
+ }
105
+ if (currentItems.length || !pages.length) pages.push({ items: currentItems, itemCount: currentItemCount });
106
+
107
+ const pageCount = pages.length;
108
+ const safePage = Math.min(Math.max(1, Number(page) || 1), pageCount);
109
+ const selectedPage = pages[safePage - 1];
110
+ return {
111
+ items: selectedPage.items,
112
+ itemCount: selectedPage.itemCount,
113
+ page: safePage,
114
+ limit: safeLimit,
115
+ total: races.length,
116
+ pageCount,
117
+ hasMore: safePage < pageCount,
118
+ nextPage: safePage < pageCount ? safePage + 1 : null
119
+ };
120
+ }
@@ -80,6 +80,7 @@
80
80
  [data-pending-view="shelf"] .auth-pending #shelf-view.hidden,
81
81
  [data-pending-view="settings"] .auth-pending #settings-hub-view.hidden,
82
82
  [data-pending-view="platform-ai"] .auth-pending #platform-ai-view.hidden,
83
+ [data-pending-view="platform-usage"] .auth-pending #platform-usage-view.hidden,
83
84
  [data-pending-view="module"] .auth-pending #module-view.hidden { display: block !important; }
84
85
  [data-pending-view="welcome"] .auth-pending #welcome-view.hidden,
85
86
  [data-pending-view="editor"] .auth-pending #editor-view.hidden { display: grid !important; }
@@ -243,10 +244,10 @@
243
244
  --row-active: #332d27;
244
245
  --surface-hover: #3a342d;
245
246
  --app-glow: rgba(98,82,66,.18);
246
- --toast-bg: #ece6dc;
247
- --toast-fg: #171714;
248
- --toast-error-bg: #e08a72;
249
- --toast-error-fg: #171714;
247
+ --toast-bg: #25231f;
248
+ --toast-fg: #fffefa;
249
+ --toast-error-bg: #6e2e21;
250
+ --toast-error-fg: #fffefa;
250
251
  --relationship-card-border: #1c1c24;
251
252
  --relationship-card-surface: #12121a;
252
253
  --relationship-toolbar-surface: #12121a;
@@ -403,6 +404,26 @@ input[type="checkbox"][hidden] { display: none; }
403
404
  color: var(--muted);
404
405
  background: transparent;
405
406
  }
407
+ .background-task-button { position: relative; }
408
+ .background-task-button.is-active { border-color: color-mix(in srgb, var(--accent) 48%, var(--line)); color: var(--accent-dark); }
409
+ .background-task-count {
410
+ position: absolute;
411
+ top: -5px;
412
+ right: -6px;
413
+ display: grid;
414
+ min-width: 18px;
415
+ height: 18px;
416
+ padding: 0 4px;
417
+ place-items: center;
418
+ border: 2px solid var(--paper);
419
+ border-radius: 10px;
420
+ background: var(--accent);
421
+ color: #fff;
422
+ font-family: var(--font-latin), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
423
+ font-size: 8px;
424
+ font-weight: 700;
425
+ line-height: 1;
426
+ }
406
427
  .theme-icon, .settings-icon, .topbar-icon {
407
428
  width: 17px;
408
429
  height: 17px;
@@ -534,6 +555,78 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
534
555
  .settings-hub-card strong { align-self: end; font-size: 16px; }
535
556
  .settings-hub-card small { align-self: start; color: var(--muted); font-size: 10px; line-height: 1.5; }
536
557
  .settings-work-note { max-width: 1000px; margin: 18px auto 0; color: var(--muted); font-size: 11px; }
558
+ .usage-page-content { width: 100%; max-width: 1400px; margin: 0 auto; padding-top: 0; }
559
+ .usage-overview { min-width: 0; container-name: usage-overview; container-type: inline-size; }
560
+ .usage-stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
561
+ .usage-stat {
562
+ display: grid;
563
+ align-content: start;
564
+ min-width: 0;
565
+ min-height: 122px;
566
+ padding: 17px 18px;
567
+ border: 1px solid var(--line);
568
+ border-radius: 6px;
569
+ background: var(--surface-soft);
570
+ }
571
+ .usage-stat.is-primary { border-color: color-mix(in srgb, var(--accent) 42%, var(--line)); background: color-mix(in srgb, var(--accent) 6%, var(--surface-soft)); }
572
+ .usage-stat > span { color: var(--muted); font-size: 10px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
573
+ .usage-stat strong { margin: 10px 0 5px; overflow: hidden; color: var(--ink); font: 600 clamp(23px, 2.8vw, 34px)/1 var(--font-latin), ui-monospace, monospace; letter-spacing: -.035em; text-overflow: ellipsis; white-space: nowrap; }
574
+ .usage-stat.is-primary strong { color: var(--accent-dark); }
575
+ .usage-stat small { overflow-wrap: anywhere; color: var(--muted); font-size: 9px; line-height: 1.45; }
576
+ .usage-measurement-note { margin: 11px 0 0; color: var(--muted); font-size: 10px; line-height: 1.6; }
577
+ .usage-calendar-section, .usage-work-section { margin-top: 26px; padding-top: 22px; border-top: 1px solid var(--line); }
578
+ .usage-calendar-section > header, .usage-work-section > header { display: flex; align-items: end; justify-content: space-between; gap: 18px; margin-bottom: 14px; }
579
+ .usage-calendar-section h3, .usage-work-section h3 { margin: 0 0 4px; font-size: 15px; font-weight: 650; }
580
+ .usage-calendar-section header p, .usage-work-section header p { margin: 0; color: var(--muted); font-size: 10px; }
581
+ .usage-calendar-scroll { max-width: 100%; padding: 10px 12px 12px; overflow-x: auto; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
582
+ .usage-calendar-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
583
+ .usage-calendar-frame { width: max-content; min-width: 100%; }
584
+ .usage-calendar-months {
585
+ display: grid;
586
+ grid-template-columns: repeat(var(--usage-week-count), 11px);
587
+ gap: 3px;
588
+ min-width: calc(var(--usage-week-count) * 14px);
589
+ height: 19px;
590
+ margin-left: 27px;
591
+ color: var(--muted);
592
+ font: 9px/1 var(--font-latin), sans-serif;
593
+ }
594
+ .usage-calendar-months span { white-space: nowrap; }
595
+ .usage-calendar-body { display: grid; grid-template-columns: 20px max-content; gap: 7px; }
596
+ .usage-calendar-weekdays { display: grid; grid-template-rows: repeat(7, 11px); gap: 3px; color: var(--muted); font: 8px/11px var(--font-latin), sans-serif; }
597
+ .usage-calendar-weekdays span:nth-child(1) { grid-row: 2; }
598
+ .usage-calendar-weekdays span:nth-child(2) { grid-row: 4; }
599
+ .usage-calendar-weekdays span:nth-child(3) { grid-row: 6; }
600
+ .usage-calendar-grid {
601
+ display: grid;
602
+ grid-template-rows: repeat(7, 11px);
603
+ grid-auto-columns: 11px;
604
+ grid-auto-flow: column;
605
+ gap: 3px;
606
+ min-width: calc(var(--usage-week-count) * 14px);
607
+ }
608
+ .usage-calendar-cell { display: block; width: 11px; height: 11px; border: 1px solid color-mix(in srgb, var(--line) 82%, transparent); border-radius: 2px; background: var(--paper-deep); }
609
+ .usage-calendar-cell[data-level="1"], .usage-calendar-legend i[data-level="1"] { border-color: color-mix(in srgb, var(--accent) 25%, var(--line)); background: color-mix(in srgb, var(--accent) 18%, var(--surface)); }
610
+ .usage-calendar-cell[data-level="2"], .usage-calendar-legend i[data-level="2"] { border-color: color-mix(in srgb, var(--accent) 46%, var(--line)); background: color-mix(in srgb, var(--accent) 42%, var(--surface)); }
611
+ .usage-calendar-cell[data-level="3"], .usage-calendar-legend i[data-level="3"] { border-color: color-mix(in srgb, var(--accent) 72%, var(--line)); background: color-mix(in srgb, var(--accent) 70%, var(--surface)); }
612
+ .usage-calendar-cell[data-level="4"], .usage-calendar-legend i[data-level="4"] { border-color: var(--accent-dark); background: var(--accent-dark); }
613
+ .usage-calendar-cell.is-future { border-color: transparent; background: transparent; }
614
+ .usage-calendar-cell[tabindex="0"]:focus-visible { position: relative; z-index: 1; outline: 2px solid var(--ink); outline-offset: 1px; }
615
+ .usage-calendar-legend { display: flex; align-items: center; justify-content: flex-end; gap: 4px; margin-top: 8px; color: var(--muted); font-size: 9px; }
616
+ .usage-calendar-legend i { width: 11px; height: 11px; border: 1px solid color-mix(in srgb, var(--line) 82%, transparent); border-radius: 2px; background: var(--paper-deep); }
617
+ .usage-work-table-scroll { max-width: 100%; overflow-x: auto; border: 1px solid var(--line); border-radius: 6px; }
618
+ .usage-work-table { width: 100%; min-width: 680px; border-collapse: collapse; background: var(--surface); font-size: 11px; }
619
+ .usage-work-table th, .usage-work-table td { padding: 11px 13px; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
620
+ .usage-work-table thead th { background: var(--surface-soft); color: var(--muted); font-size: 9px; font-weight: 600; letter-spacing: .04em; }
621
+ .usage-work-table th:first-child, .usage-work-table td:first-child { text-align: left; }
622
+ .usage-work-table tbody th { max-width: 320px; overflow: hidden; color: var(--ink); font-weight: 600; text-overflow: ellipsis; }
623
+ .usage-work-table tbody tr:last-child > * { border-bottom: 0; }
624
+ @container usage-overview (max-width: 760px) {
625
+ .usage-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
626
+ }
627
+ @container usage-overview (max-width: 420px) {
628
+ .usage-stat-grid { grid-template-columns: minmax(0, 1fr); }
629
+ }
537
630
  .product-footer { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; width: 100%; max-width: 1400px; margin: auto auto 0; padding-top: 20px; border-top: 1px solid color-mix(in srgb, var(--line) 76%, transparent); color: var(--muted); font-size: 10px; line-height: 1.5; }
538
631
  .product-footer-meta { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
539
632
  .product-footer a { color: inherit; text-decoration: none; text-underline-offset: 3px; transition: color .14s ease; }
@@ -1031,9 +1124,6 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1031
1124
  .chapter-space-marker.tab::after { content: "→"; color: color-mix(in srgb, var(--muted) 72%, transparent); font-size: .72em; line-height: 1.65; text-align: left; }
1032
1125
  .chapter-line-measure { position: absolute; z-index: -1; top: 0; left: 38px; visibility: hidden; white-space: pre-wrap; overflow-wrap: break-word; pointer-events: none; }
1033
1126
  .chapter-line-measure > div { display: block; }
1034
- .chapter-insight { margin: 14px 7% 0; padding: 13px 16px; border: 1px solid var(--line); border-left: 3px solid var(--accent); background: var(--surface-soft); color: var(--muted); font-size: 11px; line-height: 1.5; }
1035
- .chapter-insight strong { color: var(--ink); margin-right: 8px; }
1036
-
1037
1127
  .module-view { height: 100%; overflow-y: auto; padding: 42px 6%; }
1038
1128
  .module-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 18px; padding-bottom: 24px; border-bottom: 1px solid var(--line); }
1039
1129
  .module-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
@@ -1326,6 +1416,15 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1326
1416
  white-space: pre-wrap;
1327
1417
  }
1328
1418
  .task-result-readable { display: grid; gap: 10px; margin-top: 7px !important; }
1419
+ .relationship-change-preview { display: grid; gap: 10px; min-width: 0; padding: 13px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
1420
+ .relationship-change-preview > div:first-child { display: grid; gap: 3px; }
1421
+ .relationship-change-preview h4 { margin: 0; font-size: 14px; }
1422
+ .relationship-change-preview small { color: var(--muted); }
1423
+ .relationship-change-preview.is-pending { border-color: color-mix(in srgb, var(--accent) 48%, var(--line)); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
1424
+ .relationship-change-preview.is-applied { border-color: color-mix(in srgb, var(--green) 46%, var(--line)); }
1425
+ .relationship-change-preview.is-discarded { color: var(--muted); }
1426
+ .relationship-change-preview-warning { padding: 8px 10px; border-left: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); color: var(--ink); }
1427
+ .relationship-change-preview-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
1329
1428
  .task-result-section { display: grid; gap: 7px; min-width: 0; padding: 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
1330
1429
  .task-result-section h4 { margin: 0 0 2px; color: var(--ink); font-size: 13px; }
1331
1430
  .task-result-section code { overflow-wrap: anywhere; }
@@ -1369,6 +1468,29 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1369
1468
  .task-result-json-content { grid-column: 1 / -1; min-width: 0; }
1370
1469
  .task-result-json-content:empty { display: none; }
1371
1470
  .task-result-json-content textarea { width: 100%; min-height: 360px; max-height: 52vh; resize: vertical; overflow: auto; margin: 0; padding: 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface-soft); color: var(--ink); font-family: var(--font-latin), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 10px; line-height: 1.55; tab-size: 2; white-space: pre; }
1471
+ .task-detail-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 12px; }
1472
+ .task-detail-actions small { color: var(--muted); }
1473
+ .relationship-identity-repair-entry { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-top: 10px; padding: 12px; border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line)); border-radius: 6px; background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
1474
+ .relationship-identity-repair-entry > div { display: grid; gap: 4px; }
1475
+ .relationship-identity-repair-entry strong { color: var(--ink); }
1476
+ .relationship-identity-repair-entry p { margin: 0; color: var(--muted); font-size: 10px; line-height: 1.55; }
1477
+ .relationship-identity-repair-entry button, .relationship-identity-repair-entry small { flex: 0 0 auto; }
1478
+ .relationship-identity-repair-summary { display: grid; gap: 12px; padding: 15px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface-soft); }
1479
+ .relationship-identity-repair-summary > div:first-child { display: grid; gap: 4px; }
1480
+ .relationship-identity-repair-summary > div:first-child > span { color: var(--accent-dark); font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
1481
+ .relationship-identity-repair-summary h3, .relationship-identity-repair-summary p { margin: 0; }
1482
+ .relationship-identity-repair-summary h3 { color: var(--ink); font-size: 17px; }
1483
+ .relationship-identity-repair-summary p { color: var(--muted); font-size: 10px; line-height: 1.55; }
1484
+ .relationship-identity-repair-summary dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin: 0; }
1485
+ .relationship-identity-repair-summary dl > div { display: grid; gap: 2px; padding: 8px 9px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); }
1486
+ .relationship-identity-repair-summary dt { color: var(--muted); font-size: 9px; }
1487
+ .relationship-identity-repair-summary dd { margin: 0; color: var(--ink); font-family: var(--font-latin), monospace; font-size: 11px; font-weight: 700; }
1488
+ .relationship-identity-anchor-list { display: grid; gap: 6px; }
1489
+ .relationship-identity-anchor-list > strong { color: var(--ink); font-size: 10px; }
1490
+ .relationship-identity-anchor-list > div { display: flex; flex-wrap: wrap; gap: 6px; }
1491
+ .relationship-identity-anchor-list span, .relationship-identity-anchor-list em { padding: 4px 7px; border-radius: 12px; background: var(--paper-deep); color: var(--muted); font-size: 9px; font-style: normal; }
1492
+ .relationship-identity-repair-guidance { margin: 0; padding: 10px 12px; border-left: 2px solid var(--accent); background: var(--surface-soft); color: var(--muted); font-size: 10px; line-height: 1.65; }
1493
+ .relationship-identity-full-profile { justify-self: start; }
1372
1494
  .task-trace-section { display: grid; gap: 16px; min-width: 0; margin-top: 6px; }
1373
1495
  .task-trace-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; padding-top: 8px; }
1374
1496
  .task-trace-heading h3 { margin: 3px 0 0; font-size: 19px; font-weight: 600; }
@@ -1741,7 +1863,28 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1741
1863
  .book-summary-context-percent-field input, .context-compact-threshold-field input { width: 64px; min-height: 32px; padding: 5px 8px; font-size: 13px; font-family: var(--font-latin), monospace; }
1742
1864
  .config-inline-save { display: flex; align-items: flex-end; gap: 10px; margin: 14px 0 4px; flex-wrap: wrap; }
1743
1865
  .config-inline-save .book-summary-context-percent-field,
1744
- .config-inline-save .context-compact-threshold-field { display: grid; gap: 6px; width: auto; margin: 0; color: var(--muted); font-size: 10px; }
1866
+ .config-inline-save .context-compact-threshold-field { display: grid; gap: 6px; width: 64px; margin: 0; color: var(--muted); font-size: 10px; }
1867
+ .relationship-index-summary { display: grid; gap: 14px; padding: 15px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-soft); }
1868
+ .relationship-index-state-row { display: flex; align-items: center; gap: 12px 18px; flex-wrap: wrap; color: var(--muted); font-size: 10px; }
1869
+ .relationship-index-state-row strong { color: var(--ink); font-family: var(--font-latin), monospace; font-weight: 600; }
1870
+ .relationship-index-state { display: inline-flex; align-items: center; min-height: 23px; padding: 3px 9px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--muted); font-size: 10px; font-weight: 650; }
1871
+ .relationship-index-state.is-ready { border-color: color-mix(in srgb, var(--green) 42%, var(--line)); background: color-mix(in srgb, var(--green) 9%, var(--surface)); color: var(--green); }
1872
+ .relationship-index-state.is-building { border-color: color-mix(in srgb, var(--task-running) 45%, var(--line)); background: color-mix(in srgb, var(--task-running) 9%, var(--surface)); color: var(--task-running); }
1873
+ .relationship-index-state.is-queued { border-color: color-mix(in srgb, var(--accent) 38%, var(--line)); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); color: var(--accent-dark); }
1874
+ .relationship-index-state.is-failed { border-color: color-mix(in srgb, var(--accent) 60%, var(--line)); background: color-mix(in srgb, var(--accent) 12%, var(--surface)); color: var(--accent-dark); }
1875
+ .relationship-index-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0; }
1876
+ .relationship-index-metrics > div { display: grid; gap: 3px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); }
1877
+ .relationship-index-metrics dt { color: var(--muted); font-size: 9px; }
1878
+ .relationship-index-metrics dd { margin: 0; color: var(--ink); font-family: var(--font-latin), monospace; font-size: 18px; font-weight: 650; line-height: 1.2; }
1879
+ .relationship-index-queue { display: grid; gap: 8px; }
1880
+ .relationship-index-queue-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }
1881
+ .relationship-index-queue-heading strong { font-size: 11px; font-weight: 600; }
1882
+ .relationship-index-queue-heading span, .relationship-index-queue-empty { color: var(--muted); font-size: 9px; }
1883
+ .relationship-index-queue-list { display: flex; align-items: center; gap: 6px; min-height: 27px; flex-wrap: wrap; }
1884
+ .relationship-index-queue-chip { display: inline-flex; align-items: center; gap: 7px; min-height: 25px; padding: 3px 4px 3px 8px; border: 1px solid var(--line); border-radius: 13px; background: var(--surface); color: var(--muted); font-size: 9px; }
1885
+ .relationship-index-queue-chip strong { display: inline-grid; min-width: 18px; height: 18px; padding: 0 4px; place-items: center; border-radius: 9px; background: var(--paper-deep); color: var(--ink); font-family: var(--font-latin), monospace; font-size: 9px; }
1886
+ .relationship-index-error { margin: 0; padding: 8px 10px; border-left: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); color: var(--accent-dark); font-size: 10px; }
1887
+ .relationship-index-actions { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
1745
1888
  .config-section .config-save-button { min-height: 32px; padding: 5px 11px; font-size: 11px; }
1746
1889
  .config-section .card-actions { margin-top: 12px; }
1747
1890
  .config-section .card-actions .config-save-button { border: 1px solid var(--line); background: transparent; color: var(--ink); }
@@ -1936,6 +2079,29 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1936
2079
  .toast-input { width: 100%; min-height: 34px; padding: 7px 9px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--ink); font-size: 11px; }
1937
2080
  .toast-confirmation-actions { display: flex; justify-content: flex-end; gap: 7px; margin-top: 3px; }
1938
2081
  .toast-confirmation-actions button { min-height: 30px; padding: 6px 10px; }
2082
+ .chapter-insight-toast {
2083
+ display: grid;
2084
+ grid-template-rows: auto minmax(0, 1fr);
2085
+ width: min(520px, calc(100vw - 48px));
2086
+ max-width: none;
2087
+ max-height: min(56dvh, 420px);
2088
+ padding: 0;
2089
+ overflow: hidden;
2090
+ border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
2091
+ background: var(--panel);
2092
+ color: var(--ink);
2093
+ pointer-events: auto;
2094
+ }
2095
+ .chapter-insight-toast-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 11px 12px 10px 14px; border-bottom: 1px solid var(--line); }
2096
+ .chapter-insight-toast-heading { display: flex; min-width: 0; align-items: center; gap: 8px; }
2097
+ .chapter-insight-toast-heading strong { font-size: 12px; }
2098
+ .chapter-insight-toast-heading span { overflow: hidden; color: var(--accent-dark); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; }
2099
+ .chapter-insight-toast-close { flex: 0 0 auto; min-height: 28px; padding: 5px 9px; font-size: 10px; }
2100
+ .chapter-insight-toast-body { display: grid; gap: 10px; min-height: 0; padding: 12px 14px 14px; overflow-y: auto; color: var(--muted); font-size: 11px; line-height: 1.6; overscroll-behavior: contain; }
2101
+ .chapter-insight-toast-body p { margin: 0; white-space: pre-wrap; }
2102
+ .chapter-insight-toast-detail { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px; padding-top: 9px; border-top: 1px solid var(--line); }
2103
+ .chapter-insight-toast-detail strong { color: var(--ink); font-size: 10px; }
2104
+ .chapter-insight-toast-empty { color: var(--muted); }
1939
2105
  .chapter-type-menu { position: fixed; z-index: 80; width: 176px; padding: 10px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); box-shadow: 0 14px 38px rgba(49,42,32,.22); }
1940
2106
  .chapter-type-menu strong { display: block; overflow: hidden; margin: 0 2px 8px; color: var(--muted); font-size: 9px; text-overflow: ellipsis; white-space: nowrap; }
1941
2107
  .chapter-type-menu > div { display: grid; gap: 3px; }
@@ -1978,6 +2144,28 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1978
2144
  .dialog-fields label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; }
1979
2145
  .dialog-fields input, .dialog-fields textarea, .dialog-fields select { width: 100%; padding: 9px 10px; font-size: 13px; }
1980
2146
  .dialog-fields textarea { resize: vertical; min-height: 90px; line-height: 1.6; }
2147
+ .background-task-dialog { width: min(860px, 94vw); }
2148
+ .background-task-content { display: grid; gap: 16px; max-height: 64vh; overflow-y: auto; padding: 20px 24px; }
2149
+ .background-task-section { display: grid; gap: 12px; min-width: 0; padding: 15px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-soft); }
2150
+ .background-task-section-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
2151
+ .background-task-section-heading > div:first-child { display: grid; gap: 4px; }
2152
+ .background-task-section-heading strong { font-size: 13px; }
2153
+ .background-task-section-heading small { color: var(--muted); font-size: 10px; }
2154
+ .background-index-actions { display: flex; gap: 7px; flex-wrap: wrap; justify-content: flex-end; }
2155
+ .background-index-actions button { min-height: 32px; padding: 6px 10px; font-size: 10px; }
2156
+ .background-task-list { display: grid; gap: 7px; }
2157
+ .background-task-row { display: grid; grid-template-columns: 104px minmax(0, 1fr) 42px auto; align-items: center; gap: 10px; padding: 10px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); }
2158
+ .background-task-row > div { display: grid; min-width: 0; gap: 4px; }
2159
+ .background-task-row > div strong, .background-task-row > div small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2160
+ .background-task-row > div strong { font-size: 11px; }
2161
+ .background-task-row > div small { color: var(--muted); font-size: 9px; }
2162
+ .background-task-row .task-status-badge { min-height: 24px; padding: 3px 8px; font-size: 9px; }
2163
+ .background-task-row .ghost-button { min-height: 30px; padding: 5px 9px; font-size: 10px; }
2164
+ .background-task-progress { color: var(--muted); font-family: var(--font-latin), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 10px; text-align: right; }
2165
+ .background-task-empty, .background-task-error { margin: 0; padding: 12px; color: var(--muted); font-size: 10px; text-align: center; }
2166
+ .background-task-error { border-left: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); color: var(--accent-dark); text-align: left; }
2167
+ .background-task-section .relationship-index-summary { padding: 12px; background: var(--surface); }
2168
+ .background-task-actions #background-task-open-analysis { margin-right: auto; }
1981
2169
  .merge-dialog-note { margin: 0; padding: 10px 12px; border-left: 2px solid var(--accent); background: var(--surface-soft); color: var(--muted); font-size: 11px; line-height: 1.6; }
1982
2170
  .form-field { display: grid; gap: 6px; color: var(--muted); font-size: 11px; }
1983
2171
  .analysis-type-description { margin: 0; color: var(--muted); font-size: 10px; line-height: 1.55; }
@@ -2014,6 +2202,25 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2014
2202
  .relationship-overwrite-card .checkbox-field { color: var(--ink); font-size: 11px; font-weight: 600; }
2015
2203
  .relationship-overwrite-card > p { margin: 0 0 0 25px; color: var(--muted); font-size: 10px; line-height: 1.55; }
2016
2204
  .relationship-overwrite-card:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 62%, var(--line)); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
2205
+ .relationship-source-preview-card { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-soft); }
2206
+ .relationship-source-preview-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
2207
+ .relationship-source-preview-header > div { display: grid; gap: 4px; }
2208
+ .relationship-source-preview-header strong { color: var(--ink); font-size: 11px; }
2209
+ .relationship-source-preview-header p { margin: 0; color: var(--muted); font-size: 10px; line-height: 1.55; }
2210
+ .relationship-source-preview-header button { flex: 0 0 auto; padding: 7px 10px; font-size: 10px; }
2211
+ .relationship-source-preview-content { display: grid; gap: 9px; color: var(--muted); font-size: 10px; line-height: 1.5; }
2212
+ .relationship-source-preview-content.is-loading { color: var(--accent-dark); }
2213
+ .relationship-source-preview-summary { display: flex; flex-wrap: wrap; gap: 6px 10px; padding-top: 8px; border-top: 1px solid var(--line); }
2214
+ .relationship-source-preview-summary strong { color: var(--ink); }
2215
+ .relationship-source-preview-list { display: grid; gap: 6px; max-height: 240px; overflow-y: auto; padding-right: 3px; }
2216
+ .dialog-fields .relationship-source-preview-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 8px; padding: 8px 9px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); cursor: pointer; }
2217
+ .dialog-fields .relationship-source-preview-row input { width: 15px; height: 15px; margin: 0; }
2218
+ .relationship-source-preview-main { display: grid; gap: 2px; min-width: 0; }
2219
+ .relationship-source-preview-main strong { overflow: hidden; color: var(--ink); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
2220
+ .relationship-source-preview-main small { color: var(--muted); font-size: 9px; }
2221
+ .relationship-source-preview-match { padding: 2px 6px; border-radius: 10px; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent-dark); font-size: 8px; white-space: nowrap; }
2222
+ .relationship-source-preview-match.is-fuzzy { background: color-mix(in srgb, var(--warning, #a56f19) 12%, transparent); color: var(--warning, #8b5c10); }
2223
+ .relationship-source-preview-empty { margin: 0; padding: 9px; border: 1px dashed var(--line); border-radius: 4px; }
2017
2224
  .model-temperature-hint { margin: 0; color: var(--accent-dark); font-size: 10px; line-height: 1.55; }
2018
2225
  .item-list-rows { display: grid; gap: 7px; }
2019
2226
  .item-list-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px; }
@@ -2115,6 +2322,18 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2115
2322
  .import-mode-permission { color: var(--accent-dark); font-size: 9px; line-height: 1.55; }
2116
2323
  .import-mode-dialog .primary-button:disabled { cursor: not-allowed; opacity: .42; }
2117
2324
  @media (max-width: 560px) {
2325
+ .background-task-content { max-height: 68vh; padding: 14px 16px; }
2326
+ .background-task-section { padding: 12px; }
2327
+ .background-task-section-heading { align-items: stretch; flex-direction: column; }
2328
+ .background-index-actions { justify-content: stretch; }
2329
+ .background-index-actions button { flex: 1 1 130px; }
2330
+ .background-task-row { grid-template-columns: minmax(0, 1fr) auto; }
2331
+ .background-task-row .task-status-badge { grid-column: 1; width: fit-content; }
2332
+ .background-task-row > div { grid-column: 1; grid-row: 2; }
2333
+ .background-task-progress { grid-column: 2; grid-row: 1; }
2334
+ .background-task-row .ghost-button { grid-column: 2; grid-row: 2; }
2335
+ .background-task-section .relationship-index-metrics { grid-template-columns: 1fr; }
2336
+ .background-task-actions #background-task-open-analysis { margin-right: 0; }
2118
2337
  .import-mode-options { grid-template-columns: 1fr; }
2119
2338
  .import-mode-dialog .dialog-actions { flex-wrap: wrap; }
2120
2339
  .character-filter-toolbar { grid-template-columns: minmax(0, 1fr); }
@@ -2407,6 +2626,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2407
2626
  .task-auto-run-progress-ring { display: none; }
2408
2627
  .task-auto-run-progress-bar-layout { display: grid; gap: 6px; width: 100%; }
2409
2628
  .settings-hub-grid { grid-template-columns: 1fr; }
2629
+ .usage-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
2410
2630
  .settings-layout-toolbar, .module-layout-toolbar { justify-content: stretch; }
2411
2631
  .settings-layout-toggle, .module-layout-toggle { width: 100%; }
2412
2632
  .settings-layout-toggle button, .module-layout-toggle button { flex: 1; }
@@ -2460,6 +2680,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2460
2680
  .avatar-crop-side { grid-template-columns: auto 1fr; align-items: center; justify-items: start; gap: 10px; padding-top: 0; }
2461
2681
  .avatar-crop-preview { width: 64px; height: 64px; }
2462
2682
  .account-settings-form .primary-button { width: 100%; }
2683
+ .usage-stat-grid { grid-template-columns: minmax(0, 1fr); }
2684
+ .usage-stat { min-height: 104px; }
2463
2685
  }
2464
2686
 
2465
2687
  /* 移动端工作台:仅在窄屏覆盖桌面三栏布局,保留桌面端原有尺寸与排列。 */
@@ -2622,8 +2844,6 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2622
2844
  .chapter-line-numbers { width: 32px; font-size: 11px; }
2623
2845
  .chapter-editor-frame { grid-template-columns: 32px minmax(0, 1fr); }
2624
2846
  .chapter-line-measure { left: 32px; }
2625
- .chapter-insight { margin: 10px var(--mobile-gutter) 0; }
2626
-
2627
2847
  .module-view { padding: 26px var(--mobile-gutter) 46px; }
2628
2848
  .module-header { padding-bottom: 18px; }
2629
2849
  .module-header h1 { font-size: 22px; }
@@ -14,9 +14,9 @@
14
14
  // 会话恢复期间按目标路由预显示对应视图的骨架屏
15
15
  const pendingView = ["editor", "module", "welcome"].includes(routeView) && routeParams.get("work")
16
16
  ? routeView
17
- : ["settings", "platform-ai"].includes(routeView) ? routeView : "shelf";
17
+ : ["settings", "platform-ai", "platform-usage"].includes(routeView) ? routeView : "shelf";
18
18
  document.documentElement.dataset.pendingView = pendingView;
19
- if (["shelf", "settings", "platform-ai"].includes(pendingView)) {
19
+ if (["shelf", "settings", "platform-ai", "platform-usage"].includes(pendingView)) {
20
20
  document.documentElement.classList.add("pending-shelf-mode");
21
21
  }
22
22
  }