@musnows/scriverse 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,50 +99,55 @@
99
99
  [data-pending-view="module"] .auth-pending #module-view.hidden { display: block !important; }
100
100
  [data-pending-view="welcome"] .auth-pending #welcome-view.hidden,
101
101
  [data-pending-view="editor"] .auth-pending #editor-view.hidden { display: grid !important; }
102
+ /* 阅读深链在会话和正文恢复完成前直接显示稳定骨架,并隐藏后台工作台的响应式重排。 */
103
+ [data-pending-view="reader"] #reader-view.hidden { display: grid !important; }
104
+ [data-pending-view="reader"] .app-shell { visibility: hidden; }
102
105
  /* 书架/设置/平台 AI 路由的骨架使用整宽布局,与 shelf-mode 一致 */
103
106
  .pending-shelf-mode .auth-pending .app-shell { grid-template-columns: 1fr; }
104
107
  .pending-shelf-mode .auth-pending .topbar { grid-template-columns: 280px 1fr auto; }
105
108
  .pending-shelf-mode .auth-pending .left-panel, .pending-shelf-mode .auth-pending .ai-panel { display: none; }
106
109
  .pending-shelf-mode .auth-pending .main-panel { grid-column: 1 / -1; }
107
- .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); }
110
+ .auth-view { position: fixed; inset: 0; z-index: 1000; display: grid; grid-template-rows: minmax(min-content, 1fr) auto; gap: 12px; place-items: center; padding: 10px; 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); }
108
111
  .auth-view.hidden { display: none; }
109
- .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); }
110
- .auth-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 34px; }
112
+ .auth-card { align-self: center; box-sizing: border-box; width: min(400px, 100%); padding: 24px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: var(--shadow); }
113
+ .auth-brand { display: flex; align-items: center; gap: 8px; margin-bottom: 22px; }
114
+ .auth-brand .brand-mark { width: 30px; height: 30px; }
111
115
  .auth-brand div { display: grid; }
112
- .auth-brand small { color: var(--muted); }
113
- .auth-card h1 { margin: 8px 0; font-size: 30px; }
114
- .auth-card > p { color: var(--muted); line-height: 1.6; }
116
+ .auth-brand strong { font-size: 15px; }
117
+ .auth-brand small { color: var(--muted); font-size: 11px; }
118
+ .auth-card h1 { margin: 6px 0; font-size: 26px; }
119
+ .auth-card > p { margin: 10px 0; color: var(--muted); line-height: 1.45; }
115
120
  .auth-tabs {
116
121
  display: grid;
117
122
  grid-template-columns: 1fr 1fr;
118
123
  gap: 0;
119
- margin: 24px 0 18px;
120
- padding: 3px;
124
+ margin: 18px 0 14px;
125
+ padding: 2px;
121
126
  overflow: hidden;
122
127
  border: 1px solid color-mix(in srgb, var(--accent) 38%, var(--line));
123
- border-radius: 9px;
128
+ border-radius: 7px;
124
129
  background: var(--paper-deep);
125
130
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--surface) 65%, transparent);
126
131
  }
127
132
  .auth-tabs button {
128
133
  position: relative;
129
134
  z-index: 0;
130
- min-height: 42px;
135
+ min-height: 38px;
131
136
  border: 0;
132
- border-radius: 6px;
137
+ border-radius: 5px;
133
138
  background: transparent;
134
139
  color: var(--muted);
135
140
  cursor: pointer;
136
- font-size: 14px;
141
+ font-size: 13px;
137
142
  font-weight: 600;
138
143
  letter-spacing: .04em;
139
144
  transition: background .16s ease, color .16s ease, box-shadow .16s ease, transform .16s ease;
140
145
  }
141
146
  .auth-tabs button + button::before {
142
147
  position: absolute;
143
- top: 10px;
144
- bottom: 10px;
145
- left: -3px;
148
+ top: 8px;
149
+ bottom: 8px;
150
+ left: -2px;
146
151
  width: 1px;
147
152
  background: var(--line);
148
153
  content: "";
@@ -163,24 +168,24 @@
163
168
  .auth-tabs button[aria-selected="true"]::after {
164
169
  position: absolute;
165
170
  right: 24%;
166
- bottom: 5px;
171
+ bottom: 4px;
167
172
  left: 24%;
168
- height: 3px;
173
+ height: 2px;
169
174
  border-radius: 999px;
170
175
  background: var(--accent);
171
176
  content: "";
172
177
  }
173
178
  .auth-tabs button:focus-visible { z-index: 2; outline: 2px solid color-mix(in srgb, var(--accent) 82%, white); outline-offset: -2px; }
174
- .auth-form { display: grid; gap: 16px; }
175
- .auth-form label { display: grid; gap: 8px; color: var(--muted); font-size: 13px; }
179
+ .auth-form { display: grid; gap: 12px; }
180
+ .auth-form label { display: grid; gap: 5px; color: var(--muted); font-size: 12px; }
176
181
  .auth-form input {
177
182
  width: 100%;
178
- min-height: 46px;
179
- padding: 12px 14px;
183
+ min-height: 42px;
184
+ padding: 9px 12px;
180
185
  border: 1px solid var(--line);
181
- border-radius: 7px;
186
+ border-radius: 6px;
182
187
  background: var(--paper-deep);
183
- font-size: 15px;
188
+ font-size: 14px;
184
189
  line-height: 1.4;
185
190
  }
186
191
  .auth-form input:focus {
@@ -212,34 +217,34 @@
212
217
  .password-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
213
218
  .auth-form .primary-button {
214
219
  width: 100%;
215
- min-height: 46px;
216
- margin-top: 4px;
217
- padding: 12px 16px;
218
- border-radius: 7px;
219
- font-size: 15px;
220
+ min-height: 42px;
221
+ margin-top: 2px;
222
+ padding: 10px 14px;
223
+ border-radius: 6px;
224
+ font-size: 14px;
220
225
  font-weight: 600;
221
226
  }
222
- .auth-form small { color: var(--muted); line-height: 1.5; font-size: 12px; }
223
- .auth-captcha { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: end; }
227
+ .auth-form small { color: var(--muted); line-height: 1.45; font-size: 11px; }
228
+ .auth-captcha { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: end; }
224
229
  .auth-captcha label { margin: 0; }
225
230
  .auth-captcha-image {
226
231
  display: inline-flex;
227
232
  align-items: center;
228
233
  justify-content: center;
229
- min-width: 148px;
230
- min-height: 46px;
234
+ min-width: 128px;
235
+ min-height: 42px;
231
236
  padding: 0;
232
237
  border: 1px solid var(--line);
233
- border-radius: 7px;
238
+ border-radius: 6px;
234
239
  background: var(--paper-deep);
235
240
  cursor: pointer;
236
241
  }
237
- .auth-captcha-image img { display: block; width: 148px; height: 48px; border-radius: 6px; }
242
+ .auth-captcha-image img { display: block; width: 128px; height: 42px; border-radius: 5px; }
238
243
  .auth-captcha-image img[hidden], .auth-captcha-placeholder[hidden] { display: none; }
239
- .auth-captcha-placeholder { color: var(--muted); font-size: 13px; padding: 0 14px; white-space: nowrap; }
240
- .auth-captcha-hint { margin: -8px 0 0; color: var(--muted); font-size: 12px; line-height: 1.4; }
241
- .auth-security-hint { margin: -8px 0 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
242
- .auth-error { min-height: 20px; margin: 14px 0 0 !important; color: var(--accent-dark) !important; }
244
+ .auth-captcha-placeholder { color: var(--muted); font-size: 12px; padding: 0 10px; white-space: nowrap; }
245
+ .auth-captcha-hint { margin: -6px 0 0; color: var(--muted); font-size: 11px; line-height: 1.35; }
246
+ .auth-security-hint { margin: -6px 0 0; color: var(--muted); font-size: 11px; line-height: 1.4; }
247
+ .auth-error { min-height: 17px; margin: 10px 0 0 !important; color: var(--accent-dark) !important; }
243
248
 
244
249
  :root[data-theme="dark"] {
245
250
  --ink: #e8e2d8;
@@ -791,7 +796,7 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
791
796
  .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; }
792
797
  .product-footer .product-footer-update { padding: 2px 8px; border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--line)); border-radius: 999px; background: color-mix(in srgb, var(--accent) 9%, transparent); color: var(--accent-dark); font-weight: 700; }
793
798
  .product-footer .product-footer-update:hover, .product-footer .product-footer-update:focus-visible { color: var(--accent-dark); }
794
- .auth-product-footer { align-self: end; max-width: 440px; margin: 0; padding-top: 14px; }
799
+ .auth-product-footer { align-self: end; max-width: 400px; margin: 0; padding-top: 8px; }
795
800
  .settings-product-footer { max-width: 1000px; }
796
801
  .access-dialog-body { display: grid; gap: 16px; max-height: calc(88vh - 82px); overflow-y: auto; padding: 18px 24px 22px; }
797
802
  .access-list { display: grid; gap: 8px; max-height: min(34vh, 340px); overflow: auto; padding: 0; }
@@ -977,9 +982,7 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
977
982
  .app-shell.prose-hidden-mode:not(.shelf-mode) .panel-heading,
978
983
  .app-shell.prose-hidden-mode:not(.shelf-mode) #novel-tree { display: none !important; }
979
984
  .app-shell.prose-read-only-mode:not(.shelf-mode) #tidy-blank-lines-button,
980
- .app-shell.prose-read-only-mode:not(.shelf-mode) #save-button,
981
- .app-shell.prose-read-only-mode:not(.shelf-mode) #chapter-delete-button,
982
- .app-shell.prose-read-only-mode:not(.shelf-mode) #chapter-edit-button { display: none !important; }
985
+ .app-shell.prose-read-only-mode:not(.shelf-mode) #save-button { display: none !important; }
983
986
  .app-shell.prose-read-only-mode:not(.shelf-mode) .left-primary-actions { justify-content: flex-end; }
984
987
  .app-shell.prose-read-only-mode:not(.shelf-mode) #chapter-title[readonly],
985
988
  .app-shell.prose-read-only-mode:not(.shelf-mode) #chapter-content[readonly] { cursor: default; }
@@ -987,7 +990,6 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
987
990
  .app-shell.view-only-mode:not(.shelf-mode) [data-work-settings],
988
991
  .app-shell.view-only-mode:not(.shelf-mode) #tidy-blank-lines-button,
989
992
  .app-shell.view-only-mode:not(.shelf-mode) #save-button,
990
- .app-shell.view-only-mode:not(.shelf-mode) #chapter-delete-button,
991
993
  .app-shell.view-only-mode:not(.shelf-mode) #chapter-edit-button { display: none !important; }
992
994
  .app-shell.view-only-mode:not(.shelf-mode) .left-primary-actions { justify-content: flex-end; }
993
995
  .app-shell.view-only-mode:not(.shelf-mode) #chapter-title[readonly],
@@ -1136,6 +1138,11 @@ body.work-viewer-mode .character-editor-actions { display: none !important; }
1136
1138
  .work-danger-field .danger-button { flex: 0 0 auto; white-space: nowrap; }
1137
1139
  .work-access-options { display: flex; flex-wrap: wrap; gap: 5px; }
1138
1140
  .work-access-options span { padding: 3px 7px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--ink); font-size: 10px; line-height: 1.35; }
1141
+ .work-editor-preference-options { display: grid; flex: 0 1 320px; gap: 7px; }
1142
+ .work-editor-preference-option { display: flex; align-items: flex-start; gap: 8px; min-width: 0; padding: 8px 10px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); cursor: pointer; }
1143
+ .work-editor-preference-option input { flex: 0 0 auto; margin: 2px 0 0; }
1144
+ .work-editor-preference-option span { display: grid; gap: 2px; min-width: 0; }
1145
+ .work-editor-preference-option b { color: var(--ink); font-size: 11px; }
1139
1146
  .account-dialog { width: min(640px, 92vw); overflow: hidden; }
1140
1147
  .account-settings-body { display: grid; gap: 16px; max-height: calc(88vh - 86px); overflow-y: auto; padding: 20px 24px 24px; }
1141
1148
  .account-settings-section { padding: 18px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface-soft); }
@@ -1493,6 +1500,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1493
1500
  .chapter-line-number.is-line-selected { background: rgba(139,61,44,.16); color: var(--accent-dark); font-weight: 700; }
1494
1501
  .chapter-line-number.is-line-selected::after { content: ""; position: absolute; top: 0; left: 100%; width: 100vw; height: 100%; background: rgba(139,61,44,.085); box-shadow: inset 3px 0 rgba(139,61,44,.28); pointer-events: none; }
1495
1502
  .chapter-content { position: relative; z-index: 1; grid-column: 2; grid-row: 1; resize: none; width: 100%; height: 100%; min-height: 0; margin: 0; padding: 32px 36px 72px; border: 0; background: transparent; border-radius: 0; font-size: var(--editor-font-size); line-height: var(--editor-line-height); letter-spacing: .01em; overflow-wrap: break-word; }
1503
+ .app-shell.editor-typewriter-mode .chapter-content { padding-bottom: max(72px, 45dvh); }
1496
1504
  .chapter-content:focus { box-shadow: none; }
1497
1505
  .chapter-whitespace-overlay { position: relative; z-index: 2; grid-column: 2; grid-row: 1; width: 100%; height: 100%; overflow: hidden; opacity: 0; pointer-events: none; }
1498
1506
  .chapter-whitespace-overlay.is-visible { opacity: 1; }
@@ -1558,7 +1566,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1558
1566
  .entity-detail-pin-button:hover, .entity-detail-pin-button:focus-visible { border-color: var(--accent); color: var(--accent-dark); outline: none; }
1559
1567
  .entity-detail-pin-button.is-pinned { border-color: color-mix(in srgb, var(--accent) 58%, var(--line)); background: color-mix(in srgb, var(--accent) 10%, var(--surface)); color: var(--accent-dark); }
1560
1568
  .entity-detail-pin-button:disabled { cursor: not-allowed; opacity: .5; }
1561
- .entity-detail-pin-button svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.6; }
1569
+ .entity-detail-pin-button svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.6; transform: translateY(.5px); }
1562
1570
  .entity-detail-pin-button.is-pinned svg { fill: currentColor; }
1563
1571
  .record-card h3 { font-size: 16px; margin: 5px 0 10px; font-weight: 600; }
1564
1572
  .record-card p { color: var(--muted); font-size: 12px; line-height: 1.55; margin: 0; white-space: pre-wrap; }
@@ -2808,7 +2816,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2808
2816
  .message-body .markdown-image img { display: block; max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: 5px; background: var(--surface-soft); }
2809
2817
  .message-body .markdown-image small { color: var(--muted); font-size: 9px; line-height: 1.45; text-align: center; }
2810
2818
  .message-meta { margin-top: 8px; color: var(--muted); font-size: 9px; }
2811
- .message-meta .ai-stream-character-count { display: inline-block; min-width: 6ch; font-variant-numeric: tabular-nums; text-align: right; }
2819
+ .message-meta .ai-stream-character-count { display: inline-block; min-width: 7ch; font-variant-numeric: tabular-nums; text-align: right; }
2812
2820
  .message-meta .ai-stream-connection-seconds { display: inline-block; min-width: 3ch; font-variant-numeric: tabular-nums; text-align: right; }
2813
2821
  .ai-process-details { margin: 0 0 10px; overflow: hidden; border: 1px solid var(--line); border-radius: 5px; background: color-mix(in srgb, var(--surface-soft) 82%, transparent); }
2814
2822
  .ai-process-details > summary { display: flex; align-items: center; justify-content: space-between; gap: 9px; padding: 8px 10px; color: var(--muted); cursor: pointer; font-size: 10px; list-style: none; }
@@ -2851,6 +2859,122 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2851
2859
  #ai-tool-call-arguments { min-height: 0; max-height: 26vh; }
2852
2860
  .ai-tool-call-detail section:last-child pre { min-height: 180px; }
2853
2861
  @media (max-width: 680px) { .ai-tool-call-info { grid-template-columns: minmax(0, 1fr); }.ai-tool-call-detail pre { min-height: 100px; max-height: 26vh; }#ai-tool-call-arguments { min-height: 0; max-height: 20vh; }.ai-tool-call-detail section:last-child pre { min-height: 140px; } }
2862
+
2863
+ /* --- AI 可写工具:审批卡片 / 修改计划明细 / 用户提问 / 审批中心 --- */
2864
+ .ai-interactive-card { display: grid; gap: 8px; margin-top: 10px; padding: 11px 12px; border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: 5px; background: color-mix(in srgb, var(--surface-soft) 88%, transparent); }
2865
+ .ai-question-card { border-left-color: var(--task-running); }
2866
+ .ai-interactive-failure-card { border-left-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
2867
+ .ai-interactive-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
2868
+ .ai-interactive-card-head strong { color: var(--ink); font-size: 11px; }
2869
+ .ai-status-chip { flex: 0 0 auto; display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; border: 1px solid transparent; color: #fff; font-size: 9px; font-weight: 600; letter-spacing: .05em; white-space: nowrap; }
2870
+ .ai-status-chip[data-tone="pending"] { background: var(--accent); }
2871
+ .ai-status-chip[data-tone="running"] { background: var(--task-running); }
2872
+ .ai-status-chip[data-tone="success"] { background: var(--green); }
2873
+ .ai-status-chip[data-tone="danger"] { color: var(--accent-dark); border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
2874
+ .ai-status-chip[data-tone="muted"] { color: var(--muted); border-color: var(--line); background: var(--paper-deep); }
2875
+ .ai-interactive-summary { margin: 0; color: var(--ink); font-size: 11px; line-height: 1.55; overflow-wrap: anywhere; }
2876
+ .ai-interactive-meta { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; }
2877
+ .ai-interactive-meta > div { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
2878
+ .ai-interactive-meta dt { color: var(--muted); font-size: 9px; }
2879
+ .ai-interactive-meta dd { margin: 0; color: var(--ink); font-size: 10px; font-family: var(--font-latin), monospace; overflow-wrap: anywhere; }
2880
+ .ai-interactive-warn { margin: 0; padding: 6px 8px; border-radius: 4px; background: color-mix(in srgb, #c07b31 12%, var(--surface)); color: color-mix(in srgb, #c07b31 70%, black); font-size: 10px; line-height: 1.5; overflow-wrap: anywhere; }
2881
+ .ai-question-option-preview { display: grid; gap: 3px; margin: 0; padding-left: 18px; color: var(--muted); font-size: 10px; line-height: 1.5; }
2882
+ .ai-question-option-preview li.is-recommended { color: var(--accent-dark); }
2883
+ .ai-interactive-actions { display: flex; flex-wrap: wrap; gap: 5px; }
2884
+ .ai-interactive-actions button { border: 1px solid var(--line); border-radius: 3px; background: var(--surface); color: var(--muted); }
2885
+ .ai-interactive-actions :is(button.ghost-button, button.primary-button) { min-width: 0; min-height: 24px; padding: 3px 7px; font-size: calc(9px * var(--ai-font-scale)); line-height: 1.35; }
2886
+ .ai-interactive-actions button:hover, .ai-interactive-actions button:focus-visible { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); color: var(--ink); }
2887
+ .ai-interactive-actions .ai-card-primary { border-color: var(--accent); background: var(--accent); color: #fff; }
2888
+ .ai-interactive-actions .ai-card-primary:hover, .ai-interactive-actions .ai-card-primary:focus-visible { border-color: var(--accent-dark); background: var(--accent-dark); color: #fff; }
2889
+ .ai-interactive-actions .ai-card-danger:hover, .ai-interactive-actions .ai-card-danger:focus-visible { border-color: var(--accent); color: var(--accent-dark); }
2890
+ .ai-interactive-note { margin: 0; color: var(--muted); font-size: 9px; line-height: 1.55; }
2891
+ .ai-write-plan-dialog { width: min(880px, 94vw); }
2892
+ .ai-write-plan-body { display: grid; gap: 12px; max-height: 64vh; padding: 18px 24px 20px; overflow-y: auto; }
2893
+ .ai-plan-detail-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
2894
+ .ai-plan-detail-head .eyebrow { margin: 0; letter-spacing: .08em; text-transform: none; color: var(--muted); font-size: 10px; }
2895
+ .ai-plan-summary-title { margin: 2px 0 0; color: var(--muted); font-size: 10px; }
2896
+ .ai-plan-summary-text { margin: 0; color: var(--ink); font-size: 12px; line-height: 1.65; white-space: pre-wrap; overflow-wrap: anywhere; }
2897
+ .ai-plan-banner { margin: 0; padding: 9px 11px; border-radius: 4px; font-size: 10px; line-height: 1.55; }
2898
+ .ai-plan-banner.is-invalidated { background: color-mix(in srgb, #c07b31 14%, var(--surface)); color: color-mix(in srgb, #c07b31 70%, black); }
2899
+ .ai-plan-banner.is-failed { background: color-mix(in srgb, var(--accent) 10%, var(--surface)); color: var(--accent-dark); }
2900
+ .ai-operation-list { display: grid; gap: 10px; }
2901
+ .ai-operation-item { display: grid; gap: 8px; min-width: 0; padding: 11px 13px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); }
2902
+ .ai-operation-item.is-restricted { border-style: dashed; background: var(--paper-deep); }
2903
+ .ai-operation-item header { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
2904
+ .ai-operation-item h4 { margin: 0; color: var(--ink); font-size: 11px; }
2905
+ .ai-operation-item h5 { margin: 0; color: var(--muted); font-size: 11px; font-weight: 500; overflow-wrap: anywhere; }
2906
+ .ai-op-required { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; color: var(--muted); font-size: 9px; }
2907
+ .ai-op-required span { padding: 2px 7px; border: 1px solid var(--line); border-radius: 999px; background: var(--paper-deep); color: var(--muted); }
2908
+ .ai-op-annotation { display: grid; gap: 6px; padding: 9px 10px; border-radius: 4px; background: var(--paper-deep); }
2909
+ .ai-op-annotation > div { display: flex; align-items: baseline; gap: 8px; }
2910
+ .ai-op-annotation span { color: var(--muted); font-size: 9px; }
2911
+ .ai-op-annotation strong { color: var(--ink); font-size: 10px; }
2912
+ .ai-op-quote { margin: 0; padding: 7px 9px; border-left: 3px solid var(--task-running); border-radius: 3px; background: color-mix(in srgb, var(--surface) 70%, transparent); color: var(--ink); font-size: 10px; line-height: 1.6; white-space: pre-wrap; }
2913
+ .ai-op-note { margin: 0; color: var(--ink); font-size: 11px; line-height: 1.55; }
2914
+ .ai-op-task { display: grid; gap: 5px; padding: 9px 10px; border-radius: 4px; background: var(--paper-deep); }
2915
+ .ai-op-task div { display: flex; align-items: baseline; gap: 8px; }
2916
+ .ai-op-task span { color: var(--muted); font-size: 9px; }
2917
+ .ai-op-task strong { color: var(--ink); font-size: 10px; }
2918
+ .ai-op-task code { font-family: var(--font-latin), monospace; font-size: 10px; color: var(--ink); }
2919
+ .ai-field-diff-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
2920
+ .ai-field-diff-table th { padding: 4px 6px; border-bottom: 1px solid var(--line); color: var(--muted); font-size: 9px; font-weight: 600; text-align: left; }
2921
+ .ai-field-diff-table td { vertical-align: top; padding: 8px 6px; border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent); font-size: 11px; line-height: 1.55; color: var(--ink); }
2922
+ .ai-field-diff-table tr:last-child td { border-bottom: 0; }
2923
+ .ai-field-diff-table td:first-child { width: 26%; }
2924
+ .ai-field-diff-table td strong { display: block; color: var(--ink); font-size: 10px; }
2925
+ .ai-field-diff-table td small { display: block; margin-top: 2px; color: var(--muted); font-size: 9px; font-family: var(--font-latin), monospace; }
2926
+ .diff-value { white-space: pre-wrap; overflow-wrap: anywhere; }
2927
+ .diff-empty { color: var(--muted); font-size: 10px; }
2928
+ .diff-preview { margin: 6px 0 0; padding: 6px 8px; border-radius: 4px; font: 9px/1.5 var(--font-latin), monospace; white-space: pre-wrap; word-break: break-word; color: var(--ink); }
2929
+ .diff-preview.diff-remove { background: color-mix(in srgb, var(--accent) 10%, transparent); }
2930
+ .diff-preview.diff-add { background: color-mix(in srgb, var(--green) 14%, transparent); }
2931
+ .ai-op-result { display: grid; gap: 3px; padding-top: 8px; border-top: 1px dashed var(--line); }
2932
+ .ai-op-result strong { color: var(--green); font-size: 10px; }
2933
+ .ai-op-result p { margin: 0; color: var(--ink); font-size: 11px; line-height: 1.5; overflow-wrap: anywhere; }
2934
+ .ai-op-result small { color: var(--muted); font-size: 9px; font-family: var(--font-latin), monospace; }
2935
+ .ai-op-audits { display: grid; gap: 5px; margin: 0; padding: 8px 0 0; list-style: none; border-top: 1px dashed var(--line); }
2936
+ .ai-op-audits li { display: flex; justify-content: space-between; gap: 10px; color: var(--muted); font-size: 10px; }
2937
+ .ai-op-audits strong { color: var(--ink); }
2938
+ .ai-plan-audit-note { margin: 0; }
2939
+ .card-actions:is(.ai-plan-actions, .ai-question-actions) { flex-wrap: wrap; justify-content: flex-end; gap: 6px; margin-top: 0; padding: 14px 24px 20px; }
2940
+ .card-actions:is(.ai-plan-actions, .ai-question-actions) > button { flex: 0 0 auto; }
2941
+ .ai-question-dialog { width: min(540px, 92vw); }
2942
+ .ai-question-body { display: grid; gap: 12px; padding: 18px 22px 8px; }
2943
+ .ai-question-text { margin: 0; color: var(--ink); font-size: 13px; line-height: 1.65; overflow-wrap: anywhere; }
2944
+ .ai-question-options { display: grid; gap: 6px; }
2945
+ .ai-question-option-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--ink); font-size: 11px; line-height: 1.5; cursor: pointer; }
2946
+ .ai-question-option-item:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
2947
+ .ai-question-option-item.is-recommended { border-color: color-mix(in srgb, var(--accent) 20%, var(--line)); background: color-mix(in srgb, var(--accent) 3%, var(--surface)); }
2948
+ .ai-question-option-item.is-selected { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
2949
+ .ai-question-option-item input[type="radio"] { margin-top: 2px; accent-color: var(--accent); }
2950
+ .ai-question-custom-field { display: grid; gap: 5px; }
2951
+ .ai-question-custom-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
2952
+ .ai-question-custom-heading output { flex: 0 0 auto; color: var(--muted); font: 9px/1.4 var(--font-latin), monospace; font-variant-numeric: tabular-nums; }
2953
+ .ai-question-custom-field input[type="text"] { padding: 7px 9px; border: 1px solid var(--line); border-radius: 4px; background: var(--surface); color: var(--ink); font-size: 11px; }
2954
+ .ai-question-custom-field input[type="text"]:disabled { background: var(--paper-deep); color: var(--muted); }
2955
+ #ai-question-expiry { margin: 4px 0 0; }
2956
+ .ai-approval-center-dialog { width: min(780px, 94vw); }
2957
+ .ai-approval-center-body { display: grid; gap: 12px; padding: 16px 22px 22px; }
2958
+ .ai-approval-filters { display: flex; flex-wrap: wrap; gap: 6px; }
2959
+ .ai-approval-filters button { padding: 4px 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--muted); font-size: 10px; }
2960
+ .ai-approval-filters button[aria-pressed="true"] { border-color: var(--accent); background: var(--accent); color: #fff; }
2961
+ .ai-approval-list-host { min-height: 60px; }
2962
+ .ai-approval-list { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
2963
+ .ai-approval-row { display: flex; align-items: center; gap: 10px; width: 100%; min-width: 0; padding: 9px 11px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface); text-align: left; cursor: pointer; }
2964
+ .ai-approval-row:hover, .ai-approval-row:focus-visible { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
2965
+ .ai-approval-row-main { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
2966
+ .ai-approval-row-main strong { color: var(--ink); font-size: 11px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2967
+ .ai-approval-row-main small { color: var(--muted); font-size: 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2968
+ .ai-approval-row-open { flex: 0 0 auto; color: var(--accent-dark); font-size: 9px; }
2969
+ .ai-approval-empty { margin: 18px 0; }
2970
+ @media (max-width: 680px) {
2971
+ .ai-write-plan-body { padding: 14px 14px 16px; }
2972
+ :is(.ai-write-plan-dialog .ai-plan-actions, .ai-question-dialog .ai-question-actions) { padding: 12px 16px 16px; }
2973
+ .ai-approval-center-body, .ai-question-body { padding: 12px 14px 14px; }
2974
+ .ai-field-diff-table { table-layout: auto; }
2975
+ .ai-field-diff-table th:nth-child(2), .ai-field-diff-table th:nth-child(3) { font-size: 8px; }
2976
+ }
2977
+
2854
2978
  .guard-card { margin-top: 10px; padding: 9px 10px; border: 1px solid var(--line); border-left: 3px solid var(--green); border-radius: 4px; background: var(--surface-soft); }
2855
2979
  .guard-card.warning { border-left-color: #c07b31; }.guard-card.failed { border-left-color: var(--accent); }
2856
2980
  .guard-card strong { display: block; margin-bottom: 5px; font-size: 10px; }.guard-card p { margin: 4px 0; color: var(--muted); font-size: 9px; line-height: 1.45; }.guard-card p b { color: var(--ink); }
@@ -2902,6 +3026,51 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2902
3026
  .ai-attachment-button:disabled, .ai-scene-button:disabled { cursor: wait; opacity: .56; }
2903
3027
  .ai-scene-button.hidden { display: none; }
2904
3028
  .ai-image-button-icon, .ai-scene-button-icon { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
3029
+
3030
+ .character-roleplay-memory-surface { display: grid; grid-column: 1 / -1; gap: 14px; min-width: 0; }
3031
+ .roleplay-memory-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
3032
+ .roleplay-memory-toolbar button { min-height: 34px; }
3033
+ .roleplay-memory-filter-panel { display: grid; grid-template-columns: minmax(200px, 1fr) minmax(120px, .45fr) minmax(120px, .45fr) auto; align-items: end; gap: 8px; padding: 10px; border: 1px solid var(--line); border-radius: 6px; background: var(--paper); }
3034
+ .roleplay-memory-filter-panel.hidden { display: none; }
3035
+ .roleplay-memory-filter-panel label { display: grid; gap: 4px; color: var(--muted); font-size: 9px; }
3036
+ .roleplay-memory-filter-panel input, .roleplay-memory-filter-panel select, .roleplay-memory-filter-panel button { min-width: 0; min-height: 34px; padding: 6px 9px; font-size: 10px; }
3037
+ .roleplay-memory-list { display: grid; gap: 9px; }
3038
+ .roleplay-memory-empty { display: grid; place-items: center; min-height: 160px; margin: 0; border: 1px dashed var(--line); border-radius: 6px; color: var(--muted); font-size: 11px; text-align: center; }
3039
+ .roleplay-memory-card { display: grid; gap: 8px; padding: 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); }
3040
+ .roleplay-memory-card.is-archived { opacity: .72; }
3041
+ .roleplay-memory-card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
3042
+ .roleplay-memory-card-badges { display: flex; flex-wrap: wrap; gap: 5px; }
3043
+ .roleplay-memory-badge { display: inline-flex; align-items: center; min-height: 21px; padding: 2px 6px; border: 1px solid var(--line); border-radius: 999px; background: var(--paper); color: var(--muted); font-size: 8px; }
3044
+ .roleplay-memory-badge.is-noncanonical { border-color: color-mix(in srgb, #bf6a35 48%, var(--line)); color: #a34f20; }
3045
+ .roleplay-memory-badge.is-pinned { border-color: color-mix(in srgb, var(--accent) 48%, var(--line)); color: var(--accent-dark); }
3046
+ .roleplay-memory-card time { flex: 0 0 auto; color: var(--muted); font-size: 8px; }
3047
+ .roleplay-memory-content { margin: 0; color: var(--ink); font-size: 11px; line-height: 1.65; white-space: pre-wrap; overflow-wrap: anywhere; }
3048
+ .roleplay-memory-card-meta { margin: 0; color: var(--muted); font-size: 9px; }
3049
+ .roleplay-memory-sources { border-top: 1px solid var(--line); padding-top: 7px; }
3050
+ .roleplay-memory-sources summary { color: var(--muted); font-size: 9px; cursor: pointer; }
3051
+ .roleplay-memory-source-list { display: grid; gap: 6px; margin-top: 7px; }
3052
+ .roleplay-memory-source { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 7px; padding: 7px; border-radius: 4px; background: var(--paper); }
3053
+ .roleplay-memory-source p { margin: 0; color: var(--muted); font-size: 9px; line-height: 1.5; overflow-wrap: anywhere; }
3054
+ .roleplay-memory-source button { min-height: 29px; padding: 4px 7px; font-size: 9px; }
3055
+ .roleplay-memory-card-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
3056
+ .roleplay-memory-card-actions button { min-height: 30px; padding: 5px 8px; font-size: 9px; }
3057
+ .roleplay-memory-card-actions .roleplay-memory-icon-action { display: inline-grid; place-items: center; width: 30px; min-width: 30px; height: 30px; min-height: 30px; padding: 0; }
3058
+ .roleplay-memory-icon-action svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
3059
+ .roleplay-memory-card-actions .danger-button.roleplay-memory-icon-action { border-color: color-mix(in srgb, #d9363e 62%, var(--line)); color: #d9363e; }
3060
+ .roleplay-memory-card-actions .danger-button.roleplay-memory-icon-action:hover, .roleplay-memory-card-actions .danger-button.roleplay-memory-icon-action:focus-visible { border-color: #d9363e; background: color-mix(in srgb, #d9363e 11%, transparent); }
3061
+ .roleplay-memory-icon-action.is-pinned { border-width: 1px; border-style: solid; border-color: color-mix(in srgb, var(--accent) 58%, var(--line)); background: color-mix(in srgb, var(--accent) 10%, var(--surface)); color: var(--accent-dark); }
3062
+ .roleplay-memory-pagination { margin-top: 2px; }
3063
+
3064
+ @media (max-width: 640px) {
3065
+ .roleplay-memory-filter-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
3066
+ .roleplay-memory-filter-panel label:first-child { grid-column: 1 / -1; }
3067
+ .roleplay-memory-filter-panel button { width: 100%; }
3068
+ .roleplay-memory-card-header { display: grid; }
3069
+ .roleplay-memory-source { grid-template-columns: minmax(0, 1fr); }
3070
+ .roleplay-memory-source button { justify-self: start; }
3071
+ .roleplay-memory-card-actions button { min-height: 34px; }
3072
+ .roleplay-memory-card-actions .roleplay-memory-icon-action { width: 34px; min-width: 34px; height: 34px; min-height: 34px; }
3073
+ }
2905
3074
  .ai-mention-menu { position: absolute; z-index: 20; left: 0; right: 0; bottom: calc(100% + 6px); max-height: 230px; overflow-y: auto; padding: 6px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); box-shadow: 0 12px 34px rgba(49,42,32,.18); }
2906
3075
  .ai-mention-option { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 8px; width: 100%; padding: 7px 8px; border: 0; border-radius: 4px; background: transparent; text-align: left; }
2907
3076
  .ai-mention-option:hover, .ai-mention-option:focus-visible, .ai-mention-option.is-active { background: var(--paper-deep); }
@@ -3512,6 +3681,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3512
3681
  #character-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
3513
3682
  #knowledge-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
3514
3683
  .entity-editor-header, .character-editor-header { display: grid; grid-template-columns: minmax(160px, 1fr) minmax(0, 2fr) minmax(160px, 1fr); align-items: center; gap: 24px; min-height: 78px; padding: 14px clamp(18px, 3vw, 44px); border-bottom: 1px solid var(--line); background: var(--panel); }
3684
+ .character-editor-header { grid-template-columns: minmax(160px, 1fr) minmax(0, 2fr) auto; }
3515
3685
  .entity-editor-heading { min-width: 0; text-align: center; }
3516
3686
  .entity-editor-heading h1 { overflow: hidden; margin: 2px 0 0; font-size: 24px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
3517
3687
  .entity-editor-readonly-badge { display: inline-block; width: fit-content; margin: 0 auto; padding: 3px 7px; border: 1px solid color-mix(in srgb, var(--muted) 55%, var(--line)); border-radius: 999px; color: var(--muted); font-size: 10px; line-height: 1.2; }
@@ -3522,9 +3692,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3522
3692
  .entity-editor-back:hover { border-color: var(--accent); color: var(--accent-dark); }
3523
3693
  #setting-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr); }
3524
3694
  .setting-editor-header { min-height: 112px; }
3525
- .setting-editor-heading { display: grid; align-content: center; gap: 8px; }
3526
- .setting-editor-title-input { width: min(100%, 520px); margin: 0 auto; padding: 0 0 4px; border: 0; border-bottom: 1px solid transparent; border-radius: 0; background: transparent; color: var(--ink); font-size: 24px; font-weight: 600; line-height: 1.2; text-align: center; }
3527
- .setting-editor-title-input::placeholder { color: var(--ink); opacity: .92; }
3695
+ .setting-editor-header .entity-editor-heading { display: grid; align-content: center; justify-items: center; gap: 8px; text-align: center; }
3696
+ .setting-editor-title-input { display: block; width: min(100%, 520px); margin: 0 auto; padding: 0 0 4px; border: 0; border-bottom: 1px solid transparent; border-radius: 0; background: transparent; color: var(--ink); font-size: 22px; font-weight: 600; line-height: 1.2; text-align: center; }
3697
+ .setting-editor-title-input::placeholder { color: var(--muted); opacity: 1; }
3528
3698
  .setting-editor-title-input:focus { border-color: var(--accent); box-shadow: none; }
3529
3699
  .setting-editor-header-fields { display: flex; align-items: center; justify-content: center; gap: 14px; min-width: 0; }
3530
3700
  .setting-editor-header-fields > label:not(.setting-editor-lock) { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 10px; white-space: nowrap; }
@@ -3594,6 +3764,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3594
3764
  .knowledge-editor-header-note { color: var(--muted); font-size: 10px; text-align: right; }
3595
3765
  .character-version-badge { display: inline-flex; align-items: center; min-height: 22px; padding: 2px 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--paper-deep); color: var(--accent-dark); font: 10px/1 var(--font-latin), monospace; }
3596
3766
  .character-editor-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
3767
+ .character-editor-header-actions > .primary-button, .character-editor-header-actions > .ghost-button { flex: 0 0 auto; white-space: nowrap; }
3597
3768
  .character-editor-header-actions .ghost-button { min-height: 34px; }
3598
3769
  .character-editor-header-actions .ghost-button:disabled { cursor: not-allowed; opacity: .46; }
3599
3770
  .character-editor-workspace { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 0; }
@@ -3608,6 +3779,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3608
3779
  .character-editor-section > header { display: flex; align-items: end; justify-content: space-between; gap: 24px; padding-bottom: 14px; border-bottom: 1px solid var(--line); }
3609
3780
  .character-editor-section > header h3 { margin: 2px 0 0; font-size: 21px; }
3610
3781
  .character-editor-section > header p { max-width: 430px; margin: 0; color: var(--muted); font-size: 10px; line-height: 1.55; text-align: right; }
3782
+ .character-editor-section.has-header-actions > header { align-items: center; }
3783
+ .character-editor-section.has-header-actions > header > .character-editor-section-header-copy { display: grid; gap: 4px; min-width: 0; }
3784
+ .character-editor-section.has-header-actions > header > .character-editor-section-header-copy > p { max-width: 620px; text-align: left; }
3785
+ .character-editor-section.has-header-actions > header .roleplay-memory-toolbar { flex: 0 0 auto; }
3611
3786
  .character-editor-section-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 17px 20px; }
3612
3787
  .character-editor-section-fields > label, .character-editor-section-fields > .form-field { display: grid; align-content: start; gap: 7px; color: var(--muted); font-size: 11px; }
3613
3788
  .character-editor-section-fields > label:has(textarea), .character-editor-section-fields > .form-field:has(textarea), .character-editor-section-fields > .structured-list-field, .character-editor-section-fields > .chip-field, .character-editor-section-fields > .markdown-editor-field, .character-editor-field-help { grid-column: 1 / -1; }
@@ -3854,7 +4029,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3854
4029
  .entity-editor-back::before { margin-right: 18px; }
3855
4030
  .setting-editor-header { min-height: 102px; }
3856
4031
  .setting-editor-header-fields { flex-wrap: wrap; gap: 8px 12px; }
3857
- .setting-editor-title-input { font-size: 18px; }
4032
+ .setting-editor-title-input { font-size: 16px; }
3858
4033
  .setting-editor-workspace { overflow-y: auto; }
3859
4034
  .setting-editor-content { height: auto; min-height: 70dvh; padding: 16px; }
3860
4035
  .setting-markdown-field { height: 70dvh; }
@@ -3870,6 +4045,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3870
4045
  .character-editor-section-fields > label, .character-editor-section-fields > .form-field, .character-editor-field-help { grid-column: 1; }
3871
4046
  .character-editor-section > header { align-items: flex-start; flex-direction: column; gap: 7px; }
3872
4047
  .character-editor-section > header p { text-align: left; }
4048
+ .character-editor-section.has-header-actions > header { align-items: flex-end; flex-direction: row; }
4049
+ .character-editor-section.has-header-actions > header > .character-editor-section-header-copy { min-width: 0; }
3873
4050
  .character-markdown-editor { overflow: hidden; }
3874
4051
  .character-markdown-editor > .vditor-editor-host { min-height: 42dvh; }
3875
4052
  .character-markdown-editor-meta { grid-template-columns: minmax(0, 1fr); }
@@ -4094,6 +4271,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4094
4271
  .editor-view .editor-actions > button { min-width: 0; min-height: 34px; padding-inline: 6px; font-size: 11px; }
4095
4272
  .chapter-title { font-size: 21px; }
4096
4273
  .chapter-content { padding: 22px 16px 64px 12px; font-size: max(16px, var(--editor-font-size)); }
4274
+ .app-shell.editor-typewriter-mode .chapter-content { padding-bottom: max(64px, 45dvh); }
4097
4275
  .chapter-line-numbers { width: 32px; font-size: 11px; }
4098
4276
  .chapter-editor-frame { grid-template-columns: 32px minmax(0, 1fr); }
4099
4277
  .chapter-line-measure { left: 32px; }
@@ -4181,6 +4359,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4181
4359
  .access-row { grid-template-columns: minmax(0, 1fr); align-items: stretch; }
4182
4360
  .access-row select, .access-row button, .work-access-field .ghost-button { width: 100%; }
4183
4361
  .work-access-field { align-items: stretch; flex-direction: column; }
4362
+ .work-editor-preference-options { flex-basis: auto; width: 100%; }
4184
4363
  .work-access-field .danger-button { width: 100%; }
4185
4364
 
4186
4365
  .recycle-bin-card { grid-template-columns: minmax(0, 1fr); gap: 7px; }
@@ -4190,6 +4369,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4190
4369
 
4191
4370
  .entity-editor-view { min-width: 0; }
4192
4371
  .entity-editor-header, .character-editor-header { grid-template-columns: auto minmax(0, 1fr); gap: 8px; padding: 12px var(--mobile-gutter); }
4372
+ .setting-editor-header .entity-editor-heading { grid-column: 1 / -1; grid-row: 1; padding-inline: 48px; }
4373
+ .setting-editor-header > .entity-editor-back { z-index: 1; grid-column: 1; grid-row: 1; }
4193
4374
  .entity-editor-mode-actions, .character-editor-header-actions { grid-column: 1 / -1; justify-content: stretch; flex-wrap: wrap; }
4194
4375
  .entity-editor-mode-actions > button, .character-editor-header-actions > button { flex: 1 1 auto; }
4195
4376
  .entity-editor-mode-actions > .entity-detail-favorite-button, .entity-editor-mode-actions > .entity-detail-pin-button, .character-editor-header-actions > .entity-detail-favorite-button, .character-editor-header-actions > .entity-detail-pin-button { flex: 0 0 40px; width: 40px; min-width: 40px; height: 40px; }
@@ -8,11 +8,35 @@
8
8
  // 登录页路由首帧直接显示登录卡片,避免出现"骨架屏 → 登录页"的跳变
9
9
  const routeParams = new URLSearchParams(window.location.hash.replace(/^#/, ""));
10
10
  const routeView = routeParams.get("view") ?? "";
11
+ const routeWorkId = routeParams.get("work") ?? "";
12
+ const routeChapterId = routeParams.get("chapter") ?? "";
13
+ const prefetchData = (path, key) => fetch(path, { headers: { Accept: "application/json" }, priority: "high" })
14
+ .then(async (response) => {
15
+ const payload = await response.json().catch(() => null);
16
+ if (!response.ok) throw new Error(payload?.error?.message ?? "首屏预取失败");
17
+ return { [key]: payload?.data };
18
+ })
19
+ .catch((error) => ({ error }));
20
+ if (routeView === "reader" && routeChapterId && routeChapterId.length <= 200) {
21
+ window.__scriverseReaderChapterPrefetch = {
22
+ chapterId: routeChapterId,
23
+ request: prefetchData(`/api/chapters/${encodeURIComponent(routeChapterId)}`, "chapter")
24
+ };
25
+ }
26
+ if (routeView === "reader" && routeWorkId && routeWorkId.length <= 200) {
27
+ window.__scriverseReaderWorksPrefetch = {
28
+ request: prefetchData("/api/works?page=1&limit=30", "works")
29
+ };
30
+ window.__scriverseReaderWorkPrefetch = {
31
+ workId: routeWorkId,
32
+ request: prefetchData(`/api/works/${encodeURIComponent(routeWorkId)}?directory=volumes`, "work")
33
+ };
34
+ }
11
35
  if (routeView === "login") {
12
36
  document.documentElement.classList.add("login-route");
13
37
  } else {
14
38
  // 会话恢复期间按目标路由预显示对应视图的骨架屏
15
- const pendingView = ["editor", "module", "welcome"].includes(routeView) && routeParams.get("work")
39
+ const pendingView = ["editor", "module", "welcome", "reader"].includes(routeView) && routeParams.get("work")
16
40
  ? routeView
17
41
  : ["settings", "platform-ai", "platform-usage", "work-audit"].includes(routeView) ? routeView : "shelf";
18
42
  document.documentElement.dataset.pendingView = pendingView;
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ export const ROLEPLAY_MEMORY_CATEGORIES = ["event", "state", "relationship", "commitment", "knowledge", "scene"];
3
+ export const ROLEPLAY_MEMORY_IMPORTANCE = ["low", "medium", "high"];
4
+ export const ROLEPLAY_MEMORY_CERTAINTY = ["experienced", "observed", "heard", "believed"];
5
+ export const ROLEPLAY_MEMORY_STATUSES = ["active", "superseded", "archived"];
6
+ export const roleplayMemoryCandidateSchema = z.object({
7
+ category: z.enum(ROLEPLAY_MEMORY_CATEGORIES),
8
+ content: z.string().trim().min(1).max(500),
9
+ importance: z.enum(ROLEPLAY_MEMORY_IMPORTANCE).default("medium"),
10
+ certainty: z.enum(ROLEPLAY_MEMORY_CERTAINTY).default("experienced"),
11
+ supersedesMemoryId: z.string().trim().min(1).max(200).optional()
12
+ }).strict();
13
+ export const rememberRoleplayArgumentsSchema = z.object({
14
+ memories: z.array(roleplayMemoryCandidateSchema).min(1).max(8)
15
+ }).strict();
16
+ export const recallRoleplayMemoryArgumentsSchema = z.object({
17
+ query: z.string().trim().max(200).default(""),
18
+ categories: z.array(z.enum(ROLEPLAY_MEMORY_CATEGORIES)).max(ROLEPLAY_MEMORY_CATEGORIES.length).default([]),
19
+ cursor: z.number().int().min(0).max(100_000).default(0)
20
+ }).strict();
21
+ export function normalizeRoleplayMemoryContent(value, maximumLength = 2_000) {
22
+ return Array.from(value.normalize("NFC")
23
+ .replace(/\r\n?/gu, "\n")
24
+ .replace(/[\t ]+/gu, " ")
25
+ .replace(/\n{3,}/gu, "\n\n")
26
+ .trim()).slice(0, maximumLength).join("");
27
+ }
28
+ export function roleplayMemoryCandidateIsSafe(value) {
29
+ const normalized = value.normalize("NFKC").toLocaleLowerCase("zh-CN");
30
+ const forbidden = [
31
+ /<\/?(?:system|developer|tool)(?:\s|>)/u,
32
+ /(?:system prompt|developer message|系统提示(?:词)?|开发者消息)/u,
33
+ /\b(?:bearer\s+[a-z0-9._-]{12,}|sk-[a-z0-9_-]{12,}|api[_ -]?key\s*[:=]\s*\S+)/iu,
34
+ /(?:密码|口令|密钥|令牌)\s*[:=]\s*\S{8,}/u
35
+ ];
36
+ return forbidden.every((pattern) => !pattern.test(normalized));
37
+ }
38
+ export function renderRoleplayMemoriesForPrompt(memories) {
39
+ return JSON.stringify({
40
+ origin: "roleplay",
41
+ canonical: false,
42
+ memories: memories.map((memory) => ({
43
+ id: memory.id,
44
+ category: memory.category,
45
+ content: memory.content,
46
+ importance: memory.importance,
47
+ certainty: memory.certainty,
48
+ status: memory.status,
49
+ isPinned: memory.isPinned
50
+ }))
51
+ });
52
+ }
53
+ //# sourceMappingURL=roleplay-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roleplay-memory.js","sourceRoot":"","sources":["../src/roleplay-memory.ts"],"names":[],"mappings":"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"}