@musnows/scriverse 0.9.3 → 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); }
@@ -1437,9 +1444,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1437
1444
  .editor-view { container-name: editor-workspace; container-type: inline-size; display: grid; grid-template-rows: auto auto minmax(0, 1fr); height: 100%; }
1438
1445
  .editor-toolbar { position: relative; display: grid; grid-row: 1; grid-template-areas: "path path" "title actions"; grid-template-columns: minmax(0, 1fr) auto; align-items: flex-end; column-gap: 20px; row-gap: 6px; padding: 25px 7% 18px; border-bottom: 1px solid var(--line); }
1439
1446
  #chapter-path { grid-area: path; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1440
- .chapter-title { grid-area: title; display: block; width: 100%; min-width: 0; border: 0; border-radius: 0; background: transparent; font-size: 27px; padding: 0; }
1447
+ .chapter-title { grid-area: title; display: block; width: 100%; min-width: 0; border: 0; border-radius: 0; background: transparent; font-size: 25px; padding: 0; }
1441
1448
  .chapter-title:focus { box-shadow: none; border-bottom: 1px solid var(--accent); }
1442
- .editor-actions { grid-area: actions; display: flex; align-items: center; gap: 10px; }
1449
+ .editor-actions { grid-area: actions; display: flex; align-items: center; gap: 8px; }
1450
+ .editor-view .editor-actions > button { min-height: 32px; padding: 6px 10px; font-size: 11px; }
1443
1451
  .chapter-stats { color: var(--muted); font-size: 11px; }
1444
1452
  .chapter-search-panel { position: absolute; z-index: 8; top: calc(100% + 8px); right: 7%; display: grid; width: min(520px, calc(100% - 14%)); gap: 12px; padding: 14px; border: 1px solid var(--line-strong); outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 7px; background: var(--panel); box-shadow: 0 16px 36px rgba(36, 30, 24, .22); }
1445
1453
  .chapter-search-panel-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
@@ -1492,6 +1500,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1492
1500
  .chapter-line-number.is-line-selected { background: rgba(139,61,44,.16); color: var(--accent-dark); font-weight: 700; }
1493
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; }
1494
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); }
1495
1504
  .chapter-content:focus { box-shadow: none; }
1496
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; }
1497
1506
  .chapter-whitespace-overlay.is-visible { opacity: 1; }
@@ -1557,7 +1566,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
1557
1566
  .entity-detail-pin-button:hover, .entity-detail-pin-button:focus-visible { border-color: var(--accent); color: var(--accent-dark); outline: none; }
1558
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); }
1559
1568
  .entity-detail-pin-button:disabled { cursor: not-allowed; opacity: .5; }
1560
- .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); }
1561
1570
  .entity-detail-pin-button.is-pinned svg { fill: currentColor; }
1562
1571
  .record-card h3 { font-size: 16px; margin: 5px 0 10px; font-weight: 600; }
1563
1572
  .record-card p { color: var(--muted); font-size: 12px; line-height: 1.55; margin: 0; white-space: pre-wrap; }
@@ -2807,7 +2816,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2807
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); }
2808
2817
  .message-body .markdown-image small { color: var(--muted); font-size: 9px; line-height: 1.45; text-align: center; }
2809
2818
  .message-meta { margin-top: 8px; color: var(--muted); font-size: 9px; }
2810
- .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; }
2811
2820
  .message-meta .ai-stream-connection-seconds { display: inline-block; min-width: 3ch; font-variant-numeric: tabular-nums; text-align: right; }
2812
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); }
2813
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; }
@@ -2850,6 +2859,122 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2850
2859
  #ai-tool-call-arguments { min-height: 0; max-height: 26vh; }
2851
2860
  .ai-tool-call-detail section:last-child pre { min-height: 180px; }
2852
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
+
2853
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); }
2854
2979
  .guard-card.warning { border-left-color: #c07b31; }.guard-card.failed { border-left-color: var(--accent); }
2855
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); }
@@ -2901,6 +3026,51 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2901
3026
  .ai-attachment-button:disabled, .ai-scene-button:disabled { cursor: wait; opacity: .56; }
2902
3027
  .ai-scene-button.hidden { display: none; }
2903
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
+ }
2904
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); }
2905
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; }
2906
3076
  .ai-mention-option:hover, .ai-mention-option:focus-visible, .ai-mention-option.is-active { background: var(--paper-deep); }
@@ -2961,7 +3131,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
2961
3131
  .ai-context-distribution-row[data-key="system-prompt"] { --distribution-color: var(--accent); }
2962
3132
  .ai-context-distribution-row[data-key="function"] { --distribution-color: #9a7651; }
2963
3133
  .ai-context-distribution-row[data-key="skills"] { --distribution-color: var(--muted); }
2964
- .ai-context-distribution-row[data-key="context"] { --distribution-color: var(--green); }
3134
+ .ai-context-distribution-row[data-key="input"] { --distribution-color: var(--green); }
3135
+ .ai-context-distribution-row[data-key="output"] { --distribution-color: #718a9f; }
2965
3136
  .ai-context-distribution-row[data-key="left"] { --distribution-color: color-mix(in srgb, var(--muted) 55%, transparent); }
2966
3137
  .ai-send-button { display: grid; flex: 0 0 32px; place-items: center; width: 32px; min-width: 32px; min-height: 32px; height: 32px; padding: 0; border: 0; border-radius: 4px; background: var(--accent); color: #fff; box-shadow: 0 4px 12px rgba(139,61,44,.2); }
2967
3138
  .ai-send-button:hover, .ai-send-button:focus-visible { background: var(--accent-dark); outline: 0; }
@@ -3510,6 +3681,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3510
3681
  #character-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
3511
3682
  #knowledge-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
3512
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; }
3513
3685
  .entity-editor-heading { min-width: 0; text-align: center; }
3514
3686
  .entity-editor-heading h1 { overflow: hidden; margin: 2px 0 0; font-size: 24px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
3515
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; }
@@ -3520,9 +3692,9 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3520
3692
  .entity-editor-back:hover { border-color: var(--accent); color: var(--accent-dark); }
3521
3693
  #setting-editor-form { display: grid; grid-template-rows: auto minmax(0, 1fr); }
3522
3694
  .setting-editor-header { min-height: 112px; }
3523
- .setting-editor-heading { display: grid; align-content: center; gap: 8px; }
3524
- .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; }
3525
- .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; }
3526
3698
  .setting-editor-title-input:focus { border-color: var(--accent); box-shadow: none; }
3527
3699
  .setting-editor-header-fields { display: flex; align-items: center; justify-content: center; gap: 14px; min-width: 0; }
3528
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; }
@@ -3592,6 +3764,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3592
3764
  .knowledge-editor-header-note { color: var(--muted); font-size: 10px; text-align: right; }
3593
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; }
3594
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; }
3595
3768
  .character-editor-header-actions .ghost-button { min-height: 34px; }
3596
3769
  .character-editor-header-actions .ghost-button:disabled { cursor: not-allowed; opacity: .46; }
3597
3770
  .character-editor-workspace { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 0; }
@@ -3606,6 +3779,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3606
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); }
3607
3780
  .character-editor-section > header h3 { margin: 2px 0 0; font-size: 21px; }
3608
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; }
3609
3786
  .character-editor-section-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 17px 20px; }
3610
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; }
3611
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; }
@@ -3852,7 +4029,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3852
4029
  .entity-editor-back::before { margin-right: 18px; }
3853
4030
  .setting-editor-header { min-height: 102px; }
3854
4031
  .setting-editor-header-fields { flex-wrap: wrap; gap: 8px 12px; }
3855
- .setting-editor-title-input { font-size: 18px; }
4032
+ .setting-editor-title-input { font-size: 16px; }
3856
4033
  .setting-editor-workspace { overflow-y: auto; }
3857
4034
  .setting-editor-content { height: auto; min-height: 70dvh; padding: 16px; }
3858
4035
  .setting-markdown-field { height: 70dvh; }
@@ -3868,6 +4045,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
3868
4045
  .character-editor-section-fields > label, .character-editor-section-fields > .form-field, .character-editor-field-help { grid-column: 1; }
3869
4046
  .character-editor-section > header { align-items: flex-start; flex-direction: column; gap: 7px; }
3870
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; }
3871
4050
  .character-markdown-editor { overflow: hidden; }
3872
4051
  .character-markdown-editor > .vditor-editor-host { min-height: 42dvh; }
3873
4052
  .character-markdown-editor-meta { grid-template-columns: minmax(0, 1fr); }
@@ -4089,9 +4268,10 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4089
4268
  .editor-actions { position: static; z-index: auto; right: auto; bottom: auto; left: auto; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; max-width: none; gap: 6px; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; transform: none; transition: none; }
4090
4269
  .app-shell.left-panel-collapsed .editor-actions { transform: none; pointer-events: auto; }
4091
4270
  .editor-actions .chapter-stats { grid-column: 1 / -1; }
4092
- .editor-actions > button { min-width: 0; min-height: 36px; padding-inline: 8px; font-size: 11px; }
4093
- .chapter-title { font-size: 23px; }
4271
+ .editor-view .editor-actions > button { min-width: 0; min-height: 34px; padding-inline: 6px; font-size: 11px; }
4272
+ .chapter-title { font-size: 21px; }
4094
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); }
4095
4275
  .chapter-line-numbers { width: 32px; font-size: 11px; }
4096
4276
  .chapter-editor-frame { grid-template-columns: 32px minmax(0, 1fr); }
4097
4277
  .chapter-line-measure { left: 32px; }
@@ -4179,6 +4359,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4179
4359
  .access-row { grid-template-columns: minmax(0, 1fr); align-items: stretch; }
4180
4360
  .access-row select, .access-row button, .work-access-field .ghost-button { width: 100%; }
4181
4361
  .work-access-field { align-items: stretch; flex-direction: column; }
4362
+ .work-editor-preference-options { flex-basis: auto; width: 100%; }
4182
4363
  .work-access-field .danger-button { width: 100%; }
4183
4364
 
4184
4365
  .recycle-bin-card { grid-template-columns: minmax(0, 1fr); gap: 7px; }
@@ -4188,6 +4369,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
4188
4369
 
4189
4370
  .entity-editor-view { min-width: 0; }
4190
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; }
4191
4374
  .entity-editor-mode-actions, .character-editor-header-actions { grid-column: 1 / -1; justify-content: stretch; flex-wrap: wrap; }
4192
4375
  .entity-editor-mode-actions > button, .character-editor-header-actions > button { flex: 1 1 auto; }
4193
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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"}