@musnows/scriverse 0.4.0 → 0.4.2

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.
@@ -19,6 +19,39 @@
19
19
  --toast-fg: #fffefa;
20
20
  --toast-error-bg: #6e2e21;
21
21
  --toast-error-fg: #fffefa;
22
+ --relationship-card-border: #d9dfe8;
23
+ --relationship-card-surface: #f4f6fa;
24
+ --relationship-toolbar-surface: #f8fafc;
25
+ --relationship-toolbar-ink: #28364c;
26
+ --relationship-toolbar-muted: #6b7890;
27
+ --relationship-control-border: #cdd6e4;
28
+ --relationship-control-ink: #53627a;
29
+ --relationship-control-hover-border: #9dacbf;
30
+ --relationship-control-hover-surface: #e8edf4;
31
+ --relationship-control-hover-ink: #27364e;
32
+ --relationship-network-surface: #eef2f7;
33
+ --relationship-edge: rgba(76,93,120,.34);
34
+ --relationship-edge-directed: rgba(70,88,117,.58);
35
+ --relationship-edge-pending: rgba(107,121,145,.5);
36
+ --relationship-edge-highlight: rgba(45,80,133,.78);
37
+ --relationship-edge-selected: rgba(38,69,118,.9);
38
+ --relationship-label-ink: rgba(40,52,73,.9);
39
+ --relationship-label-stroke: #eef2f7;
40
+ --relationship-node-ink: rgba(36,51,74,.9);
41
+ --relationship-node-label: rgba(48,62,86,.88);
42
+ --relationship-node-label-active: rgba(24,44,71,.98);
43
+ --relationship-node-text-shadow: 0 1px 2px rgba(255,255,255,.72);
44
+ --relationship-node-hover-shadow: 0 0 10px rgba(91,124,166,.28), 0 0 18px var(--node-glow, rgba(139,144,153,.4));
45
+ --relationship-node-selected-shadow: 0 0 10px rgba(91,124,166,.34), 0 0 20px var(--node-glow, rgba(139,144,153,.46));
46
+ --relationship-node-endpoint-shadow: 0 0 10px rgba(91,124,166,.3), 0 0 18px var(--node-glow, rgba(139,144,153,.4));
47
+ --relationship-node-dragging-shadow: 0 0 10px rgba(91,124,166,.38), 0 0 18px var(--node-glow, rgba(139,144,153,.46));
48
+ --relationship-focus: #61708a;
49
+ --relationship-focus-strong: #31445e;
50
+ --relationship-focus-muted: #78869a;
51
+ --relationship-detail-border: #c9d3e1;
52
+ --relationship-detail-surface: rgba(248,250,253,.96);
53
+ --relationship-detail-ink: #2b3a52;
54
+ --relationship-detail-muted: #67758c;
22
55
  --font-latin: "SFMono-Regular", "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono";
23
56
  --font-cjk: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Heiti SC";
24
57
  --editor-font-size: 17px;
@@ -51,9 +84,9 @@
51
84
  .pending-shelf-mode .auth-pending .topbar { grid-template-columns: 280px 1fr auto; }
52
85
  .pending-shelf-mode .auth-pending .left-panel, .pending-shelf-mode .auth-pending .ai-panel { display: none; }
53
86
  .pending-shelf-mode .auth-pending .main-panel { grid-column: 1 / -1; }
54
- .auth-view { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; align-content: safe center; padding: 24px; overflow-y: auto; overscroll-behavior: contain; background: radial-gradient(circle at 18% 16%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 34%), var(--paper); }
87
+ .auth-view { position: fixed; inset: 0; z-index: 1000; display: grid; grid-template-rows: minmax(min-content, 1fr) auto; gap: 18px; place-items: center; padding: 24px; overflow-y: auto; overscroll-behavior: contain; background: radial-gradient(circle at 18% 16%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 34%), var(--paper); }
55
88
  .auth-view.hidden { display: none; }
56
- .auth-card { box-sizing: border-box; width: min(440px, 100%); padding: 34px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); }
89
+ .auth-card { align-self: center; box-sizing: border-box; width: min(440px, 100%); padding: 34px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); }
57
90
  .auth-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 34px; }
58
91
  .auth-brand div { display: grid; }
59
92
  .auth-brand small { color: var(--muted); }
@@ -185,6 +218,7 @@
185
218
  .auth-captcha-image img[hidden], .auth-captcha-placeholder[hidden] { display: none; }
186
219
  .auth-captcha-placeholder { color: var(--muted); font-size: 13px; padding: 0 14px; white-space: nowrap; }
187
220
  .auth-captcha-hint { margin: -8px 0 0; color: var(--muted); font-size: 12px; line-height: 1.4; }
221
+ .auth-security-hint { margin: -8px 0 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
188
222
  .auth-error { min-height: 20px; margin: 14px 0 0 !important; color: var(--accent-dark) !important; }
189
223
 
190
224
  :root[data-theme="dark"] {
@@ -208,6 +242,39 @@
208
242
  --toast-fg: #171714;
209
243
  --toast-error-bg: #e08a72;
210
244
  --toast-error-fg: #171714;
245
+ --relationship-card-border: #1c1c24;
246
+ --relationship-card-surface: #12121a;
247
+ --relationship-toolbar-surface: #12121a;
248
+ --relationship-toolbar-ink: #e8e8ef;
249
+ --relationship-toolbar-muted: #7a7a88;
250
+ --relationship-control-border: #2a2a36;
251
+ --relationship-control-ink: #a8a8b4;
252
+ --relationship-control-hover-border: #4a4a58;
253
+ --relationship-control-hover-surface: #1a1a24;
254
+ --relationship-control-hover-ink: #f0f0f5;
255
+ --relationship-network-surface: #12121a;
256
+ --relationship-edge: rgba(255,255,255,.26);
257
+ --relationship-edge-directed: rgba(214,218,232,.5);
258
+ --relationship-edge-pending: rgba(255,255,255,.18);
259
+ --relationship-edge-highlight: rgba(255,255,255,.72);
260
+ --relationship-edge-selected: rgba(220,220,235,.88);
261
+ --relationship-label-ink: rgba(230,230,240,.88);
262
+ --relationship-label-stroke: #12121a;
263
+ --relationship-node-ink: rgba(245,245,250,.88);
264
+ --relationship-node-label: rgba(235,235,245,.78);
265
+ --relationship-node-label-active: rgba(255,255,255,.95);
266
+ --relationship-node-text-shadow: 0 1px 2px rgba(0,0,0,.65);
267
+ --relationship-node-hover-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
268
+ --relationship-node-selected-shadow: 0 0 10px rgba(255,255,255,.55), 0 0 20px var(--node-glow, rgba(139,144,153,.6));
269
+ --relationship-node-endpoint-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
270
+ --relationship-node-dragging-shadow: 0 0 10px rgba(255,255,255,.6), 0 0 18px var(--node-glow, rgba(139,144,153,.6));
271
+ --relationship-focus: #7a7a88;
272
+ --relationship-focus-strong: #c8c8d4;
273
+ --relationship-focus-muted: #6a6a78;
274
+ --relationship-detail-border: #2a2a36;
275
+ --relationship-detail-surface: rgba(18,18,26,.94);
276
+ --relationship-detail-ink: #e2e2ea;
277
+ --relationship-detail-muted: #9a9aa8;
211
278
  color-scheme: dark;
212
279
  }
213
280
 
@@ -291,8 +358,11 @@ button { cursor: pointer; }
291
358
  .user-avatar-fallback { display: grid; width: 100%; height: 100%; place-items: center; }
292
359
  .account-button > .account-avatar { width: 26px; height: 26px; font-size: 11px; }
293
360
  .account-button > span:last-child { max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }
294
- .account-menu { position: absolute; z-index: 80; top: 48px; right: 84px; display: grid; min-width: 180px; gap: 4px; padding: 12px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface); box-shadow: var(--shadow); }
361
+ .account-menu { position: absolute; z-index: 80; top: 48px; right: 84px; display: grid; width: 180px; min-width: 0; gap: 4px; padding: 12px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface); box-shadow: var(--shadow); }
295
362
  .account-menu.hidden { display: none; }
363
+ .account-menu-name { display: grid; min-width: 0; gap: 2px; }
364
+ .account-menu-name > span { overflow-wrap: anywhere; }
365
+ .account-menu-username { color: var(--muted); font-size: 10px; font-weight: 500; }
296
366
  .account-menu small { margin-bottom: 8px; color: var(--muted); }
297
367
  .account-menu button { min-height: 30px; padding: 6px 9px; border: 1px solid var(--line); border-radius: 4px; background: transparent; color: var(--muted); text-align: left; font-size: 10px; }
298
368
  .account-menu button:hover, .account-menu button:focus-visible { border-color: var(--accent); background: var(--paper-deep); color: var(--accent-dark); outline: none; }
@@ -378,11 +448,13 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
378
448
  .app-shell.shelf-mode .save-state { display: none; }
379
449
  .app-shell.shelf-mode .main-panel { grid-column: 1 / -1; }
380
450
 
381
- .shelf-view { height: 100%; overflow-y: auto; padding: 48px clamp(32px, 7vw, 110px) 90px; }
451
+ .shelf-view { display: flex; flex-direction: column; height: 100%; overflow-y: auto; padding: 48px clamp(32px, 7vw, 110px) 90px; }
452
+ #shelf-view, #settings-hub-view { padding-bottom: 24px; }
382
453
  .shelf-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 30px; max-width: 1400px; margin: 0 auto 38px; }
383
454
  .shelf-header h1 { margin: 0 0 10px; font-size: clamp(30px, 4vw, 52px); font-weight: 560; letter-spacing: -.04em; }
384
455
  .shelf-header p { margin: 0; color: var(--muted); }
385
456
  .settings-hub-header { align-items: center; }
457
+ .settings-hub-header h1 { font-size: clamp(26px, 3vw, 36px); line-height: 1.15; letter-spacing: -.02em; }
386
458
  .settings-hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; max-width: 1000px; margin: 0 auto; }
387
459
  .settings-hub-card { display: grid; grid-template-columns: 48px minmax(0, 1fr); grid-template-rows: auto auto; gap: 4px 14px; align-items: center; min-height: 128px; padding: 22px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface-soft); text-align: left; }
388
460
  .settings-hub-card:hover, .settings-hub-card:focus-visible { border-color: var(--accent); background: var(--paper-deep); box-shadow: var(--shadow); transform: translateY(-2px); }
@@ -391,6 +463,13 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
391
463
  .settings-hub-card strong { align-self: end; font-size: 16px; }
392
464
  .settings-hub-card small { align-self: start; color: var(--muted); font-size: 10px; line-height: 1.5; }
393
465
  .settings-work-note { max-width: 1000px; margin: 18px auto 0; color: var(--muted); font-size: 11px; }
466
+ .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; }
467
+ .product-footer-meta { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
468
+ .product-footer a { color: inherit; text-decoration: none; text-underline-offset: 3px; transition: color .14s ease; }
469
+ .product-footer a:hover, .product-footer a:focus-visible { color: var(--accent-dark); text-decoration: underline; }
470
+ .product-footer-development { padding: 2px 8px; border: 1px solid color-mix(in srgb, var(--accent) 48%, var(--line)); border-radius: 999px; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent-dark); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 9px; font-weight: 700; letter-spacing: .05em; }
471
+ .auth-product-footer { align-self: end; max-width: 440px; margin: 0; padding-top: 14px; }
472
+ .settings-product-footer { max-width: 1000px; }
394
473
  .access-dialog-body { display: grid; gap: 16px; max-height: calc(88vh - 82px); overflow-y: auto; padding: 18px 24px 22px; }
395
474
  .access-list { display: grid; gap: 8px; max-height: min(34vh, 340px); overflow: auto; padding: 0; }
396
475
  .access-row {
@@ -500,6 +579,7 @@ body.work-viewer-mode [data-edit-event],
500
579
  body.work-viewer-mode [data-split-event],
501
580
  body.work-viewer-mode [data-event-select],
502
581
  body.work-viewer-mode #create-timeline-track,
582
+ body.work-viewer-mode #timeline-multi-select-toggle,
503
583
  body.work-viewer-mode #merge-events,
504
584
  body.work-viewer-mode [data-edit-foreshadow],
505
585
  body.work-viewer-mode [data-edit-outline],
@@ -618,7 +698,7 @@ body.work-viewer-mode .character-editor-actions { display: none !important; }
618
698
  .api-key-result input { width: 100%; min-height: 38px; padding: 9px 10px; background: var(--surface); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 11px; }
619
699
  .api-key-result button { min-height: 38px; }
620
700
  .book-access-badge { display: inline-flex; width: fit-content; margin-top: 7px; padding: 2px 7px; border-radius: 10px; background: var(--paper-deep); color: var(--accent-dark); font-size: 9px; }
621
- .book-shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(205px, 1fr)); gap: clamp(22px, 3vw, 38px); max-width: 1400px; margin: 0 auto; }
701
+ .book-shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(205px, 1fr)); gap: clamp(22px, 3vw, 38px); width: 100%; min-width: 0; max-width: 1400px; margin: 0 auto; }
622
702
  .book-card { position: relative; min-width: 0; border: 0; background: transparent; text-align: left; }
623
703
  .book-open { width: 100%; padding: 0; border: 0; background: transparent; text-align: left; }
624
704
  .book-cover { position: relative; display: grid; place-items: center; aspect-ratio: 3 / 4.25; overflow: hidden; border-radius: 8px 13px 13px 8px; background: linear-gradient(145deg, #a96350, #612d27); color: rgba(255,255,255,.9); box-shadow: 0 20px 34px rgba(62,39,29,.18), inset 9px 0 0 rgba(0,0,0,.08); transition: transform .2s ease, box-shadow .2s ease; }
@@ -719,7 +799,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
719
799
  .module-nav .nav-icon { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
720
800
  #module-more-button[aria-expanded="true"] .nav-icon { transform: rotate(180deg); }
721
801
  .module-nav button.active, .module-nav button:hover { background: var(--paper-deep); color: var(--ink); }
722
- .module-nav .ai-analysis-entry { background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent-dark); font-weight: 650; }
802
+ .module-nav .ai-analysis-entry,
803
+ .module-nav .ai-analysis-entry:hover,
804
+ .module-nav .ai-analysis-entry.active { background: transparent; color: var(--accent-dark); font-weight: 650; }
723
805
  #module-more-button { grid-column: 1 / -1; color: var(--accent-dark); text-align: center; }
724
806
  .panel-heading { display: flex; align-items: center; gap: 8px; padding: 15px 0 9px 7px; color: var(--muted); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }
725
807
  .panel-heading-actions { display: flex; align-items: center; gap: 7px; margin-left: auto; }
@@ -734,7 +816,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
734
816
  .chapter-add-button { flex: none; }
735
817
  .volume-chapters { display: block; }
736
818
  .volume-node.is-collapsed .volume-chapters { display: none; }
737
- .chapter-node { display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 8px; width: 100%; padding: 9px 10px 9px 20px; border: 0; background: transparent; border-radius: 4px; text-align: left; font-size: 12px; }
819
+ .chapter-node { display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 8px; width: 100%; padding: 9px 0 9px 20px; border: 0; background: transparent; border-radius: 4px; text-align: left; font-size: 12px; }
738
820
  .chapter-node:hover, .chapter-node.active { background: var(--row-active); }
739
821
  .chapter-node.active { color: var(--accent-dark); font-weight: 700; }
740
822
  .chapter-node > span:first-child { min-width: 0; overflow-wrap: anywhere; line-height: 1.45; white-space: normal; }
@@ -797,19 +879,26 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
797
879
  .chapter-insight strong { color: var(--ink); margin-right: 8px; }
798
880
 
799
881
  .module-view { height: 100%; overflow-y: auto; padding: 42px 6%; }
800
- .module-header { display: flex; justify-content: space-between; align-items: flex-end; padding-bottom: 24px; border-bottom: 1px solid var(--line); }
882
+ .module-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 18px; padding-bottom: 24px; border-bottom: 1px solid var(--line); }
883
+ .module-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
884
+ .module-header-actions > [data-module-header-action] { order: 1; }
885
+ .module-header-actions > #module-create-button { order: 2; min-height: 36px; }
801
886
  .module-header h1 { margin: 0 0 8px; font-weight: 500; font-size: 34px; }
802
887
  .module-header p { margin: 0; color: var(--muted); font-size: 13px; }
803
888
  .module-content { padding: 24px 0 80px; }
804
889
  .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 13px; }
805
890
  .record-card { position: relative; border: 1px solid var(--line); background: var(--surface-soft); padding: 18px; min-height: 130px; border-radius: 4px; }
891
+ .record-card.has-card-edit h3 { padding-right: 34px; }
892
+ .record-card-edit { position: absolute; top: 12px; right: 12px; display: inline-grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 1px solid var(--line); border-radius: 4px; background: transparent; color: var(--muted); }
893
+ .record-card-edit:hover, .record-card-edit:focus-visible { border-color: var(--accent); color: var(--accent-dark); outline: none; }
894
+ .record-card-edit svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
806
895
  .record-card h3 { font-size: 16px; margin: 5px 0 10px; font-weight: 600; }
807
896
  .record-card p { color: var(--muted); font-size: 12px; line-height: 1.55; margin: 0; white-space: pre-wrap; }
808
897
  .record-card small { color: var(--accent); font-size: 9px; letter-spacing: .1em; text-transform: uppercase; }
809
- .settings-layout-toolbar, .module-layout-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-bottom: 14px; }
898
+ .settings-layout-toolbar, .module-layout-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-bottom: 0; }
810
899
  .settings-layout-hint, .module-layout-hint { color: var(--muted); font-size: 10px; }
811
900
  .settings-layout-toggle, .module-layout-toggle { display: inline-flex; border: 1px solid var(--line); border-radius: 4px; overflow: hidden; background: var(--surface); }
812
- .settings-layout-toggle button, .module-layout-toggle button { min-height: 30px; padding: 0 12px; border: 0; border-right: 1px solid var(--line); background: transparent; color: var(--muted); font-size: 11px; }
901
+ .settings-layout-toggle button, .module-layout-toggle button { min-height: 34px; padding: 0 12px; border: 0; border-right: 1px solid var(--line); background: transparent; color: var(--muted); font-size: 11px; }
813
902
  .settings-layout-toggle button:last-child, .module-layout-toggle button:last-child { border-right: 0; }
814
903
  .settings-layout-toggle button:hover, .settings-layout-toggle button:focus-visible,
815
904
  .module-layout-toggle button:hover, .module-layout-toggle button:focus-visible { color: var(--ink); background: var(--paper-deep); }
@@ -840,6 +929,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
840
929
  .character-duplicate-actions { flex-wrap: wrap; }
841
930
  .card-actions { display: flex; gap: 6px; margin-top: 15px; }
842
931
  .card-actions button { border: 1px solid var(--line); background: transparent; border-radius: 3px; font-size: 10px; padding: 5px 8px; }
932
+ .danger-button { border: 1px solid color-mix(in srgb, var(--accent) 52%, var(--line)); border-radius: 4px; background: transparent; color: var(--accent-dark); padding: 8px 13px; font-size: 12px; }
933
+ .danger-button:hover, .danger-button:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); outline: none; }
843
934
  .card-actions .danger-button { border-color: color-mix(in srgb, var(--accent) 52%, var(--line)); color: var(--accent-dark); }
844
935
  .card-actions .danger-button:hover, .card-actions .danger-button:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); }
845
936
  .card-actions .primary-button { border-color: var(--accent); background: var(--accent); color: #fff; padding: 8px 13px; font-size: 12px; }
@@ -867,6 +958,17 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
867
958
  .race-settings .pill { display: inline-flex; align-items: center; gap: 5px; }
868
959
  .race-settings .pill small { color: inherit; font-size: 8px; letter-spacing: 0; text-transform: none; opacity: .72; }
869
960
  .race-settings .pill.inherited { border-style: dashed; }
961
+ .entity-dialog-management, .entity-editor-management { display: grid; gap: 10px; padding: 14px; border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--line)); border-radius: 5px; background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
962
+ .entity-dialog-management > div:first-child, .entity-editor-management > div:first-child { display: grid; gap: 4px; }
963
+ .entity-dialog-management strong, .entity-editor-management strong { color: var(--ink); font-size: 11px; }
964
+ .entity-dialog-management small, .entity-editor-management small { color: var(--muted); font-size: 10px; line-height: 1.5; }
965
+ .entity-dialog-management-actions, .entity-editor-management-actions { display: flex; flex-wrap: wrap; gap: 7px; }
966
+ .entity-dialog-management-actions button, .entity-editor-management-actions button { min-height: 32px; }
967
+ .danger-confirm-field { display: grid !important; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 9px !important; padding: 12px; border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line)); border-radius: 5px; background: color-mix(in srgb, var(--accent) 5%, var(--surface)); }
968
+ .danger-confirm-field input { width: auto !important; margin-top: 3px; }
969
+ .danger-confirm-field span { display: grid; gap: 4px; }
970
+ .danger-confirm-field strong { color: var(--ink); font-size: 11px; }
971
+ .danger-confirm-field small { color: var(--muted); font-size: 10px; line-height: 1.5; }
870
972
  .config-section { margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line); }
871
973
  .config-section:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
872
974
  .platform-system-prompt-section { margin-bottom: 36px; }
@@ -940,7 +1042,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
940
1042
  .table-list th, .table-list td { padding: 12px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
941
1043
  .table-list th { color: var(--muted); font-weight: 400; font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }
942
1044
  .danger-text { color: var(--accent); }
943
- .timeline-tools { display: flex; justify-content: flex-end; gap: 8px; margin-bottom: 12px; }
1045
+ .timeline-tools { display: flex; justify-content: flex-end; gap: 8px; }
944
1046
  .timeline-select { position: absolute; left: -33px; top: 0; }
945
1047
  .timeline-kanban { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(290px, 340px); gap: 14px; align-items: start; overflow-x: auto; padding: 3px 2px 18px; scroll-snap-type: x proximity; }
946
1048
  .timeline-lane { display: flex; max-height: calc(100vh - 250px); min-height: 420px; flex-direction: column; overflow: hidden; border: 1px solid var(--line); border-radius: 7px; background: color-mix(in srgb, var(--paper-deep) 42%, transparent); scroll-snap-align: start; }
@@ -999,12 +1101,12 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
999
1101
  .relationship-map-expanded-host .relationship-map-card { height: 100%; margin: 0; }
1000
1102
  .relationship-map-expanded-host .relationship-map-toolbar { padding-right: 72px; }
1001
1103
  .relationship-map-expanded-host .relationship-mindmap { height: calc(100% - 67px); min-height: 0; }
1002
- .relationship-network-card { border-color: #1c1c24; background: #12121a; box-shadow: none; }
1003
- .relationship-network-card .relationship-map-toolbar { min-height: 58px; border-color: #1c1c24; background: #12121a; color: #e8e8ef; }
1004
- .relationship-network-card .relationship-map-toolbar small { color: #7a7a88; }
1005
- .relationship-network-card .relationship-map-actions button { border-color: #2a2a36; background: transparent; color: #a8a8b4; }
1006
- .relationship-network-card .relationship-map-actions button:hover, .relationship-network-card .relationship-map-actions button:focus-visible { border-color: #4a4a58; background: #1a1a24; color: #f0f0f5; }
1007
- .relationship-network { height: min(68vh, 650px); min-height: 520px; contain: layout paint style; touch-action: none; cursor: grab; background: #12121a; }
1104
+ .relationship-network-card { border-color: var(--relationship-card-border); background: var(--relationship-card-surface); box-shadow: none; }
1105
+ .relationship-network-card .relationship-map-toolbar { min-height: 58px; border-color: var(--relationship-card-border); background: var(--relationship-toolbar-surface); color: var(--relationship-toolbar-ink); }
1106
+ .relationship-network-card .relationship-map-toolbar small { color: var(--relationship-toolbar-muted); }
1107
+ .relationship-network-card .relationship-map-actions button { border-color: var(--relationship-control-border); background: transparent; color: var(--relationship-control-ink); }
1108
+ .relationship-network-card .relationship-map-actions button:hover, .relationship-network-card .relationship-map-actions button:focus-visible { border-color: var(--relationship-control-hover-border); background: var(--relationship-control-hover-surface); color: var(--relationship-control-hover-ink); }
1109
+ .relationship-network { height: min(68vh, 650px); min-height: 520px; contain: layout paint style; touch-action: none; cursor: grab; background: var(--relationship-network-surface); }
1008
1110
  .relationship-network.is-panning { cursor: grabbing; }
1009
1111
  .relationship-network-stage { contain: layout paint style; will-change: transform; }
1010
1112
  .relationship-network-stage.is-view-animating { transition: transform .34s cubic-bezier(.22,.78,.3,1); }
@@ -1019,21 +1121,21 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1019
1121
  stroke: transparent;
1020
1122
  }
1021
1123
  .relationship-network .mind-edge,
1022
- .relationship-network .obsidian-edge { stroke: rgba(255,255,255,.26); stroke-width: 1px; opacity: 1; transition: opacity .12s ease, stroke .12s ease; }
1023
- .relationship-network .mind-edge.is-directed { stroke: rgba(214,218,232,.5); }
1124
+ .relationship-network .obsidian-edge { stroke: var(--relationship-edge); stroke-width: 1px; opacity: 1; transition: opacity .12s ease, stroke .12s ease; }
1125
+ .relationship-network .mind-edge.is-directed { stroke: var(--relationship-edge-directed); }
1024
1126
  .relationship-network .relationship-edge-arrow { pointer-events: none; }
1025
1127
  .relationship-network .mind-edge.family,
1026
1128
  .relationship-network .mind-edge.social,
1027
1129
  .relationship-network .mind-edge.emotional,
1028
1130
  .relationship-network .mind-edge.conflict,
1029
- .relationship-network .mind-edge.uncertain { stroke: rgba(255,255,255,.26); stroke-dasharray: none; }
1030
- .relationship-network .mind-edge.is-pending { stroke: rgba(255,255,255,.18); stroke-dasharray: 4 6; }
1131
+ .relationship-network .mind-edge.uncertain { stroke: var(--relationship-edge); stroke-dasharray: none; }
1132
+ .relationship-network .mind-edge.is-pending { stroke: var(--relationship-edge-pending); stroke-dasharray: 4 6; }
1031
1133
  .relationship-network .mind-edge.is-dimmed { opacity: .06; }
1032
- .relationship-network .mind-edge.is-highlighted { stroke: rgba(255,255,255,.72); stroke-width: 1.35px; opacity: 1; }
1033
- .relationship-network .mind-edge.is-edge-selected { stroke: rgba(220,220,235,.88); stroke-width: 1.6px; opacity: 1; }
1134
+ .relationship-network .mind-edge.is-highlighted { stroke: var(--relationship-edge-highlight); stroke-width: 1.35px; opacity: 1; }
1135
+ .relationship-network .mind-edge.is-edge-selected { stroke: var(--relationship-edge-selected); stroke-width: 1.6px; opacity: 1; }
1034
1136
  .relationship-network .mind-edge-label {
1035
- fill: rgba(230,230,240,.88);
1036
- stroke: #12121a;
1137
+ fill: var(--relationship-label-ink);
1138
+ stroke: var(--relationship-label-stroke);
1037
1139
  stroke-width: 2.5px;
1038
1140
  font-size: 7px;
1039
1141
  font-weight: 400;
@@ -1054,7 +1156,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1054
1156
  border: 0;
1055
1157
  border-radius: 50%;
1056
1158
  background: var(--node-color, #8b9099);
1057
- color: rgba(245,245,250,.88);
1159
+ color: var(--relationship-node-ink);
1058
1160
  box-shadow: 0 0 8px var(--node-glow, rgba(139,144,153,.42));
1059
1161
  font-family: "SF Pro Text", "Segoe UI", "Helvetica Neue", sans-serif;
1060
1162
  font-size: 9px;
@@ -1075,30 +1177,39 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1075
1177
  text-overflow: ellipsis;
1076
1178
  white-space: nowrap;
1077
1179
  pointer-events: none;
1078
- color: rgba(235,235,245,.78);
1180
+ color: var(--relationship-node-label);
1079
1181
  font-size: 9px;
1080
1182
  font-weight: 400;
1081
1183
  letter-spacing: .01em;
1082
- text-shadow: 0 1px 2px rgba(0,0,0,.65);
1184
+ text-shadow: var(--relationship-node-text-shadow);
1185
+ opacity: 0;
1186
+ transition: opacity .12s ease, color .12s ease;
1083
1187
  }
1188
+ .relationship-network .mind-node.is-label-visible span,
1189
+ .relationship-network .mind-node:hover span,
1190
+ .relationship-network .mind-node:focus-visible span,
1191
+ .relationship-network .mind-node.is-hovered span,
1192
+ .relationship-network .mind-node.is-selected span,
1193
+ .relationship-network .mind-node.is-related span,
1194
+ .relationship-network .mind-node.is-edge-endpoint span { opacity: 1; }
1084
1195
  .relationship-network .mind-node:hover,
1085
1196
  .relationship-network .mind-node:focus-visible,
1086
1197
  .relationship-network .mind-node.is-hovered {
1087
1198
  transform: translate(-50%, -50%) scale(1.28);
1088
1199
  outline: none;
1089
1200
  z-index: 6;
1090
- box-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
1201
+ box-shadow: var(--relationship-node-hover-shadow);
1091
1202
  }
1092
1203
  .relationship-network .mind-node:hover span,
1093
1204
  .relationship-network .mind-node:focus-visible span,
1094
1205
  .relationship-network .mind-node.is-hovered span,
1095
1206
  .relationship-network .mind-node.is-selected span,
1096
1207
  .relationship-network .mind-node.is-related span,
1097
- .relationship-network .mind-node.is-edge-endpoint span { color: rgba(255,255,255,.95); }
1208
+ .relationship-network .mind-node.is-edge-endpoint span { color: var(--relationship-node-label-active); }
1098
1209
  .relationship-network .mind-node.is-selected {
1099
1210
  transform: translate(-50%, -50%) scale(1.32);
1100
1211
  z-index: 5;
1101
- box-shadow: 0 0 10px rgba(255,255,255,.55), 0 0 20px var(--node-glow, rgba(139,144,153,.6));
1212
+ box-shadow: var(--relationship-node-selected-shadow);
1102
1213
  }
1103
1214
  .relationship-network .mind-node.is-related { opacity: 1; }
1104
1215
  .relationship-network .mind-node.is-dimmed { opacity: .14; box-shadow: none; }
@@ -1106,7 +1217,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1106
1217
  .relationship-network .mind-node.is-edge-endpoint {
1107
1218
  opacity: 1;
1108
1219
  transform: translate(-50%, -50%) scale(1.3);
1109
- box-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
1220
+ box-shadow: var(--relationship-node-endpoint-shadow);
1110
1221
  }
1111
1222
  .relationship-network[data-interaction="dragging"] .mind-edge,
1112
1223
  .relationship-network[data-interaction="dragging"] .mind-node,
@@ -1126,7 +1237,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1126
1237
  transition: none;
1127
1238
  z-index: 8;
1128
1239
  will-change: left, top;
1129
- box-shadow: 0 0 10px rgba(255,255,255,.6), 0 0 18px var(--node-glow, rgba(139,144,153,.6));
1240
+ box-shadow: var(--relationship-node-dragging-shadow);
1130
1241
  }
1131
1242
  .relationship-network .mind-node.is-drag-neighbor {
1132
1243
  opacity: 1;
@@ -1134,16 +1245,16 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1134
1245
  will-change: left, top;
1135
1246
  }
1136
1247
  .relationship-network .mind-node.is-settling { animation: relationship-node-settle .18s ease-out; }
1137
- .relationship-network-focus, .relationship-network-help { position: absolute; z-index: 6; color: #7a7a88; pointer-events: none; }
1248
+ .relationship-network-focus, .relationship-network-help { position: absolute; z-index: 6; color: var(--relationship-focus); pointer-events: none; }
1138
1249
  .relationship-network-focus { top: 14px; left: 16px; display: grid; gap: 3px; }
1139
- .relationship-network-focus strong { color: #c8c8d4; font-size: 10px; font-weight: 500; }
1140
- .relationship-network-focus span { color: #6a6a78; font-size: 9px; }
1250
+ .relationship-network-focus strong { color: var(--relationship-focus-strong); font-size: 10px; font-weight: 500; }
1251
+ .relationship-network-focus span { color: var(--relationship-focus-muted); font-size: 9px; }
1141
1252
  .relationship-network-help { left: 16px; bottom: 13px; font-size: 9px; }
1142
- .relationship-network .mind-edge-detail { left: 50%; right: auto; bottom: 38px; width: min(680px, calc(100% - 40px)); transform: translateX(-50%); border-color: #2a2a36; background: rgba(18,18,26,.94); color: #e2e2ea; box-shadow: none; }
1143
- .relationship-network .mind-edge-detail span { color: #9a9aa8; }
1253
+ .relationship-network .mind-edge-detail { left: 50%; right: auto; bottom: 38px; width: min(680px, calc(100% - 40px)); transform: translateX(-50%); border-color: var(--relationship-detail-border); background: var(--relationship-detail-surface); color: var(--relationship-detail-ink); box-shadow: none; }
1254
+ .relationship-network .mind-edge-detail span { color: var(--relationship-detail-muted); }
1144
1255
  .relationship-map-expanded-host .relationship-network { height: calc(100% - 63px); min-height: 0; }
1145
- .relationship-map-dialog { background: #12121a; border-color: #1c1c24; }
1146
- .relationship-map-expanded-host { background: #12121a; }
1256
+ .relationship-map-dialog { background: var(--relationship-card-surface); border-color: var(--relationship-card-border); }
1257
+ .relationship-map-expanded-host { background: var(--relationship-card-surface); }
1147
1258
  @keyframes relationship-node-settle { from { transform: translate(-50%, -50%) scale(1.36); } to { transform: translate(-50%, -50%) scale(1.32); } }
1148
1259
  @media (prefers-reduced-motion: reduce) { .relationship-network .mind-node, .relationship-network-stage { transition-duration: .01ms; animation-duration: .01ms; } }
1149
1260
 
@@ -1204,7 +1315,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1204
1315
  .field-label select { padding: 8px; font-size: 12px; }
1205
1316
  .book-summary-context-percent-field { width: min(100%, 280px); }
1206
1317
  .context-compact-threshold-field { width: min(100%, 280px); }
1207
- .book-summary-context-percent-field input, .context-compact-threshold-field input { min-height: 40px; padding: 8px 12px; font-size: 15px; font-family: var(--font-latin), monospace; }
1318
+ .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; }
1208
1319
  .field-label textarea {
1209
1320
  width: 100%;
1210
1321
  min-height: 140px;
@@ -1459,8 +1570,14 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1459
1570
  .section-list-row { grid-template-columns: minmax(0, 1fr) auto; }
1460
1571
  .section-list-row textarea { grid-column: 1 / -1; min-height: 130px; }
1461
1572
  .structured-list-row button { grid-column: -2 / -1; grid-row: 1; border: 1px solid var(--line); border-radius: 4px; padding: 0 10px; background: var(--panel); color: var(--muted); font-size: 10px; }
1462
- .character-identity { color: var(--ink) !important; font-weight: 600; }
1463
- .character-species { display: flex; align-items: center; gap: 7px; margin-top: 10px; color: var(--muted); font-size: 10px; }
1573
+ .character-card h3 { margin-bottom: 5px; }
1574
+ .character-identity { margin: 0 0 6px !important; color: var(--ink) !important; font-weight: 600; line-height: 1.55 !important; }
1575
+ .character-aliases { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; }
1576
+ .character-aliases .pill { margin: 0; }
1577
+ .character-code { display: flex; align-items: center; gap: 7px; margin-top: 10px; color: var(--muted); font-size: 10px; }
1578
+ .character-species { display: grid; grid-template-columns: max-content minmax(0, 1fr); align-items: center; gap: 6px; margin-top: 8px; color: var(--muted); font-size: 10px; }
1579
+ .character-species b { font-weight: 500; }
1580
+ .character-species .pill { justify-self: start; min-width: 0; max-width: 100%; margin: 0; overflow-wrap: anywhere; }
1464
1581
  .character-detail-list { display: grid; gap: 5px; margin: 12px 0; }
1465
1582
  .character-detail-list div { display: grid; grid-template-columns: minmax(70px, .42fr) minmax(0, 1fr); gap: 8px; font-size: 10px; }
1466
1583
  .character-detail-list dt { color: var(--muted); }
@@ -1528,7 +1645,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1528
1645
  .setting-editor-lock b { color: var(--ink); font-size: 10px; }
1529
1646
  .setting-editor-lock small { display: none; }
1530
1647
  .setting-editor-change-note { align-items: center; gap: 6px; }
1531
- .setting-editor-workspace { min-height: 0; }
1648
+ .setting-editor-workspace { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; overflow: hidden; }
1532
1649
  .setting-editor-content { height: 100%; min-height: 0; padding: 16px clamp(16px, 2vw, 32px) 24px; overflow: hidden; }
1533
1650
  .setting-markdown-field { display: grid; grid-template-rows: minmax(0, 1fr); height: 100%; min-height: 0; }
1534
1651
  .setting-markdown-heading, .markdown-editor-field-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; color: var(--ink); font-size: 14px; }
@@ -1544,7 +1661,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1544
1661
  .vditor-editor-host .vditor-reset { color: var(--ink); font-family: var(--font-cjk), var(--font-latin), sans-serif; }
1545
1662
  .vditor-editor-host .vditor-ir, .vditor-editor-host .vditor-sv, .vditor-editor-host .vditor-wysiwyg { background: var(--surface); color: var(--ink); }
1546
1663
  .vditor-editor-host .vditor-sv textarea { color: var(--ink); }
1547
- .record-markdown-preview { max-height: 260px; margin: 12px 0 8px; overflow: hidden; overflow-wrap: anywhere; color: var(--ink); font-size: 12px; line-height: 1.7; }
1664
+ .record-markdown-preview { display: -webkit-box; margin: 12px 0 8px; overflow: hidden; overflow-wrap: anywhere; color: var(--ink); font-size: 12px; line-height: 1.7; -webkit-box-orient: vertical; -webkit-line-clamp: 12; }
1548
1665
  .record-markdown-preview > :first-child, .knowledge-markdown-block .message-body > :first-child { margin-top: 0; }
1549
1666
  .record-markdown-preview > :last-child, .knowledge-markdown-block .message-body > :last-child { margin-bottom: 0; }
1550
1667
  .knowledge-markdown-block { min-width: 0; margin: 10px 0 0; padding: 11px 13px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); }
@@ -1645,6 +1762,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1645
1762
  .character-section-editor-header .entity-editor-back { grid-column: 1; grid-row: 1; z-index: 1; }
1646
1763
  .character-section-editor-header h2 { margin: 3px 0 0; font-size: 22px; font-weight: 600; }
1647
1764
  .character-markdown-editor { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 12px; min-height: 0; padding: 16px 22px 18px; overflow: hidden; background: var(--surface-soft); }
1765
+ .character-markdown-editor > .vditor-editor-host { width: 100%; max-width: 960px; justify-self: center; }
1766
+ .character-markdown-editor > .vditor-editor-host.vditor { border-color: color-mix(in srgb, var(--accent) 22%, var(--line)); box-shadow: 0 12px 34px color-mix(in srgb, var(--ink) 12%, transparent); transition: border-color .16s ease, box-shadow .16s ease; }
1767
+ .character-markdown-editor > .vditor-editor-host.vditor:focus-within { border-color: color-mix(in srgb, var(--accent) 62%, var(--line)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 15%, transparent), 0 16px 42px color-mix(in srgb, var(--ink) 16%, transparent); }
1648
1768
  .character-markdown-editor-meta { display: grid; grid-template-columns: minmax(140px, .55fr) minmax(220px, 1fr) minmax(280px, 1.45fr); gap: 12px; }
1649
1769
  .character-markdown-editor label { display: grid; gap: 6px; color: var(--muted); font-size: 10px; }
1650
1770
  .character-markdown-editor input, .character-markdown-editor select, .character-markdown-editor textarea { width: 100%; padding: 9px 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--ink); font-size: 12px; }
@@ -1686,6 +1806,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1686
1806
  .appearance-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 22px 24px; }
1687
1807
  .appearance-grid label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; }
1688
1808
  .appearance-grid select { width: 100%; padding: 9px 10px; font-size: 13px; }
1809
+ .appearance-whitespace-field { grid-column: 1 / -1; }
1689
1810
  .font-preview { grid-column: 1 / -1; padding: 16px; border: 1px solid var(--line); border-radius: 4px; background: var(--paper); }
1690
1811
  .font-preview strong, .font-preview span { display: block; }
1691
1812
  .font-preview strong { margin-bottom: 8px; font-size: 17px; }
@@ -1715,8 +1836,11 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1715
1836
  .entity-version-card > button.is-confirming { border-color: var(--accent); background: var(--accent); color: #fff; }
1716
1837
  .entity-version-card > button:disabled { cursor: default; opacity: .68; }
1717
1838
  .entity-history-empty { margin: 0; padding: 28px 12px; color: var(--muted); font-size: 11px; text-align: center; }
1718
- .relationship-table .relationship-actions { white-space: nowrap; }
1719
- .relationship-table .relationship-actions button + button { margin-left: 5px; }
1839
+ .relationship-table .relationship-actions { white-space: nowrap; vertical-align: middle; }
1840
+ .relationship-table .relationship-actions button { display: inline-block; min-height: 30px; padding: 6px 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--muted); font: inherit; font-size: 10px; line-height: 1.2; vertical-align: middle; appearance: none; transition: border-color .14s ease, background .14s ease, color .14s ease; }
1841
+ .relationship-table .relationship-actions button + button { margin-left: 6px; }
1842
+ .relationship-table .relationship-actions button:hover, .relationship-table .relationship-actions button:focus-visible { border-color: var(--accent); background: var(--surface-hover); color: var(--accent-dark); outline: none; }
1843
+ .relationship-table .relationship-actions button[data-edit-relationship] { color: var(--ink); }
1720
1844
 
1721
1845
  @media (max-width: 540px) {
1722
1846
  .member-permission-grid { grid-template-columns: minmax(0, 1fr); }
@@ -1759,7 +1883,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1759
1883
  .setting-editor-header { min-height: 102px; }
1760
1884
  .setting-editor-header-fields { flex-wrap: wrap; gap: 8px 12px; }
1761
1885
  .setting-editor-title-input { font-size: 18px; }
1762
- .setting-editor-content { min-height: 70dvh; padding: 16px; }
1886
+ .setting-editor-workspace { overflow-y: auto; }
1887
+ .setting-editor-content { height: auto; min-height: 70dvh; padding: 16px; }
1763
1888
  .setting-markdown-field { height: 70dvh; }
1764
1889
  .setting-markdown-heading, .markdown-editor-field-heading { align-items: flex-start; flex-direction: column; gap: 4px; }
1765
1890
  .setting-markdown-field > .vditor-editor-host, .markdown-editor-field .vditor-editor-host { min-height: 42dvh; }
@@ -6,7 +6,7 @@ export const WORK_PERMISSION_MODULES = Object.freeze([
6
6
  { id: "organizations", uiModule: "organizations", label: "组织" },
7
7
  { id: "timeline", uiModule: "timeline", label: "时间轴" },
8
8
  { id: "relationships", uiModule: "relationships", label: "关系" },
9
- { id: "outlines", uiModule: "outlines", label: "大纲与伏笔" },
9
+ { id: "outlines", uiModule: "outlines", label: "大纲/伏笔" },
10
10
  { id: "reviews", uiModule: "reviews", label: "审核" },
11
11
  { id: "ai-chat", uiModule: null, label: "AI 对话" },
12
12
  { id: "ai-analysis", uiModule: "tasks", label: "AI 分析" },
@@ -5,6 +5,9 @@ import { loadMasterSecret } from "./credential-vault.js";
5
5
  import { isDevelopmentAuthBypassEnabled, resolveRuntimeSecurity } from "./security.js";
6
6
  import { logger, sanitizeError } from "./logger.js";
7
7
  const publicPath = fileURLToPath(new URL("./public/", import.meta.url));
8
+ export function isDevelopmentServer(environment) {
9
+ return environment.NODE_ENV === "development" || environment.npm_lifecycle_event === "dev";
10
+ }
8
11
  export async function startLocalServer(options) {
9
12
  logger.info("server.starting", { host: options.host, port: options.port, dataDirectory: options.dataDirectory, databasePath: options.databasePath });
10
13
  let security;
@@ -19,7 +22,8 @@ export async function startLocalServer(options) {
19
22
  publicPath,
20
23
  security,
21
24
  disableUserAuth: devAuthBypass,
22
- devAuthBypass
25
+ devAuthBypass,
26
+ developmentServer: isDevelopmentServer(options.env)
23
27
  });
24
28
  }
25
29
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"server-runtime.js","sourceRoot":"","sources":["../src/server-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-runtime.js","sourceRoot":"","sources":["../src/server-runtime.ts"],"names":[],"mappings":"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"}
package/dist/store.js CHANGED
@@ -2193,6 +2193,7 @@ export class Store {
2193
2193
  delete profile.sections;
2194
2194
  return {
2195
2195
  name: String(character.name),
2196
+ code: String(character.code),
2196
2197
  aliases: [...character.aliases],
2197
2198
  raceId: character.raceId,
2198
2199
  species: String(character.species),
@@ -2245,9 +2246,9 @@ export class Store {
2245
2246
  const organizationIds = [...new Set(input.organizationIds ?? [])];
2246
2247
  this.assertOrganizationsInWork(workId, organizationIds);
2247
2248
  this.db.transaction(() => {
2248
- this.db.run(`INSERT INTO characters (id, work_id, name, aliases_json, species, race_id, attributes_json, profile_json, current_state_json,
2249
+ this.db.run(`INSERT INTO characters (id, work_id, name, code, aliases_json, species, race_id, attributes_json, profile_json, current_state_json,
2249
2250
  locked_fields_json, visibility, first_chapter_id, created_at, updated_at)
2250
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, characterId, workId, names.name, JSON.stringify(names.aliases), species, raceId, JSON.stringify(input.attributes ?? {}), JSON.stringify(input.profile ?? {}), JSON.stringify(input.currentState ?? {}), JSON.stringify(input.lockedFields ?? []), input.visibility ?? "author", input.firstChapterId ?? null, timestamp, timestamp);
2251
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, characterId, workId, names.name, input.code?.trim() ?? "", JSON.stringify(names.aliases), species, raceId, JSON.stringify(input.attributes ?? {}), JSON.stringify(input.profile ?? {}), JSON.stringify(input.currentState ?? {}), JSON.stringify(input.lockedFields ?? []), input.visibility ?? "author", input.firstChapterId ?? null, timestamp, timestamp);
2251
2252
  this.insertCharacterNames(workId, characterId, names.entries);
2252
2253
  this.replaceCharacterOrganizations(characterId, organizationIds);
2253
2254
  this.insertCharacterVersion(characterId, 1, "create", null, "建立人物档案", timestamp);
@@ -2596,8 +2597,8 @@ export class Store {
2596
2597
  this.db.transaction(() => {
2597
2598
  const lockedCurrent = this.getCharacter(characterId);
2598
2599
  this.assertExpectedRevision("character", characterId, expectedVersionNo, "人物", Number(lockedCurrent.versionNo));
2599
- this.db.run(`UPDATE characters SET name = ?, aliases_json = ?, species = ?, race_id = ?, attributes_json = ?, profile_json = ?, current_state_json = ?,
2600
- locked_fields_json = ?, visibility = ?, first_chapter_id = ?, updated_at = ? WHERE id = ?`, names.name, JSON.stringify(names.aliases), species, raceId, JSON.stringify(attributes), JSON.stringify(input.profile ?? current.profile), JSON.stringify(input.currentState ?? current.currentState), JSON.stringify(input.lockedFields ?? current.lockedFields), input.visibility ?? String(current.visibility), input.firstChapterId === undefined ? current.firstChapterId : input.firstChapterId, now(), characterId);
2600
+ this.db.run(`UPDATE characters SET name = ?, code = ?, aliases_json = ?, species = ?, race_id = ?, attributes_json = ?, profile_json = ?, current_state_json = ?,
2601
+ locked_fields_json = ?, visibility = ?, first_chapter_id = ?, updated_at = ? WHERE id = ?`, names.name, input.code === undefined ? String(current.code) : input.code.trim(), JSON.stringify(names.aliases), species, raceId, JSON.stringify(attributes), JSON.stringify(input.profile ?? current.profile), JSON.stringify(input.currentState ?? current.currentState), JSON.stringify(input.lockedFields ?? current.lockedFields), input.visibility ?? String(current.visibility), input.firstChapterId === undefined ? current.firstChapterId : input.firstChapterId, now(), characterId);
2601
2602
  this.db.run("DELETE FROM character_names WHERE character_id = ?", characterId);
2602
2603
  this.insertCharacterNames(workId, characterId, names.entries);
2603
2604
  if (organizationIds)
@@ -2666,7 +2667,7 @@ export class Store {
2666
2667
  this.assertExpectedRevision("character", characterId, expectedVersionNo, "人物", this.currentCharacterVersionNo(characterId));
2667
2668
  return this.recreateCharacterFromVersion(characterId, version, snapshot, versionNo);
2668
2669
  }
2669
- return this.updateCharacter(characterId, snapshot, "restore", requiredString(version, "id"), `恢复至 v${versionNo}`, expectedVersionNo);
2670
+ return this.updateCharacter(characterId, { ...snapshot, code: snapshot.code ?? "" }, "restore", requiredString(version, "id"), `恢复至 v${versionNo}`, expectedVersionNo);
2670
2671
  }
2671
2672
  recreateCharacterFromVersion(characterId, version, snapshot, versionNo) {
2672
2673
  const workId = requiredString(version, "work_id");
@@ -2683,9 +2684,9 @@ export class Store {
2683
2684
  const timestamp = now();
2684
2685
  const nextVersionNo = numberValue(this.db.get("SELECT COALESCE(MAX(version_no), 0) AS version_no FROM character_versions WHERE character_id = ?", characterId) ?? {}, "version_no") + 1;
2685
2686
  this.db.transaction(() => {
2686
- this.db.run(`INSERT INTO characters (id, work_id, name, aliases_json, species, race_id, attributes_json, profile_json, current_state_json,
2687
+ this.db.run(`INSERT INTO characters (id, work_id, name, code, aliases_json, species, race_id, attributes_json, profile_json, current_state_json,
2687
2688
  locked_fields_json, visibility, first_chapter_id, version_no, created_at, updated_at)
2688
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, characterId, workId, names.name, JSON.stringify(names.aliases), species, raceId, JSON.stringify(snapshot.attributes ?? {}), JSON.stringify(snapshot.profile ?? {}), JSON.stringify(snapshot.currentState ?? {}), JSON.stringify(snapshot.lockedFields ?? []), snapshot.visibility ?? "author", snapshot.firstChapterId ?? null, nextVersionNo, timestamp, timestamp);
2689
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, characterId, workId, names.name, snapshot.code ?? "", JSON.stringify(names.aliases), species, raceId, JSON.stringify(snapshot.attributes ?? {}), JSON.stringify(snapshot.profile ?? {}), JSON.stringify(snapshot.currentState ?? {}), JSON.stringify(snapshot.lockedFields ?? []), snapshot.visibility ?? "author", snapshot.firstChapterId ?? null, nextVersionNo, timestamp, timestamp);
2689
2690
  this.insertCharacterNames(workId, characterId, names.entries);
2690
2691
  this.replaceCharacterOrganizations(characterId, organizationIds);
2691
2692
  this.insertCharacterVersion(characterId, nextVersionNo, "restore", requiredString(version, "id"), `恢复至 v${versionNo}`, timestamp, workId);
@@ -2758,6 +2759,7 @@ export class Store {
2758
2759
  id: characterId,
2759
2760
  workId: requiredString(row, "work_id"),
2760
2761
  name: requiredString(row, "name"),
2762
+ code: requiredString(row, "code"),
2761
2763
  aliases: indexedAliases.length > 0 ? indexedAliases : json(requiredString(row, "aliases_json"), []),
2762
2764
  raceId: race ? String(race.id) : null,
2763
2765
  race: race ? {
@@ -2842,6 +2844,7 @@ export class Store {
2842
2844
  .filter((alias) => normalizeCharacterName(alias) !== normalizeCharacterName(String(target.name)))
2843
2845
  .map((alias) => [normalizeCharacterName(alias), alias])).values()];
2844
2846
  this.updateCharacter(targetId, {
2847
+ code: String(target.code) || String(source.code),
2845
2848
  aliases: uniqueAliases,
2846
2849
  raceId: target.raceId ?? source.raceId,
2847
2850
  organizationIds: [...new Set([...target.organizationIds, ...source.organizationIds])],