/* ==========================================================================
   ai风月 · 设计系统
   冷白底 + 冷灰线 + 一个明亮的玫瑰色强调。不用纸纹、不用暖褐、不用衬线 ——
   就是一个 2020 年代的普通应用界面：白底、细线、大圆角、一个颜色只用在动作上。
   ========================================================================== */

:root {
  --bg: #FFFFFF;
  --bg2: #F4F5F7;
  --bg3: #E9EBEF;
  --side: #F7F8FA;
  --ink: #14151A;
  --mid: #5F6472;
  --faint: #9AA0AC;
  --line: #ECEDF1;
  --line2: #D8DAE0;
  --hover: #EFF1F5;
  --accent: #D6356E;
  --on-accent: #FFFFFF;
  --warn: #E5484D;
  --on-ink: #FFFFFF;
  --r: 12px;

  --rail: 320px;
  --top: 52px;

  --sans: "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Microsoft YaHei",
    "Noto Sans SC", -apple-system, BlinkMacSystemFont, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Courier New", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0E0F12;
    --bg2: #1A1C21;
    --bg3: #24272E;
    --side: #14161A;
    --ink: #F2F3F5;
    --mid: #A2A7B4;
    --faint: #6C7280;
    --line: #22242A;
    --line2: #34373F;
    --hover: #1E2127;
    --accent: #FF6E9C;
    --on-accent: #2A0A16;
    --warn: #FF6369;
    --on-ink: #0E0F12;
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.75 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
}
h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
button, input, textarea, select { font: inherit; color: inherit; }
button { font-family: inherit; }
img { display: block; }
::selection { background: var(--ink); color: var(--on-ink); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }

* { scrollbar-width: thin; scrollbar-color: var(--line2) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--line2); border: 3px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-track { background: transparent; }

.hint { font: 400 12px/1.7 var(--sans); color: var(--faint); }
.suggest[hidden] { display: none; }
.statline {
  display: flex; flex-wrap: wrap; gap: 22px;
  padding: 16px 24px; border-bottom: 1px solid var(--line);
  font: 400 11.5px/1 var(--mono); color: var(--mid);
}
.statline b { font-weight: 400; color: var(--ink); }
.mono { font-family: var(--mono); }
.muted { color: var(--mid); }
.faint { color: var(--faint); }
.small { font-size: 12.5px; }

/* ==========================================================================
   外壳：顶栏 + 清单 + 工作区
   ========================================================================== */

.app { display: flex; flex-direction: column; height: 100%; }

.topbar {
  height: var(--top); flex: none;
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(14px) saturate(1.6);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  position: relative; z-index: 5;
}
.topbar .brand { font: 600 15px/1 var(--sans); letter-spacing: -.01em; }
.topbar .host {
  font: 400 11.5px/1 var(--mono); color: var(--faint);
  padding-left: 12px; border-left: 1px solid var(--line);
  max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar .acts { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.topbar .acts .btn { border-color: transparent; }
.topbar .acts .btn:hover { background: var(--hover); border-color: transparent; }
.topbar .acts .btn-solid, .topbar .acts .btn-primary { border-color: var(--accent); }
@media (prefers-color-scheme: dark) {
  .topbar { background: rgba(14, 15, 18, .82); }
}

.body { flex: 1; display: flex; min-height: 0; }

/* 左栏：导航 + 最近 */
.rail {
  width: var(--rail); flex: none;
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; min-height: 0;
  background: var(--side);
}
.rail .rail-h {
  height: 38px; flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: 0 16px; border-bottom: 1px solid var(--line);
  font: 600 11.5px/1 var(--sans); letter-spacing: .02em; color: var(--mid);
}
.rail .rail-h span { font: 400 10px/1 var(--mono); letter-spacing: 0; }
.nav-block { flex: none; padding: 8px 8px 10px; border-bottom: 1px solid var(--line); }
.nav-block a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 10px;
  text-decoration: none; color: var(--mid);
  font: 400 13.5px/1 var(--sans); cursor: pointer;
}
.nav-block a:hover { background: var(--hover); color: var(--ink); }
.nav-block a.on {
  font-weight: 600; color: var(--accent); background: var(--bg);
  box-shadow: 0 1px 2px rgba(16, 18, 22, .07), inset 0 0 0 1px var(--line);
}
.nav-block a em { margin-left: auto; font: 400 10.5px/1 var(--mono); font-style: normal; color: var(--faint); }
.rail .rows { flex: 1; overflow-y: auto; min-height: 0; }
.rail .rail-f {
  flex: none; height: 38px; border-top: 1px solid var(--line);
  display: flex; align-items: center; padding: 0 16px; gap: 12px;
  font: 400 10px/1 var(--mono); color: var(--faint);
}

.r {
  display: grid; grid-template-columns: 48px 1fr 56px; gap: 12px; align-items: center;
  height: 68px; margin: 0 8px 2px; padding: 0 10px; border-radius: 12px; cursor: pointer;
}
.r:hover { background: var(--hover); }
.r.on { background: var(--bg); box-shadow: 0 1px 3px rgba(16, 18, 22, .07); }
.r .tm { font: 400 10px/1.4 var(--mono); color: var(--faint); }
.r .nm { font: 600 13.5px/1.3 var(--sans); display: flex; align-items: center; gap: 6px; }
.r .nm i { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
.r .ln {
  font: 400 11.5px/1.5 var(--sans); color: var(--mid); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.r .sq { width: 40px; height: 40px; overflow: hidden; background: var(--bg2); border-radius: 9px; }
.r .sq img { width: 100%; height: 100%; object-fit: cover; }
.r .r-x {
  position: absolute; right: 12px; border: 0; background: none; color: var(--faint);
  cursor: pointer; padding: 4px 6px; font-size: 12px; opacity: 0;
}
.r { position: relative; }
.r:hover .r-x { opacity: 1; }
.r .r-x:hover { color: var(--warn); }
.rail-empty { padding: 18px 16px; font: 400 11.5px/1.8 var(--sans); color: var(--faint); }

/* ==========================================================================
   工作区
   ========================================================================== */

.work { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; background: var(--bg);
  position: relative; overflow: hidden; }
.work-scroll { flex: 1; min-height: 0; overflow-y: auto; }

.pagehead {
  display: flex; align-items: flex-end; gap: 16px;
  padding: 24px 24px 16px;
}
.pagehead .t { flex: 1; min-width: 0; }
.pagehead h1 { font-size: 24px; letter-spacing: -.01em; }
.pagehead .sub { font: 400 11px/1.6 var(--mono); color: var(--mid); margin-top: 7px; }
.pagehead .sub b { font-weight: 400; color: var(--ink); }
.pagehead .acts { display: flex; align-items: center; gap: 8px; flex: none; }

/* 按钮：方角、细线、实心黑是唯一强调 */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 34px; padding: 0 14px;
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--line2); border-radius: var(--r);
  font: 400 13px/1 var(--sans); cursor: pointer; white-space: nowrap;
}
.btn:hover { border-color: var(--ink); }
.btn-primary, .btn-solid { background: var(--accent); color: var(--on-accent); border-color: var(--accent); font-weight: 600; }
.btn-primary:hover, .btn-solid:hover { opacity: .88; border-color: var(--accent); }
.btn-ghost { border-color: transparent; }
.btn-ghost:hover { border-color: var(--line2); }
.btn-danger { border-color: transparent; color: var(--warn); }
.btn-danger:hover { border-color: var(--warn); }
.btn-sm { height: 28px; padding: 0 10px; font-size: 11.5px; }
.btn-icon { width: 34px; padding: 0; }
.btn.only-narrow { display: none; }
.btn[disabled] { opacity: .4; cursor: default; }

/* ==========================================================================
   计量条：数字画成看得见的量
   ========================================================================== */

.meter { flex: none; display: grid; border-bottom: 1px solid var(--line); }
.meter .cell { padding: 14px 24px; border-right: 1px solid var(--line); min-width: 0; }
.meter .cell:last-child { border-right: 0; }
.meter .k { font: 600 11.5px/1 var(--sans); letter-spacing: .02em; color: var(--mid); }
.meter .v {
  font: 400 26px/1 var(--mono); letter-spacing: -.03em;
  margin-top: 11px; display: flex; align-items: baseline; gap: 6px;
}
.meter .v small { font: 400 11.5px/1 var(--mono); color: var(--faint); }
.meter .sub { font: 400 10.5px/1.7 var(--mono); color: var(--faint); margin-top: 8px; }

.ruler { margin-top: 12px; position: relative; height: 26px; cursor: pointer; }
.ruler .track { position: absolute; left: 0; right: 0; top: 0; height: 6px; background: var(--bg2); border: 1px solid var(--line2); }
.ruler.bare .track { height: 1px; background: var(--line2); border: 0; }
.ruler.bare { cursor: default; }
.ruler .fill { position: absolute; left: 0; top: 0; height: 6px; background: var(--accent); border-radius: 6px; transition: width .3s ease; }
.ruler.hot .fill { background: var(--warn); }
.ruler .tick { position: absolute; top: 6px; width: 1px; height: 5px; background: var(--line2); }
.ruler .tick.long { height: 8px; background: var(--mid); }
.ruler .mark80 { position: absolute; top: -3px; width: 1px; height: 12px; background: var(--warn); left: 80%; }
.ruler .mark80::after {
  content: "80%"; position: absolute; left: 4px; top: -1px;
  font: 400 8.5px/1 var(--mono); color: var(--warn);
  /* 越过阈值后填充是红的，标签得有底色才读得出来 */
  background: var(--bg); padding: 1px 2px;
}
.ruler .lab { position: absolute; top: 15px; font: 400 8.5px/1 var(--mono); color: var(--faint); transform: translateX(-50%); }
@keyframes shake { 0%, 100% { transform: translateX(0) } 25% { transform: translateX(-2px) } 75% { transform: translateX(2px) } }
.ruler.hot { animation: shake .32s ease; }

/* 提示词顺序 */
.stacklist { margin-top: 9px; display: flex; flex-direction: column; gap: 3px; }
.stacklist .s { display: flex; align-items: center; gap: 8px; font: 400 10.5px/1.7 var(--mono); color: var(--mid); }
.stacklist .s i { font-style: normal; color: var(--faint); }
.stacklist .s b { margin-left: auto; font-weight: 400; color: var(--faint); }
.stacklist .s.on { color: var(--ink); }
.stacklist .s.on b { color: var(--ink); }

/* ==========================================================================
   表格：内容当数据读
   ========================================================================== */

.tbl { padding: 0 24px 30px; }
.tbl .th, .tbl .tr { display: grid; gap: 18px; align-items: center; }
.tbl .th > *, .tbl .tr > * { min-width: 0; }
.tbl .th.story, .tbl .tr.story { grid-template-columns: 1fr 190px 76px 104px 34px; }
.tbl .th.char, .tbl .tr.char { grid-template-columns: 1fr 150px 76px 104px 34px; }
.tbl .th.cast, .tbl .tr.cast { grid-template-columns: 1fr 76px 104px 34px; }
.tbl .th {
  height: 42px; border-bottom: 1px solid var(--line2);
  font: 600 11.5px/1 var(--sans); letter-spacing: .02em; color: var(--mid);
}
.tbl .th > div, .tbl .tr .num, .tbl .tr .ago { text-align: right; }
.tbl .th > div:first-child { text-align: left; }
.tbl .tr { min-height: 66px; padding: 12px 0; border-bottom: 1px solid var(--line); cursor: pointer; }
.tbl .tr:hover { background: var(--bg2); }
.tbl .tr.flat { cursor: default; }
.tbl .tr.flat:hover { background: none; }
.tbl .title { font: 600 15.5px/1.25 var(--sans); letter-spacing: -.005em; }
.tbl .tr.new .title { font-weight: 400; color: var(--faint); }
.tbl .pre {
  font: 400 12px/1.6 var(--sans); color: var(--mid); margin-top: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tbl .num { font: 400 13px/1 var(--mono); }
.tbl .ch { font: 400 11.5px/1.6 var(--sans); color: var(--mid); }
.tbl .ago { font: 400 11px/1 var(--mono); color: var(--faint); }
.tbl .thumbb { width: 40px; height: 40px; overflow: hidden; background: var(--bg2); border-radius: 9px; }
.tbl .thumbb img { width: 100%; height: 100%; object-fit: cover; }
.tbl .foot {
  display: flex; align-items: center; gap: 20px; padding: 16px 0 0;
  font: 400 10px/1 var(--mono); color: var(--faint);
}

/* 故事详情：正文 + 摘录 */
.reader { padding: 24px 24px 30px; }
.reader .lead { font: 400 16px/1.95 var(--sans); color: var(--ink); max-width: 74ch; white-space: pre-wrap; }
.reader .kicker {
  font: 600 12px/1 var(--sans); letter-spacing: .02em; color: var(--mid);
  margin: 30px 0 12px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
/* kicker 里的「多人开聊」和标题文字同行，垂直居中对齐 */
.reader .kicker .btn { vertical-align: middle; margin-left: 10px; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  height: 30px; padding: 0 13px; border: 1px solid var(--line2); background: var(--bg);
  color: var(--ink); border-radius: 999px; cursor: pointer; font: 400 12.5px/1 var(--sans);
}
.chip:hover { border-color: var(--ink); }
.chip.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); font-weight: 600; }
.who-me { border-bottom: 1px dashed currentColor; cursor: pointer; }

/* ==========================================================================
   对话
   ========================================================================== */

.msgs {
  flex: 1; min-height: 0; overflow-y: auto; padding: 4px 24px 0;
  /* 往上滚时顶部淡出，别让半行字硬切在仪表下面 */
  mask-image: linear-gradient(180deg, transparent, #000 16px);
}
.msgs-in { max-width: 980px; }
.m { display: grid; grid-template-columns: 64px 1fr; gap: 0; padding: 18px 0; border-bottom: 1px solid var(--line); }
/* 工具行是「不换行 + 横向滚动」，它的 min-content 会顶宽整张卡，必须能缩 */
.m > * { min-width: 0; }
.m .side { font: 400 10px/1.5 var(--mono); color: var(--faint); }
.m .side b { display: block; font-weight: 400; color: var(--line2); }
/* 16px / 1.95 是能一句一句读下去的最小值；14-15px 的长中文段落看久了很累 */
.m .txt { font: 400 16px/1.95 var(--sans); min-width: 0; max-width: 84ch; }
/* *星号* 里的叙述（动作 / 场景 / 心理）跟对白分开：次要色 + 中等字重。
   故意不用斜体 —— 整段中文斜过来在屏幕上太费眼睛，颜色和字重就够了。 */
.m .txt em { font-style: normal; font-weight: 500; color: var(--mid); }
.m.me .txt em { color: inherit; opacity: .85; }
.m .txt .dir { color: var(--mid); }
.m.me { background: var(--bg2); margin: 0 -24px; padding-left: 24px; padding-right: 24px; }
.m.me .txt { border-left: 2px solid var(--accent); padding-left: 14px; }
.m.me .side { color: var(--accent); }
/* 新消息落位：从下方 8px 淡入。只在真的多了一条时播放，不重播整列表。 */
.m.new { animation: msgIn .2s cubic-bezier(.2, .8, .3, 1); }
@keyframes msgIn { from { opacity: 0; transform: translateY(8px) } }

/* 进入一个视图：线先画（2px 规则线从左展开），内容后落（只淡入，不做位移），总长 < 400ms。
   6px 位移在这个尺寸上读不出来，也跟「安静克制」的调性打架；位移只留给真的落了一条消息。 */
@keyframes drawX { from { transform: scaleX(0) } }
@keyframes fadeIn { from { opacity: 0 } }
.pagehead, .tbl .th { position: relative; border-bottom: 0; }
.pagehead::after, .tbl .th::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--line2); transform-origin: left;
}
.app.enter .pagehead::after, .app.enter .tbl .th::after {
  animation: drawX .3s cubic-bezier(.2, .8, .3, 1) 50ms both;
}
.app.enter > .topbar { animation: fadeIn .16s ease both; }
.app.enter .rail { animation: fadeIn .2s ease 30ms both; }
.app.enter .statline { animation: fadeIn .2s ease 50ms both; }
.app.enter .meter .cell:nth-child(1) { animation: fadeIn .2s ease 70ms both; }
.app.enter .meter .cell:nth-child(2) { animation: fadeIn .2s ease 110ms both; }
.app.enter .meter .cell:nth-child(3) { animation: fadeIn .2s ease 150ms both; }
.app.enter .meter .cell:nth-child(4) { animation: fadeIn .2s ease 190ms both; }
.app.enter .pagehead .t { animation: fadeIn .22s ease 90ms both; }
.app.enter .tbl .tr:nth-child(1) { animation: fadeIn .22s ease 170ms both; }
.app.enter .tbl .tr:nth-child(2) { animation: fadeIn .22s ease 200ms both; }
.app.enter .tbl .tr:nth-child(3) { animation: fadeIn .22s ease 230ms both; }
.app.enter .tbl .tr:nth-child(4) { animation: fadeIn .22s ease 260ms both; }
.app.enter .msgs-in .m:nth-last-child(1) { animation: fadeIn .22s ease 120ms both; }

/* 换视图时一条 2px 揭幕线从上往下扫过工作区：这就是「我点的那一下去哪了」的来路 */
.app.enter .work::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--accent); z-index: 6; pointer-events: none;
  animation: sweep .34s cubic-bezier(.2, .8, .3, 1) both;
}
@keyframes sweep { from { top: 0; opacity: 1 } to { top: 100%; opacity: 0 } }

/* 按下立刻有回应 */
.btn:active, .chip:active, .send .go:active { transform: translateY(1px); }
.tr:active, .r:active { background: var(--bg3); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

.m.streaming .txt::after {
  content: ""; display: inline-block; width: 7px; height: 15px; background: var(--ink);
  margin-left: 3px; vertical-align: -2px; animation: blink 1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0 } }

.tools { display: flex; align-items: center; gap: 0; margin-top: 12px; border-top: 1px solid var(--line); }
.tools button {
  background: none; border: 0; color: var(--mid); cursor: pointer;
  font: 400 12px/1 var(--sans); padding: 11px 14px;
  border-right: 1px solid var(--line);
}
.tools button:first-child { padding-left: 0; }
.tools button:last-child { border-right: 0; }
.tools button:hover { color: var(--ink); }
.tools .swipes { display: inline-flex; align-items: center; border-right: 1px solid var(--line); }
.tools .swipes button { border-right: 0; padding: 10px 8px; font-family: var(--mono); }
.tools .swipes b { font: 400 12px/1 var(--mono); color: var(--ink); }

.send { flex: none; border-top: 1px solid var(--line); padding: 16px 24px 18px; background: var(--bg); }
.send-in { max-width: 980px; }
.send .row1 { display: flex; align-items: center; gap: 14px; }
.send textarea {
  flex: 1; resize: none; border: 0; border-bottom: 1px solid var(--line2); background: none;
  outline: none; font: 400 15px/1.6 var(--sans); padding: 10px 2px; min-height: 42px; max-height: 180px;
}
.send textarea:focus { border-color: var(--ink); }
.send textarea::placeholder { color: var(--faint); }
.send .go {
  background: var(--accent); color: var(--on-accent); border: 0; height: 44px; padding: 0 28px;
  font: 600 14px/1 var(--sans); letter-spacing: .04em; cursor: pointer; border-radius: var(--r);
}
.send .go:hover { opacity: .88; }
.send .row2 { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.send .row2 .lab { font: 600 11.5px/1 var(--sans); letter-spacing: .02em; color: var(--faint); margin-right: 4px; }
.send .row2 button {
  background: none; border: 1px solid var(--line2); color: var(--mid);
  font: 400 12.5px/1 var(--sans); padding: 7px 13px; cursor: pointer; border-radius: 999px;
}
.send .row2 button:hover { border-color: var(--ink); color: var(--ink); }
.send .row2 button.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.usage { border: 0; background: none; color: var(--mid); cursor: pointer; padding: 0; font: 400 11.5px/1 var(--mono); }
.usage:hover { color: var(--ink); text-decoration: underline; }
.usage.warn { color: var(--warn); }

/* 建议 = 选项轮盘：一行可点的候选胶囊 + ↻ ✎ × 三个控制 */
.suggest { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.suggest .sg-row { display: flex; flex-wrap: wrap; gap: 8px; }
.suggest .sg-chip {
  flex: 1 1 240px; text-align: left; background: var(--bg); border: 1px solid var(--line);
  color: var(--ink); border-radius: var(--r);
  padding: 9px 14px; cursor: pointer; font: 400 13px/1.55 var(--sans);
}
.suggest .sg-chip:hover { border-color: var(--line2); background: var(--bg2); }
.suggest .sg-chip em { font-style: normal; color: var(--mid); }
.suggest .sg-tools { display: flex; gap: 6px; justify-content: flex-end; }
.suggest .sg-tools button {
  background: none; border: 1px solid var(--line2); color: var(--mid);
  font: 400 12px/1 var(--sans); padding: 6px 11px; cursor: pointer; border-radius: 999px;
}
.suggest .sg-tools button:hover { border-color: var(--ink); color: var(--ink); }
.suggest .sg-tools button.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

/* ==========================================================================
   表单
   ========================================================================== */

.form { padding: 24px 24px 40px; max-width: 1100px; }
.fgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 26px; }
.fgrid .full { grid-column: 1 / -1; }
.field { min-width: 0; }
.field > label {
  display: block; font: 600 12px/1 var(--sans); letter-spacing: .02em; color: var(--mid);
  margin-bottom: 8px;
}
/* 只认 .field 的直接子元素：世界书里的勾选行、选角色的清单都嵌在 .field 里，
   写 .field input 会把它们的复选框也拉成 100% 宽 */
.field > input, .field > textarea, .field > select {
  width: 100%; padding: 11px 13px; border: 1px solid var(--line2); border-radius: var(--r);
  background: var(--bg); outline: none; font: 400 14px/1.7 var(--sans);
}
.field > textarea { resize: vertical; }
.field > input:focus, .field > textarea:focus, .field > select:focus { border-color: var(--ink); }
.field .hint { font: 400 11px/1.7 var(--sans); color: var(--faint); margin-top: 7px; }
.row { display: flex; gap: 14px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 170px; }
.check { display: flex; align-items: center; gap: 9px; font-size: 13px; cursor: pointer; }
.check input { width: auto; accent-color: var(--ink); }
.portrait-pick { display: flex; gap: 18px; align-items: flex-start; }
.portrait-pick .thumb {
  width: 96px; height: 128px; flex: none; overflow: hidden; background: var(--bg2);
  border: 1px solid var(--line2); border-radius: 12px; display: grid; place-items: center; color: var(--faint); font-size: 24px;
}
.portrait-pick .thumb img { width: 100%; height: 100%; object-fit: cover; }

.section-title {
  font: 600 12.5px/1 var(--sans); letter-spacing: .02em; color: var(--mid);
  margin: 34px 0 14px; padding-bottom: 9px; border-bottom: 1px solid var(--line2);
}
.section-title:first-child { margin-top: 0; }

/* 列表项（世界书、自定义设定、角色勾选） */
.list-item {
  display: flex; align-items: center; gap: 12px; padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.list-item:last-child { border-bottom: 0; }
.list-item .avatar {
  width: 42px; height: 42px; flex: none; overflow: hidden; background: var(--bg2);
  border-radius: 10px; display: grid; place-items: center; color: var(--faint);
}
.list-item .avatar img { width: 100%; height: 100%; object-fit: cover; }
.list-item .grow { flex: 1; min-width: 0; }
.list-item .name { font: 700 13.5px/1.4 var(--sans); }
.list-item .sub { font: 400 12px/1.6 var(--sans); color: var(--mid); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.panel { border: 1px solid var(--line); border-radius: 14px; overflow: hidden; }
.panel + .panel { margin-top: 18px; }
.panel-head { padding: 14px 18px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; }
.panel-head h2 { font-size: 14px; }
.panel-head .hint { font-size: 12px; color: var(--mid); flex: 1; }
.panel-body { padding: 18px; }

/* ==========================================================================
   空状态 / 弹窗 / 提示
   ========================================================================== */

.empty { padding: 70px 24px; color: var(--mid); border: 1px solid var(--line); border-radius: 16px; margin: 24px; }
.empty .dot {
  width: 40px; height: 40px; border: 1px solid var(--line2); display: grid; place-items: center;
  font: 400 14px/1 var(--mono); color: var(--mid); margin-bottom: 16px;
}
.empty h2 { font-size: 16px; margin-bottom: 8px; color: var(--ink); }
.empty .hint { font: 400 13px/1.8 var(--sans); }

.modal-back {
  position: fixed; inset: 0; z-index: 60; padding: 24px;
  background: rgba(10, 10, 10, .38);
  display: grid; place-items: center;
  animation: fade .12s ease;
}
@keyframes fade { from { opacity: 0 } }
.modal {
  background: var(--bg); border-radius: 18px; padding: 24px 26px;
  width: min(620px, 100%); max-height: 86vh; overflow: auto;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .28);
  animation: pop .16s cubic-bezier(.2, .8, .3, 1);
}
@keyframes pop { from { opacity: 0; transform: translateY(8px) } }
.modal h2 { font-size: 16px; margin-bottom: 16px; letter-spacing: -.01em; }
.modal .foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }

.pick-list { max-height: 46vh; overflow-y: auto; margin-top: 12px; display: flex; flex-direction: column; }
.pick-row {
  text-align: left; padding: 10px 12px; border: 0; border-bottom: 1px solid var(--line);
  background: none; cursor: pointer; font: 400 12.5px/1.5 var(--mono); color: var(--ink);
  word-break: break-all;
}
.pick-row:hover { background: var(--bg2); }
.pick-row.on { background: var(--bg3); font-weight: 700; }

.toast {
  position: fixed; left: 50%; top: calc(var(--top) + 12px); transform: translateX(-50%);
  background: var(--ink); color: var(--on-ink); padding: 11px 20px; border-radius: 999px;
  z-index: 90; max-width: 80vw; font: 400 13px/1.5 var(--sans);
  animation: pop .16s cubic-bezier(.2, .8, .3, 1);
}
.toast.err { background: var(--warn); color: #fff; }
.spinner {
  width: 13px; height: 13px; border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%; display: inline-block; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg) } }

.scrim { position: fixed; inset: 0; z-index: 35; background: rgba(10, 10, 10, .38); }

/* 登录 */
/* #app 只是登录页时没有高度，100% 不生效，用视口高才真的居中 */
.login { min-height: 100vh; display: grid; place-items: center; padding: 40px 24px; }
.login .box { width: min(360px, 100%); padding-top: 10px; }
.login h1 { font-size: 22px; letter-spacing: -.01em; color: var(--accent); }
.login .tag { font: 400 10.5px/1 var(--mono); color: var(--mid); margin: 10px 0 24px; }
.login .btn { width: 100%; justify-content: center; }
.login .err { color: var(--warn); font-size: 12.5px; margin-top: 12px; }

/* ==========================================================================
   窄屏：清单变抽屉
   ========================================================================== */

@media (max-width: 900px) {
  .btn.only-narrow { display: inline-flex; }
  .app > .body > .rail {
    position: fixed; top: var(--top); bottom: 0; left: 0; z-index: 40;
    width: min(330px, 86vw);
    transform: translateX(-100%); transition: transform .2s cubic-bezier(.2, .8, .3, 1);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .3);
  }
  .app.nav-open > .body > .rail { transform: none; }
  .topbar { padding: 0 12px; }
  .topbar .host { display: none; }
  .pagehead { padding: 16px 14px 12px; flex-wrap: wrap; }
  .pagehead h1 { font-size: 21px; }
  .meter { grid-template-columns: 1fr 1fr !important; }
  /* 4 格在窄屏是 2×2：第 2 格是第一行末尾，去掉右边框；第 3 格的保留 */
  .meter .cell:nth-child(2) { border-right: 0; }
  .tbl { padding: 0 14px 24px; }
  .tbl .th, .tbl .tr { gap: 12px; }
  .tbl .hide-narrow { display: none; }
  .tbl .th.story, .tbl .tr.story,
  .tbl .th.char, .tbl .tr.char { grid-template-columns: 1fr 44px 28px; }
  .tbl .th.cast, .tbl .tr.cast { grid-template-columns: 1fr 44px; }
  .tools { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .tools::-webkit-scrollbar { display: none; }
  .tools button { white-space: nowrap; flex: none; }
  :root { --top: 52px; }
  .topbar .acts .btn { height: 40px; padding: 0 12px; }
  .reader { padding: 16px 14px 24px; }
  .form { padding: 16px 14px 32px; }
  .fgrid { grid-template-columns: 1fr; }
  .msgs { padding: 4px 14px 0; }
  .m { grid-template-columns: 44px 1fr; padding: 14px 0; }
  .m.me { margin: 0 -14px; padding-left: 14px; padding-right: 14px; }
  .send { padding: 12px 14px 14px; }
  .send .go { padding: 0 16px; }
  .empty { margin: 14px; padding: 46px 18px; }
}

/* ==========================================================================
   对话页 / 故事列表：就是普通的聊天界面
   一条对话头（头像 + 名字 + 处境）+ 气泡 + 一条输入框；
   故事列表是一张会话列表。这一轮注入了什么收进「上下文」那个按钮。
   ========================================================================== */

/* 对话页：普通的聊天界面 —— 头像 + 气泡 + 一条输入框 */

.ch-head {
  flex: none; display: flex; align-items: center; gap: 12px;
  height: 62px; padding: 0 18px; border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(14px) saturate(1.6);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  position: relative; z-index: 4;
}
@media (prefers-color-scheme: dark) {
  .ch-head { background: rgba(14, 15, 18, .82); }
}
.ch-ic {
  width: 34px; height: 34px; flex: none; border: 0; background: none; cursor: pointer;
  color: var(--mid); font-size: 22px; line-height: 1; border-radius: 50%;
}
.ch-ic:hover { background: var(--hover); color: var(--ink); }
.ch-av {
  width: 40px; height: 40px; flex: none; border-radius: 50%; overflow: hidden;
  background: var(--bg3); display: grid; place-items: center;
  font: 600 15px/1 var(--sans); color: var(--mid);
}
.ch-av img { width: 100%; height: 100%; object-fit: cover; }
.ch-id { min-width: 0; }
.ch-id b { display: block; font: 600 15.5px/1.25 var(--sans); }
.ch-id span {
  display: block; margin-top: 3px; font: 400 12px/1.3 var(--sans); color: var(--faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 34vw;
}
.ch-scene {
  margin-left: auto; flex: none; max-width: 30ch;
  font: 400 12px/1.5 var(--sans); color: var(--mid);
  border-left: 2px solid var(--line2); padding-left: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ch-num {
  flex: none; border: 1px solid var(--line2); background: none; border-radius: 999px;
  font: 400 11.5px/1 var(--mono); color: var(--mid); padding: 7px 12px; cursor: pointer;
}
.ch-num:hover { border-color: var(--accent); color: var(--accent); }
.ch-btn {
  flex: none; border: 0; background: none; color: var(--mid); cursor: pointer;
  font: 400 12.5px/1 var(--sans); padding: 8px 10px; border-radius: 8px;
}
.ch-btn:hover { background: var(--hover); color: var(--ink); }

/* 群戏：头部在场角色一排小头像+名字。复用 .ch-av 的头像渲染，尺寸在这里缩小 */
.ch-cast { display: flex; align-items: center; gap: 10px; min-width: 0; overflow: hidden; }
.ch-cast .cc { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.ch-cast .ch-av { width: 26px; height: 26px; font-size: 11px; }
.ch-cast .cc i {
  font: 400 12px/1 var(--sans); color: var(--mid); font-style: normal;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 气泡 */
.msgs { padding: 18px 0 0; }
.msgs-in { max-width: 840px; margin: 0 auto; padding: 0 20px; }
.m {
  display: flex; align-items: flex-start; padding: 0 0 14px;
  border-bottom: 0; background: none;
}
.m .side { display: none; }
.m > div:last-child { max-width: 78%; min-width: 0; }
.m .txt {
  background: var(--bg2); color: var(--ink);
  border-radius: 4px 18px 18px 18px;
  /* 16px / 1.95：这是要一句一句读下去的东西，15px/1.8 看久了累。上面那条 .m .txt 是同名旧值，
     保留只为不破坏别处引用，生效的是这一条 */
  padding: 11px 15px; font: 400 16px/1.95 var(--sans); max-width: 100%;
  border-left: 0;
}
.m.me { justify-content: flex-end; margin: 0; padding-left: 0; padding-right: 0; background: none; }
.m.me .txt {
  background: var(--accent); color: var(--on-accent);
  border-radius: 18px 4px 18px 18px; border-left: 0; padding-left: 15px;
}
.m .tools {
  display: flex; gap: 2px; flex-wrap: wrap;
  margin-top: 4px; border-top: 0; opacity: 0; transition: opacity .15s;
}
.m:hover .tools, .m:focus-within .tools { opacity: 1; }
.m .tools button { font-size: 11.5px; padding: 5px 8px; border-right: 0; color: var(--faint); }
.m .tools button:hover { color: var(--ink); }
.m.me .tools { justify-content: flex-end; }
.m.streaming .txt::after { background: currentColor; }

/* 幕分隔条：1px 线 + 等宽编号，直角、无彩，融进消息流 */
.actdiv {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px;
  margin: 24px 0 14px; padding-top: 10px;
  border-top: 1px solid var(--line2);
}
.actdiv i { font: 400 11px/1.4 var(--mono); color: var(--faint); font-style: normal; }
.actdiv b { font: 600 12.5px/1.4 var(--sans); color: var(--ink); letter-spacing: .04em; }
.actdiv span { font: 400 11.5px/1.4 var(--mono); color: var(--faint); }

/* 输入条 */
.send { border-top: 1px solid var(--line); padding: 12px 0 14px; background: var(--bg); }
.send-in { max-width: 840px; margin: 0 auto; padding: 0 20px; }
.send .row1 {
  align-items: center; gap: 10px;
  border: 1px solid var(--line2); border-radius: 24px; padding: 4px 4px 4px 16px;
  background: var(--bg);
  transition: border-color .15s, box-shadow .15s;
}
.send .row1:focus-within { box-shadow: 0 0 0 4px rgba(214, 53, 110, .10); }
.send .row1:focus-within { border-color: var(--accent); }
.send textarea { border: 0; padding: 9px 0; min-height: 40px; font-size: 15px; }
.send textarea:focus { border-color: transparent; }
.send .go { height: 40px; padding: 0 20px; border-radius: 18px; font-size: 14px; letter-spacing: 0; }
/* 群戏的「推进一拍」：发送旁的描边胶囊，和主发送按钮拉开主次 */
.send .beat {
  flex: none; height: 40px; padding: 0 16px; border: 1px solid var(--line2);
  background: none; color: var(--mid); border-radius: 18px; cursor: pointer;
  font: 600 13px/1 var(--sans); letter-spacing: .02em;
}
.send .beat:hover { border-color: var(--accent); color: var(--accent); }
.send .row2 { justify-content: center; margin-top: 10px; }
.send .row2 .lab { display: none; }
.suggest { max-width: 840px; margin: 0 auto 10px; padding: 0 20px; }
.suggest .sg-chip { border-radius: 14px; }

/* 故事列表 = 一张会话列表 */
.chatlist { padding: 10px 12px 28px; max-width: 880px; margin: 0 auto; }
.cl-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: 14px; cursor: pointer;
}
.cl-row:hover { background: var(--hover); }
.cl-row:active { background: var(--bg3); }
.cl-av {
  width: 52px; height: 52px; flex: none; border-radius: 14px; overflow: hidden;
  background: var(--bg3); display: grid; place-items: center;
  font: 600 20px/1 var(--sans); color: var(--faint);
}
.cl-av img { width: 100%; height: 100%; object-fit: cover; }
.cl-av.add { background: none; border: 1px dashed var(--line2); }
.cl-tx { flex: 1; min-width: 0; }
.cl-l1 { display: flex; align-items: baseline; gap: 10px; }
.cl-l1 b { font: 600 15px/1.3 var(--sans); }
.cl-l1 span { margin-left: auto; flex: none; font: 400 11.5px/1 var(--sans); color: var(--faint); }
.cl-l2 {
  margin-top: 4px; font: 400 13px/1.5 var(--sans); color: var(--mid);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cl-l3 {
  margin-top: 3px; font: 400 11.5px/1.4 var(--sans); color: var(--faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cl-row .btn { flex: none; opacity: 0; }
.cl-row:hover .btn { opacity: 1; }
.cl-foot { padding: 14px 4px 0; font: 400 11.5px/1.6 var(--sans); color: var(--faint); }

/* 弹窗里的剧情线 */
.modal-plot { margin-bottom: 20px; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.modal-plot .k { font: 600 11.5px/1 var(--sans); letter-spacing: .02em; color: var(--accent); }
.plot-body {
  margin-top: 10px; font: 400 13.5px/1.85 var(--sans); color: var(--ink);
  max-height: 30vh; overflow: auto;
}

/* ==========================================================================
   支线树 + 结局图鉴（挂在「对话」弹窗里）
   连线只用 1px 直角竖线+短横线，不加颜色：跟 E·网格的分隔线一个语言
   ========================================================================== */

/* 图鉴：面板顶部，达成 1 个以上才渲染这块 */
.codex { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; margin-bottom: 4px; }
.codex-h { font: 600 12px/1 var(--sans); letter-spacing: .02em; color: var(--ink); margin-bottom: 9px; }
.codex-row {
  display: flex; align-items: baseline; gap: 7px;
  font: 400 12.5px/1.9 var(--sans); color: var(--mid);
}
.codex-row b { font-weight: 600; color: var(--ink); }

.sec-title {
  font: 600 11.5px/1 var(--sans); letter-spacing: .04em; color: var(--mid);
  margin: 18px 0 6px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}

.btree { margin-top: 4px; }
/* 竖线 = 子层容器的左边框；短横线 = 每行前面的 8px 小拐弯 */
.tbranch {
  margin-left: 10px; padding-left: 16px;
  border-left: 1px solid var(--line2);
}
.trow {
  position: relative;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px;
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.tbranch > .trow::before {
  content: ''; position: absolute; left: -16px; top: 50%;
  width: 16px; height: 1px; background: var(--line2);
}
.trow:last-child { border-bottom: 0; }
.trow.cur { background: var(--bg2); box-shadow: inset 3px 0 0 var(--ink); }
.tname { font: 600 13px/1.5 var(--sans); min-width: 0; overflow-wrap: anywhere; }
.tstar { font-style: normal; color: var(--accent); }
.tnum { font: 400 11px/1 var(--mono); color: var(--faint); font-variant-numeric: tabular-nums; }
.tend {
  font: 400 10.5px/1 var(--mono); color: var(--mid);
  border: 1px solid var(--line2); border-radius: 3px; padding: 3px 6px;
}
.tacts { display: flex; gap: 4px; margin-left: auto; }

/* 弹窗里的仪表：竖着排，别挤成三列 */
.modal-meter { grid-template-columns: 1fr; border-bottom: 0; }
.modal-meter .cell { border-right: 0; padding: 16px 0; }
.modal-meter .cell:first-child { padding-top: 0; }
.modal-meter .cell + .cell { border-top: 1px solid var(--line); }

/* 状态卡（功能 5）：仪表第四格整格可点；地点太长就省略号，别撑破格子 */
.meter .state-cell { cursor: pointer; }
.meter .state-cell:hover .v { color: var(--accent); }
.meter .state-cell .v {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 状态卡弹窗：一行一项，标签固定宽度对齐 */
.state-view .sc-row {
  display: flex; gap: 12px; align-items: baseline;
  padding: 9px 0; border-bottom: 1px solid var(--line);
}
.state-view .sc-row:last-child { border-bottom: 0; }
.state-view .sc-row span { flex: none; width: 44px; font: 600 12px/1.6 var(--sans); color: var(--mid); }
.state-view .sc-row b {
  font: 400 13.5px/1.7 var(--sans); color: var(--ink); overflow-wrap: anywhere;
}

/* 掷事件（功能 6）：大字 d20 + 标题 + 正文 */
.d20 { font: 400 34px/1 var(--mono); letter-spacing: -.03em; color: var(--accent); }
.ev-title { margin-top: 12px; font: 600 16px/1.4 var(--sans); color: var(--ink); }
.ev-body {
  margin-top: 8px; font: 400 14px/1.8 var(--sans); color: var(--ink);
  white-space: pre-wrap; max-height: 40vh; overflow: auto;
}
/* 没有事件表时的「掷事件」：变灰但还能点，点了给出路（去故事编辑加） */
.send .row2 button.off { opacity: .5; }

@media (prefers-color-scheme: dark) {
  .m .txt { background: var(--bg2); color: var(--ink); }
  .m.me .txt { background: var(--accent); color: var(--on-accent); }
}

@media (max-width: 900px) {
  .ch-head { gap: 8px; padding: 0 10px; height: 56px; }
  .ch-scene, .ch-btn { display: none; }
  .ch-id span { max-width: 40vw; }
  /* 窄屏只留群戏头像，名字挤不下就藏掉（title 里还有全名） */
  .ch-cast .cc i { display: none; }
  .msgs-in, .send-in { padding: 0 12px; }
  .m > div:last-child { max-width: 88%; }
  .send .row2 { justify-content: flex-start; }
}

/* 建议胶囊上的意图标签（主动 / 试探 / 退让 / 岔开） */
.suggest .sg-chip .sg-tag {
  display: inline-block; margin-right: 7px; padding: 2px 7px; border-radius: 999px;
  background: var(--bg3); color: var(--mid); font: 600 10.5px/1.6 var(--sans);
}

/* 上下文弹窗里的「玩家倾向」一行 */
.tend-line {
  display: flex; gap: 12px; align-items: baseline; padding: 10px 0 12px;
  border-bottom: 1px solid var(--line);
}
.tend-line span { flex: none; font: 600 12px/1.6 var(--sans); color: var(--mid); }
.tend-line b { font: 400 13.5px/1.7 var(--sans); color: var(--ink); }

/* 结局规则：软失败用 warn 色区分 */
.list-item .bad-mark {
  font-style: normal; font-weight: 600; font-size: 10.5px; color: var(--warn);
  border: 1px solid var(--warn); border-radius: 3px; padding: 2px 6px; margin-left: 6px;
}
.list-item.bad .name { color: var(--warn); }

/* 弹窗里必填没填时的主按钮 */
.modal .foot .btn:disabled { opacity: .45; cursor: not-allowed; }

/* 任务（功能 7）：任务表弹窗里已完成的标记；当前任务用 .pick-row.on 高亮 */
.pick-row .q-done {
  font-style: normal; font-weight: 600; font-size: 10.5px; color: var(--faint);
  border: 1px solid var(--line2); border-radius: 3px; padding: 1px 5px; margin-left: 6px;
}
