@musnows/scriverse 0.4.0 → 0.4.1

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;
@@ -208,6 +241,39 @@
208
241
  --toast-fg: #171714;
209
242
  --toast-error-bg: #e08a72;
210
243
  --toast-error-fg: #171714;
244
+ --relationship-card-border: #1c1c24;
245
+ --relationship-card-surface: #12121a;
246
+ --relationship-toolbar-surface: #12121a;
247
+ --relationship-toolbar-ink: #e8e8ef;
248
+ --relationship-toolbar-muted: #7a7a88;
249
+ --relationship-control-border: #2a2a36;
250
+ --relationship-control-ink: #a8a8b4;
251
+ --relationship-control-hover-border: #4a4a58;
252
+ --relationship-control-hover-surface: #1a1a24;
253
+ --relationship-control-hover-ink: #f0f0f5;
254
+ --relationship-network-surface: #12121a;
255
+ --relationship-edge: rgba(255,255,255,.26);
256
+ --relationship-edge-directed: rgba(214,218,232,.5);
257
+ --relationship-edge-pending: rgba(255,255,255,.18);
258
+ --relationship-edge-highlight: rgba(255,255,255,.72);
259
+ --relationship-edge-selected: rgba(220,220,235,.88);
260
+ --relationship-label-ink: rgba(230,230,240,.88);
261
+ --relationship-label-stroke: #12121a;
262
+ --relationship-node-ink: rgba(245,245,250,.88);
263
+ --relationship-node-label: rgba(235,235,245,.78);
264
+ --relationship-node-label-active: rgba(255,255,255,.95);
265
+ --relationship-node-text-shadow: 0 1px 2px rgba(0,0,0,.65);
266
+ --relationship-node-hover-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
267
+ --relationship-node-selected-shadow: 0 0 10px rgba(255,255,255,.55), 0 0 20px var(--node-glow, rgba(139,144,153,.6));
268
+ --relationship-node-endpoint-shadow: 0 0 10px rgba(255,255,255,.5), 0 0 18px var(--node-glow, rgba(139,144,153,.55));
269
+ --relationship-node-dragging-shadow: 0 0 10px rgba(255,255,255,.6), 0 0 18px var(--node-glow, rgba(139,144,153,.6));
270
+ --relationship-focus: #7a7a88;
271
+ --relationship-focus-strong: #c8c8d4;
272
+ --relationship-focus-muted: #6a6a78;
273
+ --relationship-detail-border: #2a2a36;
274
+ --relationship-detail-surface: rgba(18,18,26,.94);
275
+ --relationship-detail-ink: #e2e2ea;
276
+ --relationship-detail-muted: #9a9aa8;
211
277
  color-scheme: dark;
212
278
  }
213
279
 
@@ -500,6 +566,7 @@ body.work-viewer-mode [data-edit-event],
500
566
  body.work-viewer-mode [data-split-event],
501
567
  body.work-viewer-mode [data-event-select],
502
568
  body.work-viewer-mode #create-timeline-track,
569
+ body.work-viewer-mode #timeline-multi-select-toggle,
503
570
  body.work-viewer-mode #merge-events,
504
571
  body.work-viewer-mode [data-edit-foreshadow],
505
572
  body.work-viewer-mode [data-edit-outline],
@@ -719,7 +786,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
719
786
  .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
787
  #module-more-button[aria-expanded="true"] .nav-icon { transform: rotate(180deg); }
721
788
  .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; }
789
+ .module-nav .ai-analysis-entry,
790
+ .module-nav .ai-analysis-entry:hover,
791
+ .module-nav .ai-analysis-entry.active { background: transparent; color: var(--accent-dark); font-weight: 650; }
723
792
  #module-more-button { grid-column: 1 / -1; color: var(--accent-dark); text-align: center; }
724
793
  .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
794
  .panel-heading-actions { display: flex; align-items: center; gap: 7px; margin-left: auto; }
@@ -734,7 +803,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
734
803
  .chapter-add-button { flex: none; }
735
804
  .volume-chapters { display: block; }
736
805
  .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; }
806
+ .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
807
  .chapter-node:hover, .chapter-node.active { background: var(--row-active); }
739
808
  .chapter-node.active { color: var(--accent-dark); font-weight: 700; }
740
809
  .chapter-node > span:first-child { min-width: 0; overflow-wrap: anywhere; line-height: 1.45; white-space: normal; }
@@ -797,19 +866,26 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
797
866
  .chapter-insight strong { color: var(--ink); margin-right: 8px; }
798
867
 
799
868
  .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); }
869
+ .module-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 18px; padding-bottom: 24px; border-bottom: 1px solid var(--line); }
870
+ .module-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
871
+ .module-header-actions > [data-module-header-action] { order: 1; }
872
+ .module-header-actions > #module-create-button { order: 2; min-height: 36px; }
801
873
  .module-header h1 { margin: 0 0 8px; font-weight: 500; font-size: 34px; }
802
874
  .module-header p { margin: 0; color: var(--muted); font-size: 13px; }
803
875
  .module-content { padding: 24px 0 80px; }
804
876
  .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 13px; }
805
877
  .record-card { position: relative; border: 1px solid var(--line); background: var(--surface-soft); padding: 18px; min-height: 130px; border-radius: 4px; }
878
+ .record-card.has-card-edit h3 { padding-right: 34px; }
879
+ .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); }
880
+ .record-card-edit:hover, .record-card-edit:focus-visible { border-color: var(--accent); color: var(--accent-dark); outline: none; }
881
+ .record-card-edit svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
806
882
  .record-card h3 { font-size: 16px; margin: 5px 0 10px; font-weight: 600; }
807
883
  .record-card p { color: var(--muted); font-size: 12px; line-height: 1.55; margin: 0; white-space: pre-wrap; }
808
884
  .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; }
885
+ .settings-layout-toolbar, .module-layout-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-bottom: 0; }
810
886
  .settings-layout-hint, .module-layout-hint { color: var(--muted); font-size: 10px; }
811
887
  .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; }
888
+ .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
889
  .settings-layout-toggle button:last-child, .module-layout-toggle button:last-child { border-right: 0; }
814
890
  .settings-layout-toggle button:hover, .settings-layout-toggle button:focus-visible,
815
891
  .module-layout-toggle button:hover, .module-layout-toggle button:focus-visible { color: var(--ink); background: var(--paper-deep); }
@@ -840,6 +916,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
840
916
  .character-duplicate-actions { flex-wrap: wrap; }
841
917
  .card-actions { display: flex; gap: 6px; margin-top: 15px; }
842
918
  .card-actions button { border: 1px solid var(--line); background: transparent; border-radius: 3px; font-size: 10px; padding: 5px 8px; }
919
+ .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; }
920
+ .danger-button:hover, .danger-button:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); outline: none; }
843
921
  .card-actions .danger-button { border-color: color-mix(in srgb, var(--accent) 52%, var(--line)); color: var(--accent-dark); }
844
922
  .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
923
  .card-actions .primary-button { border-color: var(--accent); background: var(--accent); color: #fff; padding: 8px 13px; font-size: 12px; }
@@ -867,6 +945,17 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
867
945
  .race-settings .pill { display: inline-flex; align-items: center; gap: 5px; }
868
946
  .race-settings .pill small { color: inherit; font-size: 8px; letter-spacing: 0; text-transform: none; opacity: .72; }
869
947
  .race-settings .pill.inherited { border-style: dashed; }
948
+ .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)); }
949
+ .entity-dialog-management > div:first-child, .entity-editor-management > div:first-child { display: grid; gap: 4px; }
950
+ .entity-dialog-management strong, .entity-editor-management strong { color: var(--ink); font-size: 11px; }
951
+ .entity-dialog-management small, .entity-editor-management small { color: var(--muted); font-size: 10px; line-height: 1.5; }
952
+ .entity-dialog-management-actions, .entity-editor-management-actions { display: flex; flex-wrap: wrap; gap: 7px; }
953
+ .entity-dialog-management-actions button, .entity-editor-management-actions button { min-height: 32px; }
954
+ .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)); }
955
+ .danger-confirm-field input { width: auto !important; margin-top: 3px; }
956
+ .danger-confirm-field span { display: grid; gap: 4px; }
957
+ .danger-confirm-field strong { color: var(--ink); font-size: 11px; }
958
+ .danger-confirm-field small { color: var(--muted); font-size: 10px; line-height: 1.5; }
870
959
  .config-section { margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line); }
871
960
  .config-section:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
872
961
  .platform-system-prompt-section { margin-bottom: 36px; }
@@ -940,7 +1029,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
940
1029
  .table-list th, .table-list td { padding: 12px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
941
1030
  .table-list th { color: var(--muted); font-weight: 400; font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }
942
1031
  .danger-text { color: var(--accent); }
943
- .timeline-tools { display: flex; justify-content: flex-end; gap: 8px; margin-bottom: 12px; }
1032
+ .timeline-tools { display: flex; justify-content: flex-end; gap: 8px; }
944
1033
  .timeline-select { position: absolute; left: -33px; top: 0; }
945
1034
  .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
1035
  .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 +1088,12 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
999
1088
  .relationship-map-expanded-host .relationship-map-card { height: 100%; margin: 0; }
1000
1089
  .relationship-map-expanded-host .relationship-map-toolbar { padding-right: 72px; }
1001
1090
  .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; }
1091
+ .relationship-network-card { border-color: var(--relationship-card-border); background: var(--relationship-card-surface); box-shadow: none; }
1092
+ .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); }
1093
+ .relationship-network-card .relationship-map-toolbar small { color: var(--relationship-toolbar-muted); }
1094
+ .relationship-network-card .relationship-map-actions button { border-color: var(--relationship-control-border); background: transparent; color: var(--relationship-control-ink); }
1095
+ .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); }
1096
+ .relationship-network { height: min(68vh, 650px); min-height: 520px; contain: layout paint style; touch-action: none; cursor: grab; background: var(--relationship-network-surface); }
1008
1097
  .relationship-network.is-panning { cursor: grabbing; }
1009
1098
  .relationship-network-stage { contain: layout paint style; will-change: transform; }
1010
1099
  .relationship-network-stage.is-view-animating { transition: transform .34s cubic-bezier(.22,.78,.3,1); }
@@ -1019,21 +1108,21 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1019
1108
  stroke: transparent;
1020
1109
  }
1021
1110
  .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); }
1111
+ .relationship-network .obsidian-edge { stroke: var(--relationship-edge); stroke-width: 1px; opacity: 1; transition: opacity .12s ease, stroke .12s ease; }
1112
+ .relationship-network .mind-edge.is-directed { stroke: var(--relationship-edge-directed); }
1024
1113
  .relationship-network .relationship-edge-arrow { pointer-events: none; }
1025
1114
  .relationship-network .mind-edge.family,
1026
1115
  .relationship-network .mind-edge.social,
1027
1116
  .relationship-network .mind-edge.emotional,
1028
1117
  .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; }
1118
+ .relationship-network .mind-edge.uncertain { stroke: var(--relationship-edge); stroke-dasharray: none; }
1119
+ .relationship-network .mind-edge.is-pending { stroke: var(--relationship-edge-pending); stroke-dasharray: 4 6; }
1031
1120
  .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; }
1121
+ .relationship-network .mind-edge.is-highlighted { stroke: var(--relationship-edge-highlight); stroke-width: 1.35px; opacity: 1; }
1122
+ .relationship-network .mind-edge.is-edge-selected { stroke: var(--relationship-edge-selected); stroke-width: 1.6px; opacity: 1; }
1034
1123
  .relationship-network .mind-edge-label {
1035
- fill: rgba(230,230,240,.88);
1036
- stroke: #12121a;
1124
+ fill: var(--relationship-label-ink);
1125
+ stroke: var(--relationship-label-stroke);
1037
1126
  stroke-width: 2.5px;
1038
1127
  font-size: 7px;
1039
1128
  font-weight: 400;
@@ -1054,7 +1143,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1054
1143
  border: 0;
1055
1144
  border-radius: 50%;
1056
1145
  background: var(--node-color, #8b9099);
1057
- color: rgba(245,245,250,.88);
1146
+ color: var(--relationship-node-ink);
1058
1147
  box-shadow: 0 0 8px var(--node-glow, rgba(139,144,153,.42));
1059
1148
  font-family: "SF Pro Text", "Segoe UI", "Helvetica Neue", sans-serif;
1060
1149
  font-size: 9px;
@@ -1075,30 +1164,39 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1075
1164
  text-overflow: ellipsis;
1076
1165
  white-space: nowrap;
1077
1166
  pointer-events: none;
1078
- color: rgba(235,235,245,.78);
1167
+ color: var(--relationship-node-label);
1079
1168
  font-size: 9px;
1080
1169
  font-weight: 400;
1081
1170
  letter-spacing: .01em;
1082
- text-shadow: 0 1px 2px rgba(0,0,0,.65);
1171
+ text-shadow: var(--relationship-node-text-shadow);
1172
+ opacity: 0;
1173
+ transition: opacity .12s ease, color .12s ease;
1083
1174
  }
1175
+ .relationship-network .mind-node.is-label-visible span,
1176
+ .relationship-network .mind-node:hover span,
1177
+ .relationship-network .mind-node:focus-visible span,
1178
+ .relationship-network .mind-node.is-hovered span,
1179
+ .relationship-network .mind-node.is-selected span,
1180
+ .relationship-network .mind-node.is-related span,
1181
+ .relationship-network .mind-node.is-edge-endpoint span { opacity: 1; }
1084
1182
  .relationship-network .mind-node:hover,
1085
1183
  .relationship-network .mind-node:focus-visible,
1086
1184
  .relationship-network .mind-node.is-hovered {
1087
1185
  transform: translate(-50%, -50%) scale(1.28);
1088
1186
  outline: none;
1089
1187
  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));
1188
+ box-shadow: var(--relationship-node-hover-shadow);
1091
1189
  }
1092
1190
  .relationship-network .mind-node:hover span,
1093
1191
  .relationship-network .mind-node:focus-visible span,
1094
1192
  .relationship-network .mind-node.is-hovered span,
1095
1193
  .relationship-network .mind-node.is-selected span,
1096
1194
  .relationship-network .mind-node.is-related span,
1097
- .relationship-network .mind-node.is-edge-endpoint span { color: rgba(255,255,255,.95); }
1195
+ .relationship-network .mind-node.is-edge-endpoint span { color: var(--relationship-node-label-active); }
1098
1196
  .relationship-network .mind-node.is-selected {
1099
1197
  transform: translate(-50%, -50%) scale(1.32);
1100
1198
  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));
1199
+ box-shadow: var(--relationship-node-selected-shadow);
1102
1200
  }
1103
1201
  .relationship-network .mind-node.is-related { opacity: 1; }
1104
1202
  .relationship-network .mind-node.is-dimmed { opacity: .14; box-shadow: none; }
@@ -1106,7 +1204,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1106
1204
  .relationship-network .mind-node.is-edge-endpoint {
1107
1205
  opacity: 1;
1108
1206
  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));
1207
+ box-shadow: var(--relationship-node-endpoint-shadow);
1110
1208
  }
1111
1209
  .relationship-network[data-interaction="dragging"] .mind-edge,
1112
1210
  .relationship-network[data-interaction="dragging"] .mind-node,
@@ -1126,7 +1224,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1126
1224
  transition: none;
1127
1225
  z-index: 8;
1128
1226
  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));
1227
+ box-shadow: var(--relationship-node-dragging-shadow);
1130
1228
  }
1131
1229
  .relationship-network .mind-node.is-drag-neighbor {
1132
1230
  opacity: 1;
@@ -1134,16 +1232,16 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1134
1232
  will-change: left, top;
1135
1233
  }
1136
1234
  .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; }
1235
+ .relationship-network-focus, .relationship-network-help { position: absolute; z-index: 6; color: var(--relationship-focus); pointer-events: none; }
1138
1236
  .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; }
1237
+ .relationship-network-focus strong { color: var(--relationship-focus-strong); font-size: 10px; font-weight: 500; }
1238
+ .relationship-network-focus span { color: var(--relationship-focus-muted); font-size: 9px; }
1141
1239
  .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; }
1240
+ .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; }
1241
+ .relationship-network .mind-edge-detail span { color: var(--relationship-detail-muted); }
1144
1242
  .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; }
1243
+ .relationship-map-dialog { background: var(--relationship-card-surface); border-color: var(--relationship-card-border); }
1244
+ .relationship-map-expanded-host { background: var(--relationship-card-surface); }
1147
1245
  @keyframes relationship-node-settle { from { transform: translate(-50%, -50%) scale(1.36); } to { transform: translate(-50%, -50%) scale(1.32); } }
1148
1246
  @media (prefers-reduced-motion: reduce) { .relationship-network .mind-node, .relationship-network-stage { transition-duration: .01ms; animation-duration: .01ms; } }
1149
1247
 
@@ -1204,7 +1302,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1204
1302
  .field-label select { padding: 8px; font-size: 12px; }
1205
1303
  .book-summary-context-percent-field { width: min(100%, 280px); }
1206
1304
  .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; }
1305
+ .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
1306
  .field-label textarea {
1209
1307
  width: 100%;
1210
1308
  min-height: 140px;
@@ -1459,8 +1557,14 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1459
1557
  .section-list-row { grid-template-columns: minmax(0, 1fr) auto; }
1460
1558
  .section-list-row textarea { grid-column: 1 / -1; min-height: 130px; }
1461
1559
  .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; }
1560
+ .character-card h3 { margin-bottom: 5px; }
1561
+ .character-identity { margin: 0 0 6px !important; color: var(--ink) !important; font-weight: 600; line-height: 1.55 !important; }
1562
+ .character-aliases { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; }
1563
+ .character-aliases .pill { margin: 0; }
1564
+ .character-code { display: flex; align-items: center; gap: 7px; margin-top: 10px; color: var(--muted); font-size: 10px; }
1565
+ .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; }
1566
+ .character-species b { font-weight: 500; }
1567
+ .character-species .pill { justify-self: start; min-width: 0; max-width: 100%; margin: 0; overflow-wrap: anywhere; }
1464
1568
  .character-detail-list { display: grid; gap: 5px; margin: 12px 0; }
1465
1569
  .character-detail-list div { display: grid; grid-template-columns: minmax(70px, .42fr) minmax(0, 1fr); gap: 8px; font-size: 10px; }
1466
1570
  .character-detail-list dt { color: var(--muted); }
@@ -1528,7 +1632,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1528
1632
  .setting-editor-lock b { color: var(--ink); font-size: 10px; }
1529
1633
  .setting-editor-lock small { display: none; }
1530
1634
  .setting-editor-change-note { align-items: center; gap: 6px; }
1531
- .setting-editor-workspace { min-height: 0; }
1635
+ .setting-editor-workspace { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; overflow: hidden; }
1532
1636
  .setting-editor-content { height: 100%; min-height: 0; padding: 16px clamp(16px, 2vw, 32px) 24px; overflow: hidden; }
1533
1637
  .setting-markdown-field { display: grid; grid-template-rows: minmax(0, 1fr); height: 100%; min-height: 0; }
1534
1638
  .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 +1648,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1544
1648
  .vditor-editor-host .vditor-reset { color: var(--ink); font-family: var(--font-cjk), var(--font-latin), sans-serif; }
1545
1649
  .vditor-editor-host .vditor-ir, .vditor-editor-host .vditor-sv, .vditor-editor-host .vditor-wysiwyg { background: var(--surface); color: var(--ink); }
1546
1650
  .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; }
1651
+ .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
1652
  .record-markdown-preview > :first-child, .knowledge-markdown-block .message-body > :first-child { margin-top: 0; }
1549
1653
  .record-markdown-preview > :last-child, .knowledge-markdown-block .message-body > :last-child { margin-bottom: 0; }
1550
1654
  .knowledge-markdown-block { min-width: 0; margin: 10px 0 0; padding: 11px 13px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); }
@@ -1686,6 +1790,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1686
1790
  .appearance-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 22px 24px; }
1687
1791
  .appearance-grid label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; }
1688
1792
  .appearance-grid select { width: 100%; padding: 9px 10px; font-size: 13px; }
1793
+ .appearance-whitespace-field { grid-column: 1 / -1; }
1689
1794
  .font-preview { grid-column: 1 / -1; padding: 16px; border: 1px solid var(--line); border-radius: 4px; background: var(--paper); }
1690
1795
  .font-preview strong, .font-preview span { display: block; }
1691
1796
  .font-preview strong { margin-bottom: 8px; font-size: 17px; }
@@ -1715,8 +1820,11 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1715
1820
  .entity-version-card > button.is-confirming { border-color: var(--accent); background: var(--accent); color: #fff; }
1716
1821
  .entity-version-card > button:disabled { cursor: default; opacity: .68; }
1717
1822
  .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; }
1823
+ .relationship-table .relationship-actions { white-space: nowrap; vertical-align: middle; }
1824
+ .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; }
1825
+ .relationship-table .relationship-actions button + button { margin-left: 6px; }
1826
+ .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; }
1827
+ .relationship-table .relationship-actions button[data-edit-relationship] { color: var(--ink); }
1720
1828
 
1721
1829
  @media (max-width: 540px) {
1722
1830
  .member-permission-grid { grid-template-columns: minmax(0, 1fr); }
@@ -1759,7 +1867,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1759
1867
  .setting-editor-header { min-height: 102px; }
1760
1868
  .setting-editor-header-fields { flex-wrap: wrap; gap: 8px 12px; }
1761
1869
  .setting-editor-title-input { font-size: 18px; }
1762
- .setting-editor-content { min-height: 70dvh; padding: 16px; }
1870
+ .setting-editor-workspace { overflow-y: auto; }
1871
+ .setting-editor-content { height: auto; min-height: 70dvh; padding: 16px; }
1763
1872
  .setting-markdown-field { height: 70dvh; }
1764
1873
  .setting-markdown-heading, .markdown-editor-field-heading { align-items: flex-start; flex-direction: column; gap: 4px; }
1765
1874
  .setting-markdown-field > .vditor-editor-host, .markdown-editor-field .vditor-editor-host { min-height: 42dvh; }
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])],