/* app 内页面的样式 */

.pad    { padding: var(--sp-4); }
.pad-x  { padding-left: var(--sp-4); padding-right: var(--sp-4); }
.pad-t  { padding-top: var(--sp-4); }
.pad-b  { padding-bottom: var(--sp-6); }
.quiet-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }

/* 外观预设 */
.look-list { display: flex; flex-direction: column; gap: var(--sp-2); padding: 0 var(--sp-4); }
.look-row { display: flex; align-items: center; gap: var(--sp-2); }
.look-card {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--group-fill); text-align: left;
}
.look-card:active { opacity: .7; }
.look-thumb {
  flex: none; width: 46px; height: 46px; border-radius: var(--r-sm);
  background: var(--surface-3); color: var(--text-3);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.look-thumb.has-image { background-size: cover; background-position: center; }
.look-meta { flex: 1; min-width: 0; }
.look-name { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.look-sub { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
.look-more { flex: none; padding: var(--sp-2); color: var(--text-3); }
/* 导入主题包时自定义 CSS 的原文（4.295）：先看再决定导不导 */
.theme-css {
  margin: 0; max-height: 320px; overflow: auto; padding: var(--sp-3);
  background: var(--surface-2); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--fs-12); line-height: 1.5;
  white-space: pre-wrap; word-break: break-all; color: var(--text-2);
}

/* 字体 */
.font-slot-val { max-width: 130px; font-size: var(--fs-14); color: var(--text-2); }
.li-hint { font-size: var(--fs-13); color: var(--text-3); }
/* 导入预览里被勾掉的那几条 */
.is-off { opacity: .4; }
.char-name { font-size: var(--fs-17); font-weight: var(--fw-semi); }
/* 账号与小号 */
.acc-tag {
  margin-left: 6px; padding: 1px 6px; border-radius: var(--r-full);
  background: var(--group-fill); color: var(--text-3); font-size: var(--fs-11);
  font-weight: var(--fw-normal);
}
.acc-alt { padding-left: var(--sp-5); }

/* 联系：卡片墙 */
.ct-tree {
  margin: 0 var(--sp-4) var(--sp-4); padding: var(--sp-3);
  border-radius: var(--r-md); background: var(--group-fill);
  font-size: var(--fs-11); line-height: 1.6;
}
/* 一行一个元素，缩进表示嵌套；说明放不下时换到下一行 */
.ct-tree-row { display: flex; flex-wrap: wrap; column-gap: var(--sp-2); padding-left: calc(var(--d) * var(--sp-3)); }
.ct-tree-sel { font-family: var(--font-mono); color: var(--text); }
.ct-tree-label { color: var(--text-3); }
.ct-sec {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-5) var(--sp-4) var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3);
}
/* 一行三张。两张一行时一屏只看得到四个角色，角色一多要翻很久才找得到人 */
.ct-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-2); padding: 0 var(--sp-4);
}
.ct-card { text-align: left; min-width: 0; }
.ct-card:active { opacity: .72; }
.ct-cover {
  position: relative; width: 100%; aspect-ratio: 1;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--group-fill); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}
.ct-cover.has-image { background-size: cover; background-position: center; }
.ct-initial { font-size: var(--fs-28); font-weight: var(--fw-medium); }
.ct-badge {
  position: absolute; left: var(--sp-2); bottom: var(--sp-2);
  padding: 2px 7px; border-radius: var(--r-full);
  background: var(--scrim-strong); color: var(--on-scrim); font-size: var(--fs-11);
}
.ct-name { margin-top: var(--sp-2); font-size: var(--fs-14); font-weight: var(--fw-semi); }
.ct-sign { margin-top: 1px; font-size: var(--fs-12); color: var(--text-3); }

/* 联系：资料页 */
.pf-head { padding: var(--sp-6) var(--sp-4) var(--sp-4); text-align: center; }
.pf-avatar { display: flex; justify-content: center; }
.pf-name { margin-top: var(--sp-3); font-size: var(--fs-20); font-weight: var(--fw-semi); }
.pf-sign { margin-top: 4px; font-size: var(--fs-13); color: var(--text-2); }
.pf-facts {
  display: flex; justify-content: center; gap: var(--sp-5);
  margin-top: var(--sp-4);
}
.pf-fact { text-align: center; }
.pf-fact b { display: block; font-size: var(--fs-15); font-weight: var(--fw-medium); }
.pf-fact span { font-size: var(--fs-11); color: var(--text-3); }
.pf-acts { display: flex; gap: var(--sp-2); padding: var(--sp-4); }
.pf-acts > * { flex: 1; }

/* 关系网 */
.net-wrap { padding: var(--sp-4); }
.net-svg { width: 100%; height: auto; display: block; }
.net-node-label { font-size: 11px; fill: var(--text); }
.net-edge-label { font-size: 9px; fill: var(--text-3); }
/* 社交圈（4.593）：第一圈上每个圈子占一段扇形，圈子名在外侧 */
.net-wedge { fill: var(--surface-2); opacity: .8; stroke: var(--surface); stroke-width: 2; }
.net-wedge.is-alt { opacity: .4; }
.net-circle-label { font-size: 10px; fill: var(--text-3); letter-spacing: .04em; }
.font-sample {
  font-size: var(--fs-17); color: var(--text); margin-top: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 文字按钮同理：看着还是那几个字，命中区撑到 44 高 */
.nav-text {
  position: relative;
  font-size: var(--fs-14); color: var(--accent); padding: var(--sp-2);
  min-height: 34px; display: inline-flex; align-items: center;
}
.nav-text::after { content: ''; position: absolute; inset: -5px; }

.hint-box {
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.65;
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: var(--sp-3); margin-bottom: var(--sp-4);
}
.warn-box {
  font-size: var(--fs-12); color: var(--text); line-height: 1.6;
  background: var(--surface-3); border-left: 3px solid var(--text); border-radius: var(--r-sm);
  padding: var(--sp-3); margin-bottom: var(--sp-4);
}
.settings-foot {
  text-align: center; font-size: var(--fs-11); color: var(--text-3);
  padding: var(--sp-6) var(--sp-4);
}
.settings-foot.is-error { color: var(--danger); word-break: break-word; }

/* 美化库里的静态预览。里面是一个 shadow root，那份美化的 CSS 只在里面生效，
   所以外面这一圈框由本表负责，不会被它改掉。 */
.skin-preview {
  margin: var(--sp-4); border-radius: var(--r-lg); overflow: hidden;
  border: 1px solid var(--border); background: var(--surface);
  height: 220px;
}

.chip-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.chip {
  padding: 5px var(--sp-3); border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-12);
  border: 1px solid transparent;
}
.chip.is-active { background: var(--accent-weak); color: var(--accent); border-color: var(--accent); }
/* 生图提示词预设一排（4.522） */
.ipp { margin: calc(-1 * var(--sp-2)) 0 var(--sp-4); }
.ipp > .chip-row { margin-top: 0; }
.ipp-add { display: inline-flex; align-items: center; gap: 4px; }
.ipp-dirty { display: flex; align-items: baseline; gap: var(--sp-2); margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }
.ipp-dirty > span { flex: 1; min-width: 0; }
.ipp-link { flex: none; color: var(--accent); font-size: var(--fs-12); }

.avatar-picker {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-3); padding: var(--sp-4) 0 var(--sp-6);
}

input[type="range"] {
  width: 100%; padding: 0; background: none; border: none;
  accent-color: var(--accent);
}

/* 千丝万缕（4.477） */
.fate-text { font-size: var(--fs-14); line-height: 1.7; color: var(--text); margin: var(--sp-2) 0; white-space: pre-wrap; }
.fate-why { color: var(--text-2); }
.fate-hints-label { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-4); }
.fate-hints { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-3); }
.fate-prop { font-size: var(--fs-14); line-height: 1.6; margin-bottom: var(--sp-2); }

/* 千丝万缕（4.477）的画法：一根线。颜色只有线（--text）、淡线（--border-2）与底。
   --silk-a 是原线所在的横坐标，--silk-b 是支线页上新线的横坐标，--silk-pad 是正文从哪里开始。 */
.fate-home .fate-intro { padding: var(--sp-5) var(--sp-5) var(--sp-3); }
.fate-strands { display: block; width: 100%; height: 64px; color: var(--text); }
.fate-strands path { fill: none; stroke: currentColor; stroke-width: 1; opacity: .55; vector-effect: non-scaling-stroke; }
.fate-strands circle { fill: currentColor; }
.fate-intro-text { font-size: var(--fs-13); line-height: 1.8; color: var(--text-2); margin-top: var(--sp-4); }

.fate-cards { padding: 0 var(--sp-5); }
.fate-card { display: block; width: 100%; text-align: left; padding: var(--sp-4) 0 var(--sp-5); background: none; border: 0; border-top: 1px solid var(--border); color: inherit; font: inherit; }
.fate-card-top { display: flex; align-items: center; gap: var(--sp-3); }
.fate-card-info { min-width: 0; }
.fate-card-name { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.fate-card-with { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
.fate-mini { position: relative; height: 44px; margin-top: var(--sp-3); }
.fate-mini::before { content: ''; position: absolute; left: 0; right: 0; top: 11px; height: 1px; background: var(--border-2); }
.fate-mini-knot { position: absolute; z-index: 1; left: var(--x); top: 8px; width: 7px; height: 7px; margin-left: -4px; border-radius: 50%; background: var(--bg); border: 1px solid var(--text); box-sizing: border-box; }
.fate-mini-knot:where(.is-both) { background: var(--text); }
.fate-mini-off { position: absolute; left: var(--x); right: 0; top: 11px; height: calc(7px + var(--k) * 4px); border-left: 1px solid var(--text-2); border-bottom: 1px solid var(--text-2); border-bottom-left-radius: 8px; opacity: .8; }
.fate-mini-now { position: absolute; right: 0; top: 28px; font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); letter-spacing: .08em; }

.fate-head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-5) var(--sp-5) var(--sp-2); }
.fate-head-info { min-width: 0; }
.fate-head-name { font-family: var(--font-serif); font-size: var(--fs-24); line-height: 1.3; letter-spacing: .06em; }
.fate-head-with { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }

/* 命运图：横着铺开的一张网，横向滚动。线只有三种颜色：主线淡线、支线次级文字色、覆盖中的用正文色 */
.fate-web-wrap { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; padding: 0 var(--sp-3) var(--sp-2); }
.fate-web { display: block; font-family: var(--font-serif); }
.fw-spine { fill: none; stroke: var(--border-2); stroke-width: 1; }
.fw-spine:where(.is-faded) { stroke-dasharray: 3 4; }
.fw-origin { fill: var(--text-3); }
.fw-knot { fill: var(--bg); stroke: var(--text); stroke-width: 1.5; }
.fw-knot:where(.is-both) { fill: var(--text); }
.fw-knot:where(.is-manual) { stroke-dasharray: 2 2; }
.fw-knot:where(.is-now) { fill: var(--bg); stroke: var(--text); }
.fw-date { font-size: var(--fs-11); fill: var(--text-3); letter-spacing: .06em; }
.fw-title { font-family: var(--font); font-size: var(--fs-13); fill: var(--text); }
.fw-strand { fill: none; stroke: var(--text-2); stroke-width: 1; }
.fw-strand:where(.is-draft) { stroke-dasharray: 3 3; }
.fw-strand:where(.is-overwritten) { stroke: var(--text); stroke-width: 2; }
.fw-strand:where(.is-reverted) { stroke: var(--border-2); }
.fw-textline { fill: none; stroke: none; }
.fw-hit { fill: none; stroke: transparent; stroke-width: 18; pointer-events: stroke; }
.fw-hit-dot { fill: transparent; }
.fw-ev { fill: var(--bg); stroke: var(--text-2); stroke-width: 1; }
.fw-strand-g:where(.is-overwritten) .fw-ev { stroke: var(--text); stroke-width: 1.5; }
.fw-strand-g:where(.is-reverted) .fw-ev { stroke: var(--border-2); }
.fw-strand-g:where(.is-reverted) .fw-strand-text { fill: var(--text-3); }
.fw-strand-text { font-size: var(--fs-11); fill: var(--text-2); letter-spacing: .02em; }
.fw-strand-g:where(.is-overwritten) .fw-strand-text { fill: var(--text); }
.fw-node, .fw-strand-g { cursor: pointer; }
.fate-empty-btns { display: flex; gap: var(--sp-2); padding: var(--sp-2) var(--sp-5) var(--sp-4); }

/* 节点页：一个放大的结，日期与标题用衬线 */
.fate-knot { position: absolute; z-index: 1; width: 9px; height: 9px; border-radius: 50%; background: var(--bg); border: 1.5px solid var(--text); box-sizing: border-box; }
.fate-knot:where(.is-both) { background: var(--text); }
.fate-date { font-family: var(--font-serif); font-size: var(--fs-12); color: var(--text-3); letter-spacing: .06em; line-height: 1.5; }
.fate-ntitle { font-size: var(--fs-15); line-height: 1.5; margin-top: 2px; }
.fate-about { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
.fate-knot-head { position: relative; padding: var(--sp-5) var(--sp-5) var(--sp-3) 64px; }
.fate-knot-head .fate-knot { left: 27px; top: calc(var(--sp-5) + 4px); width: 13px; height: 13px; }
.fate-big { font-family: var(--font-serif); font-size: var(--fs-24); font-weight: var(--fw-normal); line-height: 1.35; letter-spacing: .04em; margin: var(--sp-1) 0 var(--sp-2); }

/* 支线页：两根线并排。原线在左，新线从同一个结分出来在右；覆盖之后原线虚掉、新线变粗 */
.fate-twin { --silk-a: 31px; --silk-b: 53px; --silk-pad: 84px; position: relative; padding: 0 var(--sp-5) var(--sp-5) var(--silk-pad); }
.fate-twin-node { position: relative; padding: var(--sp-5) 0 var(--sp-6); }
.fate-twin-node::before { content: ''; position: absolute; left: calc(var(--silk-a) - var(--silk-pad)); top: 0; bottom: 0; border-left: 1px solid var(--border-2); }
.fate-twin-node .fate-knot { top: calc(var(--sp-5) + 4px); width: 11px; height: 11px; left: calc(var(--silk-a) - var(--silk-pad) - 5px); }
.fate-twin-node .fate-big { margin-bottom: var(--sp-1); }
.fate-curve { position: absolute; left: calc(var(--silk-a) - var(--silk-pad)); top: calc(var(--sp-5) + 10px); bottom: 0; width: calc(var(--silk-b) - var(--silk-a)); border-left: 1px solid var(--text); border-bottom: 1px solid var(--text); border-bottom-left-radius: 22px; }
.fate-twin-rest { position: relative; }
.fate-twin-rest::before { content: ''; position: absolute; left: calc(var(--silk-a) - var(--silk-pad)); top: 0; bottom: 18px; border-left: 1px solid var(--border-2); }
.fate-twin-rest::after { content: ''; position: absolute; left: calc(var(--silk-b) - var(--silk-pad)); top: 0; bottom: 18px; border-left: 1px solid var(--text); }
.fate-twin:where(.is-draft) .fate-twin-rest::after, .fate-twin:where(.is-draft) .fate-curve { border-left-style: dashed; border-bottom-style: dashed; }
.fate-twin:where(.is-overwritten) .fate-twin-rest::before { border-left-style: dashed; opacity: .5; }
.fate-twin:where(.is-overwritten) .fate-twin-rest::after, .fate-twin:where(.is-overwritten) .fate-curve { border-width: 2px; }
.fate-twin:where(.is-reverted) .fate-twin-rest::after, .fate-twin:where(.is-reverted) .fate-curve { border-color: var(--border-2); }
.fate-twin-ev { position: relative; padding: var(--sp-1) 0 var(--sp-5); }
.fate-twin-ev .fate-knot { left: calc(var(--silk-b) - var(--silk-pad) - 4px); top: calc(var(--sp-1) + 5px); }
.fate-twin-ev:where(.is-change) { padding-bottom: var(--sp-6); }
.fate-change { font-size: var(--fs-15); line-height: 1.6; }
.fate-change::before { content: '改动'; display: block; font-family: var(--font-serif); font-size: var(--fs-12); color: var(--text-3); letter-spacing: .06em; }
.fate-ev-text { font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); margin-top: 2px; }
.fate-twin-ev:where(.is-pending) .btn { margin: var(--sp-3) 0 var(--sp-2); }
.fate-twin-sum { padding-bottom: var(--sp-4); }
.fate-twin-legend { position: relative; height: 18px; }
.fate-twin-legend .fate-date { position: absolute; top: 2px; white-space: nowrap; }
.fate-twin-legend .fate-date:first-child { left: calc(var(--silk-a) - var(--silk-pad) - 10px); transform: translateX(-100%) translateX(-6px); display: none; }
.fate-twin-legend .fate-date:last-child { left: calc(var(--silk-b) - var(--silk-pad) + var(--sp-3)); }
.fate-twin-legend::before, .fate-twin-legend::after { content: ''; position: absolute; top: 0; width: 9px; height: 1px; }
.fate-twin-legend::before { left: calc(var(--silk-a) - var(--silk-pad) - 4px); background: var(--border-2); }
.fate-twin-legend::after { left: calc(var(--silk-b) - var(--silk-pad) - 4px); background: var(--text); }

/* 一起观看的两票 */
.fate-votes { display: flex; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.fate-vote { flex: 1; min-width: 0; }
.fate-vote-who { font-family: var(--font-serif); font-size: var(--fs-12); color: var(--text-3); letter-spacing: .06em; margin-bottom: var(--sp-2); }
.fate-vote-state { font-size: var(--fs-14); color: var(--text-3); line-height: 32px; }
.fate-vote-state:where(.is-set) { color: var(--text); }

/* 联机会话（4.476）：发送中的那条淡一点；失败的那一行是按钮，点一下重发 */
:where(.msg.is-pending) .bubble, :where(.msg.is-pending) .bubble-sticker { opacity: .55; }
.link-failed { background: none; border: none; padding: 0; cursor: pointer; }

/* 联机「我的资料」：头像点一下换（4.472） */
.link-face-btn { background: none; border: none; padding: 0; border-radius: 50%; cursor: pointer; }
.link-face-btns { display: flex; gap: var(--sp-2); }

/* 注入顺序 */
.order-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.order-row {
  display: flex; align-items: center; gap: var(--sp-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--sp-2) var(--sp-3);
}
.order-idx {
  width: 20px; height: 20px; flex: none; border-radius: var(--r-xs);
  background: var(--surface-2); color: var(--text-3);
  font-size: var(--fs-11); display: flex; align-items: center; justify-content: center;
}
.order-body { flex: 1; min-width: 0; }
.order-label { font-size: var(--fs-13); }
.order-desc { font-size: var(--fs-11); color: var(--text-3); margin-top: 1px; }
.order-btn {
  width: 28px; height: 28px; flex: none; border-radius: var(--r-xs);
  background: var(--surface-2); color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
}
.order-btn:disabled { opacity: .3; }

.tpl-vars {
  font-size: var(--fs-11); color: var(--text-3);
  font-family: var(--font-mono); margin: var(--sp-2) 0 var(--sp-4);
}

/* 记忆 */
.stat-row { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.stat-chip {
  flex: 1; background: var(--surface); border-radius: var(--r-sm);
  padding: var(--sp-2); text-align: center;
}
.stat-chip b { display: block; font-size: var(--fs-17); font-weight: var(--fw-semi); }
.stat-chip span { font-size: var(--fs-11); color: var(--text-3); }
.rank {
  width: 22px; height: 22px; border-radius: var(--r-xs);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-11); font-weight: var(--fw-semi);
  background: var(--surface-2); color: var(--text-2);
}
.rank-S { background: var(--accent); color: var(--on-accent); }
.rank-A { background: var(--accent-weak); color: var(--accent); }

/* 会话 */
.chat-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; font-size: var(--fs-11); }

.conv { height: 100%; display: flex; flex-direction: column; }
/* 消息区 + 浮在它上面的东西。定位上下文只能是这一层：
   放到 .conv 上的话，「回到最新」会压在发送键上 */
.conv-main { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; }
.conv-body { flex: 1; min-height: 0; padding: var(--sp-4) var(--sp-3); display: flex; flex-direction: column; gap: var(--bubble-gap); }
.conv-hint { margin: auto; color: var(--text-3); font-size: var(--fs-12); }

.msg { display: flex; gap: var(--sp-2); align-items: flex-start; transition: transform var(--dur-fast) var(--ease-out); }
/* 左右滑一下引用这一条：跟着手指平移，松手弹回（Conversation.js 的 Bubble）。
   位移由脚本写进 --swipe-x，不写内联 transform */
.msg.is-swiping { transform: translateX(var(--swipe-x, 0)); transition: none; }
/* 状态类一律包进 :where()：挂了 ph- 钩子的元素，作者写单个契约钩子就要盖得住（ARCHITECTURE 4.257）*/
.msg:where(.is-mine) { flex-direction: row-reverse; }
/* 同一个人接着说的那一条，和上一条之间收紧。收紧到的距离跟着「同一轮里两个气泡之间」走，
   美化里改了那个间距，这里跟着变 */
.msg:where(.is-cont) { margin-top: calc(var(--bubble-gap-in) * 2 - var(--bubble-gap)); }
/* 两条消息中间居中的那一行时间（相隔五分钟以上才有） */
.time-sep { align-self: center; padding: var(--sp-1) 0; font-size: var(--fs-12); color: var(--text-3); }
.msg-col { display: flex; flex-direction: column; gap: var(--bubble-gap-in); max-width: 74%; min-width: 0; }
:where(.msg.is-mine) .msg-col { align-items: flex-end; }
/* 对方那一边的气泡不跟着这一列被撑宽（4.666）：列里还有心声、译文这些更长的一行时，从前气泡被拉到和它一样宽，
   右边空出一截（用户截图）。气泡按自己的内容宽；包进 :where，不压美化钩子（第 18 条） */
:where(.msg-col) > .bubble { align-self: flex-start; }
:where(.msg.is-mine .msg-col) > .bubble { align-self: flex-end; }
/* 气泡上的时刻与已读回执。两样默认都关着，开了才有这个节点。
   靠着气泡那一档（4.302）：回执在气泡列里，列变成两栏的网格 —— 一栏气泡、一栏回执，
   引用、名字、心声这些横跨两栏。回执那一栏是 1fr，宽出来的引用只撑它，不撑气泡那一栏，
   回执因此总贴着气泡，不跟着引用的宽度走。
   回执排在最后一个气泡的后面（角色）或前面（自己），自动排位正好把两者放进同一行。
   特异度一律单个类名（第 18 条） */
:where(.msg.has-aside) .msg-col {
  display: grid; grid-template-columns: minmax(0, max-content) 1fr; column-gap: 0;
  justify-items: start; align-items: start;
}
:where(.msg.is-mine.has-aside) .msg-col { grid-template-columns: 1fr minmax(0, max-content); justify-items: end; }
:where(.msg.has-aside) .msg-col > * { grid-column: 1 / -1; }
:where(.msg.has-aside:not(.is-mine)) .msg-col > :where(:has(+ .msg-meta)) { grid-column: 1; }
:where(.msg.has-aside) .msg-col > :where(.msg-meta) { grid-column: 2; justify-self: start; align-self: end; margin-left: var(--sp-2); }
:where(.msg.is-mine.has-aside) .msg-col > :where(.msg-meta) { grid-column: 1; justify-self: end; margin-left: 0; margin-right: var(--sp-2); }
:where(.msg.is-mine.has-aside) .msg-col > :where(.msg-meta + *) { grid-column: 2; }
.msg-meta {
  flex: none; display: flex; gap: var(--sp-1);
  font-size: var(--fs-11); color: var(--text-3); line-height: 1.3;
  white-space: nowrap;
}
.msg-meta.at-side {
  align-self: flex-end; flex-direction: column; align-items: flex-start;
  gap: 1px; padding-bottom: 3px;
}
.msg.is-mine .msg-meta.at-side { align-items: flex-end; }
.msg-meta.at-below { align-items: baseline; padding-top: 1px; }
.bubble {
  padding: var(--bubble-py) var(--bubble-px); border-radius: var(--bubble-r);
  background: var(--bubble-theirs, var(--surface)); font-size: var(--bubble-fs); line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
  box-shadow: var(--bubble-shadow, var(--shadow-1));
}
:where(.msg.is-mine) .bubble { background: var(--accent); color: var(--on-accent); }

/* 正在输入写在标题栏上，名字整个换掉 —— 这句话说的是「对方现在在干什么」，
   属于这段对话的状态，不属于消息流。聊天记录里凭空多一个空泡，
   是这个界面在说自己的事。 */
.conv-typing { color: var(--text-3); font-weight: var(--fw-normal); }


/* 回复失败那一条：报错原文（最多三行，点一下展开全文，4.793）、重试、去充值 */
.fail-note { display: flex; flex-direction: column; gap: var(--sp-1); max-width: 260px; }
.fail-text { font-size: var(--fs-11); color: var(--text-3); line-height: 1.5; word-break: break-all;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.fail-text:where(.is-open) { display: block; -webkit-line-clamp: unset; overflow: visible; }
.fail-acts { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.fail-hint { font-size: var(--fs-11); color: var(--text-3); line-height: 1.5; }
.msg-retry { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-2); text-decoration: underline; }
.swipes { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-11); color: var(--text-3); }
/* 命中禁写词的记号。低调地摆在气泡下面，不拦着也不弹窗 —— 要不要重掷是用户的事 */
.msg-ban { font-size: var(--fs-11); color: var(--text-3); padding: var(--sp-1) 0 0; }
.msg-cut { font-size: var(--fs-11); color: var(--text-3); padding: var(--sp-1) 0 0; }
.msg-proxy { font-size: var(--fs-11); color: var(--text-3); padding: var(--sp-1) 0 0; }
.swipe-btn { color: var(--text-2); display: flex; }
/* 旁白与「已读，未回复」那一行下面的切换条：居中，与那一行对齐（4.584） */
/* 动态页的「重新生成配图」（4.589） */
.mo-redraw { display: flex; gap: var(--sp-4); padding-top: var(--sp-2); }
.swipes-line { display: flex; justify-content: center; padding-bottom: var(--sp-1); }

/* 引用块。气泡上面顶一小条，点一下跳回原话。
   align-self 收着，不然它会撑满整列，比底下那条正文还宽。
   DOM 里它排在气泡后面，靠 order 画到上面：美化写 order: 0 就回到气泡下方（ARCHITECTURE 4.208）。
   群里那一行名字要在它更上面 */
:where(.msg-col) > .msg-who { order: -2; }
.quote-ref {
  order: -1;
  align-self: flex-start;
  display: flex; align-items: baseline; gap: var(--sp-2);
  max-width: 100%; min-width: 0; text-align: left;
  padding: 5px var(--sp-2); border-radius: var(--r-sm);
  background: var(--group-fill); border-left: 2px solid var(--group-line);
  font-size: var(--fs-11); color: var(--text-3); line-height: 1.5;
}
.quote-ref.is-dead { opacity: .6; }
.quote-name { flex: none; color: var(--text-2); }
.quote-text { min-width: 0; }
/* 引的是图片或表情包（4.936）：一张小图，和名字排在同一行 */
.quote-media { display: inline-flex; align-self: center; }
.quote-img { width: 36px; height: 36px; object-fit: cover; border-radius: var(--r-xs); display: block; }
/* 自己发的靠右，但名字仍然读在前面，别跟着一起翻过来 */
.msg.is-mine .quote-ref {
  align-self: flex-end;
  border-left: none; border-right: 2px solid var(--group-line);
}

/* 包在气泡里的那一份引用。默认不显示，美化放出来（见契约里的 .ph-quote-in）。
   颜色跟着气泡的字色走，深色气泡上也看得清 */
.bubble-quote {
  display: none; align-items: baseline; gap: var(--sp-2);
  margin: 0 0 var(--sp-2); padding: 3px var(--sp-2);
  border-left: 2px solid currentColor;
  font-size: var(--fs-11); line-height: 1.5; opacity: .7;
  text-align: left; white-space: normal;
}
.bubble-quote .quote-name { color: inherit; font-weight: var(--fw-medium); }
.bubble-quote .quote-text {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* 撤回之后留下的那一行（system/recall.js）。点开，原来那一条接在下面、压淡一点 */
.msg-gone { display: flex; flex-direction: column; }
.recall-line {
  align-self: center; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); font-size: var(--fs-12); color: var(--text-3); line-height: 1.6;
}
.recall-hint { color: var(--text-2); text-decoration: underline; text-underline-offset: 2px; }
.msg:where(.is-recalled) { opacity: .55; }
.msg-gone.is-picked .recall-line { color: var(--accent); }

/* 回应与不回复（system/reaction.js，4.468）。照 iMessage 的 tapback：回应就是回应者的一个小气泡，
   压在被回应那条气泡的上角（对方的在右上，自己的在左上），尾巴朝外、朝着回应者那一侧。
   它挂的正是气泡的类（.bubble .ph-bubble .ph-bubble-mine / -theirs）：谁贴的就是谁的气泡颜色，
   用户改了气泡样式它跟着变，不另定一套颜色。这里只改尺寸与形状；颜色那两条写在后面压过
   「自己那一侧的气泡用主色」那条（一条回应贴在我的气泡上，仍按贴的人算）。
   .msg-reacts 是排在气泡前面的一个矮占位，只负责留出高度与定位。状态类一律包进 :where()（第 18 条） */
.silence-line { font-style: normal; }
/* 占位 12px 加上气泡之间 5px 的间距，圆泡（26px）从 -2px 起：只压进气泡顶边 6px，落在内边距里，碰不到字 */
.msg-reacts { position: relative; width: 100%; height: 12px; z-index: 2; }
/* 回执靠着气泡那一档（列是两栏网格）：占位只占气泡那一栏，圆泡才贴着气泡的角，不贴到回执上 */
:where(.msg.has-aside) .msg-col > :where(.msg-reacts) { grid-column: 1; justify-self: stretch; }
:where(.msg.is-mine.has-aside) .msg-col > :where(.msg-reacts) { grid-column: 2; }
/* 横向：圆泡的中心对准气泡的角，一半探在气泡外面 */
.tapback-row { position: absolute; top: -2px; right: -13px; display: flex; flex-direction: row-reverse; }
:where(.msg.is-mine) .tapback-row { right: auto; left: -13px; flex-direction: row; }
.tapback-one { position: relative; display: inline-flex; }
.tapback-one + .tapback-one { margin-right: -8px; }
:where(.msg.is-mine) .tapback-one + .tapback-one { margin-right: 0; margin-left: -8px; }
/* 形状与尺寸由外层定死（4.474、4.505）：颜色要跟气泡走，所以里面那层 .tapback-fill 挂着气泡的类；
   可美化里给气泡写的内边距、最小宽度、阴影、尾巴（::before / ::after）会一起落到它身上，圆泡被撑成一大块白（用户截图）。
   现在外层 .tapback / .tapback-dot 定尺寸、裁成胶囊或圆，fill 只在里面铺满一格网格：它被撑大也只是被裁掉，
   内边距只挤它自己的内容区，表情绝对定位在它的内边距盒里居中，不受影响。美化作者要换圆泡的样子写 .ph-react */
.tapback {
  position: relative; display: grid; grid-template: 100% / 100%; width: 26px; height: 26px; padding: 0; margin: 0; border: 0;
  background: none; overflow: hidden; border-radius: var(--r-full); clip-path: inset(0 round var(--r-full));
}
.tapback:where(.has-n) { width: 40px; }
/* 居中放进那一格：被美化撑大时向四周平均溢出再被裁掉，表情仍在正中 */
.tapback-fill { grid-area: 1 / 1; place-self: center; position: relative; display: block; width: 100%; height: 100%; max-width: none; min-width: 0; min-height: 0; margin: 0; padding: 0; }
.tapback-fill:where(.ph-bubble-theirs) { background: var(--surface); color: var(--text); }
.tapback-fill:where(.ph-bubble-mine) { background: var(--accent); color: var(--on-accent); }
.tapback-face {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 2px;
  font-size: var(--fs-14); line-height: 1; white-space: nowrap; color: inherit;
}
/* 两颗小尾点朝外、朝着回应者那一侧（用户对照真机截图：对方气泡上的圆泡尾巴朝我这边，自己气泡上的朝对方那边）。
   第一颗大点和圆泡融在一起一小块，第二颗小点才分开。同样是外层定尺寸裁成圆，里面一层 fill 借气泡的颜色 */
.tapback-dot {
  position: absolute; display: grid; grid-template: 100% / 100%; width: 8px; height: 8px; right: -2px; bottom: -2px;
  overflow: hidden; border-radius: 50%; clip-path: circle(50%); pointer-events: none;
}
.tapback-dot:where(.is-2) { width: 5px; height: 5px; right: -8px; bottom: -8px; }
:where(.msg.is-mine) .tapback-dot { right: auto; left: -2px; }
:where(.msg.is-mine) .tapback-dot:where(.is-2) { left: -8px; }
.react-face { flex: none; }
.react-emoji { white-space: nowrap; }
.react-n { font-size: var(--fs-11); }
/* 长按菜单顶上那一条悬浮胶囊 */
.react-bar {
  display: flex; gap: var(--sp-1); margin: var(--sp-2) var(--sp-2) 0; padding: var(--sp-1);
  border-radius: var(--r-full); background: var(--surface-2);
}
.react-pick {
  flex: 1; min-width: 0; height: 38px; border-radius: var(--r-full);
  font-size: var(--fs-20); line-height: 1; display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur-fast) var(--ease-out);
}
.react-pick:active { background: var(--surface-3); transform: scale(1.2); }
.react-more { color: var(--text-2); }
/* 整页选回应 */
.react-sheet { padding: var(--sp-3) var(--sp-4); }
.react-input { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); }
.react-input > :first-child { flex: 1; }
.react-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: var(--sp-1);
}
.react-cell {
  height: 44px; border-radius: var(--r-md); font-size: var(--fs-24); line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.react-cell:active { background: var(--surface-2); }

/* 被引用的那条跳过去之后闪一下 */
.msg.is-flash .bubble { animation: msg-flash var(--dur-slow) var(--ease-out) 2 alternate; }
@keyframes msg-flash { to { background: var(--accent-weak); } }

/* 长按菜单里先把这条原样摆出来，别让人对着一列动作猜自己按中了哪条 */
.msg-menu-quote {
  margin: 0 var(--sp-4) var(--sp-3); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm); background: var(--group-fill);
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.6;
  max-height: 84px; overflow: hidden;
}

/* 修格式 */
.fix-head {
  padding: 0 var(--sp-4) var(--sp-3);
  font-size: var(--fs-12); color: var(--text-3); line-height: 1.6;
}
.fix-preview {
  margin: 0 var(--sp-4) var(--sp-3); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm); background: var(--group-fill);
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
  max-height: 120px; overflow: hidden;
}

/* 多选。只用左边那个勾表示选中，不去框气泡 —— 描一圈边太吵 */
.msg.is-picking { cursor: pointer; }
.msg.is-picking .msg-col { pointer-events: none; }
.pick-dot {
  flex: none; align-self: center; width: 18px; height: 18px; border-radius: var(--r-full);
  border: 1px solid var(--group-line); background: var(--surface);
  display: flex; align-items: center; justify-content: center; color: var(--on-accent);
}
.pick-dot.is-on { background: var(--accent); border-color: var(--accent); }

.select-bar {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  padding-bottom: calc(var(--sp-3) + var(--safe-bottom));
  background: var(--bg);
}
.select-hint { font-size: var(--fs-13); color: var(--text-3); }
/* 多选底栏上面一行：往下全选、选中间（4.757） */
.select-bar:where(.has-range) { flex-wrap: wrap; row-gap: var(--sp-2); }
.select-range { flex-basis: 100%; display: flex; justify-content: center; gap: var(--sp-6); font-size: var(--fs-14); }
/* 记忆的多选（4.299）：钉在列表底部，滚动时一直看得见 */
.mem-select { position: sticky; bottom: 0; border-top: 1px solid var(--border); }
/* 选中了进行中的事时多出「了结」「改为事件」两个（4.534）：窄屏上让「已选几条」先让位 */
.mem-select .select-hint { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mem-select { gap: var(--sp-1); }
.mem-select .nav-text { flex: none; }
.nav-text.is-off { color: var(--text-3); }
.nav-text.is-danger { color: var(--danger); }

/* 待办确认栏。和引用栏同一个位置：有一件事等你点头，就压在输入框上面。
   不做成弹窗 —— 聊天里说「我想」的频率很高，一句一个弹窗没法聊天 */
.todo-bar {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) 0;
}
.todo-ask { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); }
.todo-ask b {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--fs-13); font-weight: 500;
}
.todo-tag {
  flex: none; font-size: var(--fs-11); color: var(--text-3);
  background: var(--surface-2); border-radius: var(--r-xs); padding: 1px var(--sp-2);
}
.todo-bar .nav-text { flex: none; }
/* 好友与拉黑（4.306）：输入框上面那一行说明，以及被拒收那条气泡下面的一行 */
.tie-bar {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + var(--safe-bottom));
}
.tie-text { flex: 1; min-width: 0; font-size: var(--fs-13); color: var(--text-2); line-height: 1.5; }
.tie-bar .nav-text { flex: none; }
.msg-reject { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--danger); }
.todo-acts { display: flex; align-items: center; gap: var(--sp-2); }
/* 账户下面那一排「存入 / 取出」。贴着它自己那一行，不另起一段 */
.acc-money {
  display: flex; gap: var(--sp-2);
  padding: 0 var(--sp-4) var(--sp-3);
}
/* 更多 - 世界书与文风：展开的那本书的条目，往里缩一点 */
.lore-entries { padding-left: var(--sp-6); }
/* 支出分类那一条占比。细细一道，看的是长短不是数字 */
.sp-bar {
  display: block; height: 3px; border-radius: var(--r-full);
  background: var(--surface-3); margin: var(--sp-1) 0;
}
.sp-bar > span { display: block; height: 100%; border-radius: var(--r-full); background: var(--accent); opacity: var(--seg-o, 1); }
/* 支出构成的环形图（4.293）。各类同一个颜色，按深浅（--seg-o）分先后 */
.sp-donut { position: relative; width: 200px; height: 200px; margin: var(--sp-5) auto var(--sp-2); }
.sp-donut > svg { width: 100%; height: 100%; transform: rotate(-90deg); display: block; }
.sp-track { fill: none; stroke: var(--surface-3); stroke-width: 14; }
.sp-seg {
  fill: none; stroke: var(--accent); stroke-opacity: var(--seg-o, 1); stroke-width: 14;
  cursor: pointer; transition: stroke-width var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.sp-seg.is-hi { stroke-width: 20; }
.sp-seg.is-dim { opacity: .35; }
.sp-center {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; pointer-events: none; text-align: center; padding: 0 var(--sp-6);
}
.sp-center-lab { font-size: var(--fs-12); color: var(--text-2); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-center-num { font-size: var(--fs-20); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.sp-dot { display: block; width: 10px; height: 10px; border-radius: var(--r-full); background: var(--accent); opacity: var(--seg-o, 1); }
.sp-cat:where(.is-hi) { background: var(--accent-weak); }
/* 通话里那句「为什么没有这个角色的声音」。和字幕同一列，低一档 */
/* 两张脸：原本的与现在在用的。并排摆，一眼看得出换过 */
.face-pair { display: flex; gap: var(--sp-5); justify-content: center; }
.face-one { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); }
.face-one span { font-size: var(--fs-11); color: var(--text-3); }
/* 主页上那张小的，贴在大头像旁边，点一下换回去 */

.call-why {
  flex: none; text-align: center; font-size: var(--fs-11);
  color: var(--text-3); padding: 0 var(--sp-4) var(--sp-2);
}
.todo-tick { display: flex; color: var(--text-3); padding: var(--sp-1); }

/* 引用栏：正要引着谁说话，压在输入框上面 */
.quote-bar {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) 0;
}
.quote-bar .quote-ref { flex: 1; min-width: 0; }
.quote-bar > button { flex: none; color: var(--text-3); display: flex; padding: var(--sp-1); }

/* 回到最新。往上翻着看旧消息时才出现，压在输入框正上方 ——
   那是拇指本来就在的位置，不必伸到别处去。 */
.to-bottom {
  position: absolute; right: var(--sp-4); bottom: var(--sp-3);
  width: 38px; height: 38px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--text-2);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2);
  animation: fade-in var(--dur-fast) var(--ease);
  z-index: 3;
}
/* 往上翻着看时，底下来了几条新消息（4.451） */
.to-bottom-count { position: absolute; top: -6px; right: -4px; }
/* 联机会话：爬楼时来了新消息，一枚「N 条新消息」，点一下跳到没看到的第一条（4.734） */
.to-fresh {
  position: absolute; right: var(--sp-4); bottom: var(--sp-3);
  height: 34px; padding: 0 var(--sp-3); border-radius: var(--r-full);
  display: flex; align-items: center; gap: var(--sp-1);
  background: var(--surface); color: var(--accent);
  border: 1px solid var(--border); box-shadow: var(--shadow-2);
  font-size: var(--fs-13);
  animation: fade-in var(--dur-fast) var(--ease);
  z-index: 3;
}

/* 输入区与消息区同底，不要分隔线也不要换颜色 */
.composer-bar {
  flex: none; display: flex; gap: var(--sp-2); align-items: flex-end;
  padding: var(--composer-pad) var(--sp-3);
  padding-bottom: calc(var(--composer-pad) + var(--safe-bottom));
  background: var(--bg);
}
.composer-side {
  position: relative;
  width: var(--composer-h); height: var(--composer-h); flex: none; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center; color: var(--text-2);
}
/* 输入栏这几个是**最常按**的，命中区多给一点。
   往上扩得比往下多：拇指从下方够过来，落点总是偏下 */
.composer-side::after { content: ''; position: absolute; inset: -8px -3px -4px; }
/* 「我也写旁白」开着时输入栏上方那一行「消息 旁白」（4.343）。选中的加粗、底下一道短线；
   写旁白时输入框换成虚线框、字居中，发出去之前看上去就是一行旁白。状态类包进 :where，不压美化钩子（第 18 条） */
/* 「消息 旁白」切换：不再是横满一行的条，只是输入栏左上角两个很小的字，当前那个加一点底色 */
/* 「消息 旁白」切换条（4.343）。用户要的样子（4.506）：不再是输入栏上方多出来的一整行底色，
   而是像文件夹的标签页 —— 两个圆角梯形的小标签直接立在底栏上沿，选中的那一个和底栏同色、连成一块，
   另一个颜色稍深、退在后面。这一行本身透明，露出聊天背景。
   梯形用伪元素做：圆角矩形沿底边做一点透视，上窄下宽，四角仍是圆的。颜色走两个变量，
   底栏换了颜色（会话「聊天背景」里的底栏颜色）时跟着换，见后面 look-bottom 那一段 */
.composer-tabs {
  --tab-on: var(--bg); --tab-off: color-mix(in srgb, var(--text) 9%, var(--tab-on));
  flex: none; display: flex; align-items: flex-end; padding: 0 var(--sp-4); margin-bottom: -1px;
  position: relative; z-index: 1;
}
.composer-tab {
  position: relative; isolation: isolate; padding: 5px 18px 4px; margin-right: -4px;
  font-size: var(--fs-12); line-height: 1.4; color: var(--text-3); background: none; border-radius: 0;
}
.composer-tab::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: var(--tab-off); border-radius: 9px 9px 0 0;
  box-shadow: inset 1px 1px 0 var(--border), inset -1px 0 0 var(--border);
  transform: perspective(26px) rotateX(5deg); transform-origin: bottom;
}
.composer-tab:where(.is-on) { color: var(--text); font-weight: var(--fw-medium); z-index: 1; }
.composer-tab:where(.is-on)::before { background: var(--tab-on); }
.composer-input {
  flex: 1; max-height: 110px; min-height: var(--composer-h); border-radius: var(--r-lg);
  padding: var(--sp-2) var(--sp-3); resize: none;
  background: var(--surface-2); border: 1px solid var(--border);
}
/* 写旁白时（4.343）：虚线框、字居中。要写在上面这条之后，不然底色和边框被它盖回去 */
.composer-input:where(.is-narr) {
  background: transparent; border-style: dashed; border-color: var(--border-2);
  text-align: center; color: var(--ph-narration-color, var(--text-2));
}
.composer-panel {
  flex: none; background: var(--bg); padding: var(--sp-3) var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
}
.panel-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-4) var(--sp-2); }
/* 加号面板分页（4.901）：一页两行四列，左右滑动翻页，面板高度固定在两行。横向滚动加吸附，不藏原生手势 */
.panel-pager {
  display: flex; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.panel-pager::-webkit-scrollbar { display: none; }
.panel-page { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; scroll-snap-stop: always; }
.panel-dots { display: flex; justify-content: center; gap: var(--sp-2); padding-top: var(--sp-3); }
.panel-dot {
  width: 6px; height: 6px; border-radius: var(--r-full); background: var(--border-2); padding: 0;
  transition: background var(--dur-fast) ease;
}
.panel-dot:where(.is-on) { background: var(--text-2); }
/* 长按菜单底下那排（4.902）：贴着格子，不再隔一大段 */
.panel-dots:where(.pop-dots) { padding: 0 0 var(--sp-2); }
.panel-item {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-size: var(--fs-11); color: var(--text-2);
}
.panel-icon {
  width: 52px; height: 52px; border-radius: var(--r-md);
  background: var(--surface-2); display: flex; align-items: center; justify-content: center;
  color: var(--text);
}
.panel-empty { font-size: var(--fs-12); color: var(--text-3); line-height: 1.7; padding: var(--sp-4) 0; }

/* 兼容朋友圈评论区里那个内联输入 */
.composer { display: flex; gap: var(--sp-2); align-items: flex-end; }
.composer-inline { padding: var(--sp-3) 0 0; }
.composer textarea {
  flex: 1; max-height: 110px; min-height: 38px; border-radius: var(--r-lg);
  padding: var(--sp-2) var(--sp-3); resize: none;
}
.send-btn {
  position: relative;
  width: var(--composer-h); height: var(--composer-h); flex: none; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent);
  display: flex; align-items: center; justify-content: center;
}
.send-btn::after { content: ''; position: absolute; inset: -8px -3px -4px; }
.send-btn:disabled { opacity: .35; }
.send-btn:where(.is-stop) { background: var(--surface-3); color: var(--text); }
/* 让对方回复：不要底色，只留图标 */
.send-btn:where(.is-ghost) { background: none; color: var(--text); }

/* 转发的聊天记录（system/forward.js）：标题、前三行预览、底下一行「聊天记录」 */
.bubble-forward { cursor: pointer; min-width: 180px; max-width: 240px; }
.fw-title { font-size: var(--fs-14); font-weight: var(--fw-medium); margin-bottom: var(--sp-1); }
.fw-lines { display: grid; gap: 2px; }
/* 颜色跟着气泡走：自己发的在深色底上，写死 --text-2 就看不见 */
.fw-line { font-size: var(--fs-12); color: inherit; opacity: .78; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 转发的记录打开后按聊天的样子画（4.937），卡片自己带内边距 */
.fw-chat { padding-bottom: var(--sp-5); }

/* 长篇向导（apps/us/pages/NewSaga.js） */
.nv-add { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); }
.nv-add input { flex: 1; min-width: 0; }
.nv-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.nv-tag { font-size: var(--fs-11); color: var(--text-3); white-space: nowrap; }

/* 主页（Instagram 式，见 ARCHITECTURE 4.149） */
.ig-head { display: flex; align-items: center; gap: var(--sp-5); padding: var(--sp-4) var(--sp-4) var(--sp-3); }
:where(.ig-head) .avatar { flex: none; }
.ig-face { position: relative; flex: none; }
/* 「原本的」那一张贴在头像右下角。从前它在按钮那一行里，把整行撑开 */
.ig-face-base { position: absolute; right: -2px; bottom: -2px; border-radius: var(--r-full); }
:where(.ig-face-base) .avatar { box-shadow: 0 0 0 2px var(--bg); }
.ig-stats { flex: 1; display: flex; justify-content: space-around; min-width: 0; }
.ig-stat { text-align: center; padding: var(--sp-1) var(--sp-2); }
.ig-stat b { display: block; font-size: var(--fs-17); font-weight: var(--fw-semi); }
.ig-stat span { font-size: var(--fs-12); color: var(--text-3); }
.ig-bio { padding: 0 var(--sp-4); }
.ig-name { font-size: var(--fs-15); font-weight: var(--fw-semi); }
.ig-sign { font-size: var(--fs-13); color: var(--text-2); margin-top: 2px; white-space: pre-wrap; word-break: break-word; }
.ig-alias { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
.ig-acts { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4) var(--sp-2); }
.ig-acts > .btn { flex: 1; }
.ig-hl { display: flex; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4) var(--sp-3); overflow-x: auto; }
.ig-hl-item { flex: none; width: 64px; display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); }
.ig-hl-ring { width: 60px; height: 60px; border-radius: var(--r-full); padding: 2px; border: 1px solid var(--border-2); }
.ig-hl-ring:where(.is-add) { border-style: dashed; }
.ig-hl-img {
  width: 100%; height: 100%; border-radius: var(--r-full);
  background: var(--surface-3); background-image: var(--hl-img, none); background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.ig-hl-item span { font-size: var(--fs-11); color: var(--text-2); max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ig-hl-view {
  aspect-ratio: 1; border-radius: var(--r-md); background-color: var(--surface-3);
  background-size: contain; background-repeat: no-repeat; background-position: center;
}
.ig-tabs { display: flex; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.ig-tab { flex: 1; display: flex; justify-content: center; padding: var(--sp-3) 0; color: var(--text-3); border-bottom: 1px solid transparent; margin-bottom: -1px; }
.ig-tab:where(.is-on) { color: var(--text); border-bottom-color: var(--text); }
.ig-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; }
.ig-cell { position: relative; aspect-ratio: 1; background: var(--surface-3); background-image: var(--cell-img, none); background-size: cover; background-position: center; }
.ig-cell-multi {
  position: absolute; top: var(--sp-2); right: var(--sp-2);
  width: 22px; height: 22px; border-radius: var(--r-full);
  background: var(--scrim); color: var(--on-scrim);
  display: flex; align-items: center; justify-content: center;
}

/* 动态详情 */
.ig-author { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.ig-author-name { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.ig-author-time { font-size: var(--fs-11); color: var(--text-3); }
.ig-pager { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; aspect-ratio: 1; background: var(--surface-3); }
.ig-slide { flex: none; width: 100%; height: 100%; scroll-snap-align: start; background-image: var(--mo-img, none); background-size: contain; background-repeat: no-repeat; background-position: center; }
.ig-dots { display: flex; justify-content: center; gap: 5px; padding: var(--sp-2) 0 0; }
.ig-dot { width: 6px; height: 6px; border-radius: var(--r-full); background: var(--border-2); }
.ig-dot.is-on { background: var(--text); }
.ig-foot { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--sp-4) var(--sp-2); }
.ig-foot .mo-act { font-size: var(--fs-13); }
.ig-text { padding: 0 var(--sp-4) var(--sp-3); font-size: var(--fs-14); line-height: 1.6; white-space: pre-wrap; word-break: break-word; }
.ig-comments { padding: 0 var(--sp-4) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }

/* 朋友圈 */
.moments { padding-bottom: var(--sp-6); }
.mo-header {
  position: relative; height: 210px; margin-bottom: 34px;
  background: var(--surface-3); background-image: var(--mo-cover, none); background-size: cover; background-position: center;
}
.mo-header-acts {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  display: flex; gap: var(--sp-2);
}
.mo-header-btn {
  width: 34px; height: 34px; border-radius: var(--r-full);
  background: var(--scrim); color: var(--on-scrim);
  display: flex; align-items: center; justify-content: center;
}
.mo-header-btn svg { color: var(--on-scrim); }
.mo-header-me {
  position: absolute; right: var(--sp-4); bottom: -28px;
  display: flex; align-items: flex-end; gap: var(--sp-3);
}
.mo-header-name {
  font-size: var(--fs-15); font-weight: var(--fw-semi); color: var(--on-scrim);
  text-shadow: 0 1px 6px rgba(0, 0, 0, .55); padding-bottom: 34px;
}
:where(.mo-header-me) .avatar { box-shadow: 0 0 0 3px var(--bg); }
.mo-card {
  display: flex; gap: var(--sp-3); padding: var(--sp-4);
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.mo-main { flex: 1; min-width: 0; }
.mo-name { font-size: var(--fs-13); font-weight: var(--fw-medium); color: var(--accent); }
.mo-text { font-size: var(--fs-14); line-height: 1.6; margin-top: 3px; white-space: pre-wrap; word-break: break-word; }
.mo-photos { display: grid; gap: 3px; margin-top: var(--sp-2); grid-template-columns: repeat(3, 1fr); }
.mo-photos.n1 { grid-template-columns: 1fr; max-width: 62%; }
.mo-photos.n2, .mo-photos.n4 { grid-template-columns: repeat(2, 1fr); max-width: 76%; }
.mo-photo { aspect-ratio: 1; background: var(--surface-3); background-image: var(--mo-img, none); background-size: cover; background-position: center; border-radius: var(--r-xs); }
.mo-foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-2); }
.mo-time { font-size: var(--fs-11); color: var(--text-3); }
.mo-actions { display: flex; gap: var(--sp-3); }
.mo-act { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-3); }
.mo-act.is-on { color: var(--text); }
/* 转发朋友圈（4.367）：附在下方的原动态、聊天里那张卡片 */
.mo-repost { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); padding: var(--sp-2); background: var(--surface-2); border-radius: var(--r-sm); }
.mo-repost-body { min-width: 0; flex: 1; }
.mo-repost-who { font-size: var(--fs-12); color: var(--text-2); font-weight: var(--fw-medium); }
.mo-repost-text { font-size: var(--fs-13); color: var(--text-2); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.mo-share-thumb { flex: none; width: 44px; height: 44px; border-radius: var(--r-xs); background: var(--surface-3); background-image: var(--mo-img, none); background-size: cover; background-position: center; }
.mo-photos .mo-share-thumb { width: auto; height: auto; aspect-ratio: 1; }
.mo-share-note { font-size: var(--fs-12); color: var(--text-3); margin-bottom: var(--sp-2); }
.mo-share-time { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-2); }
.bubble-moshare { cursor: pointer; min-width: 180px; max-width: 240px; }
.mosh-who { font-size: var(--fs-14); font-weight: var(--fw-medium); margin-bottom: var(--sp-1); }
.mosh-row { display: flex; gap: var(--sp-2); align-items: flex-start; }
.mosh-text { flex: 1; min-width: 0; font-size: var(--fs-12); opacity: .78; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.mo-comments { margin-top: var(--sp-2); padding: var(--sp-2); background: var(--surface-2); border-radius: var(--r-sm); }
.mo-comment { font-size: var(--fs-12); line-height: 1.7; word-break: break-word; }
.mo-comment b { color: var(--accent); font-weight: var(--fw-medium); }
/* 动态与评论的译文（4.363）：原文下面一行淡字 */
.mo-trans { margin-top: 2px; font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); white-space: pre-wrap; word-break: break-word; }
.mo-comment-list { display: flex; flex-direction: column; gap: 2px; }
.mo-upload { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.mo-thumb { position: relative; width: 66px; }
.mo-thumb .mo-photo { border-radius: var(--r-sm); }
.mo-thumb-x {
  position: absolute; top: -5px; right: -5px; width: 19px; height: 19px;
  border-radius: var(--r-full); background: var(--text); color: var(--bg);
  display: flex; align-items: center; justify-content: center;
}
.mo-add {
  width: 66px; aspect-ratio: 1; border: 1px dashed var(--border-2);
  border-radius: var(--r-sm); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}

/* 壁纸与图标自定义 */
.wp-row {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border);
}
.wp-row:last-child { border-bottom: none; }
.wp-preview {
  flex: none; width: 52px; height: 92px; border-radius: var(--r-sm);
  background: var(--surface-2); background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
  border: 1px solid var(--border);
}
.wp-body { flex: 1; min-width: 0; }
.wp-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }

.icon-chip {
  width: 30px; height: 30px; border-radius: 24%; background: var(--tile-bg);
  box-shadow: var(--tile-shadow);
  display: flex; align-items: center; justify-content: center;
}
.color-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.swatch {
  width: 36px; height: 36px; border-radius: var(--r-full);
  border: 1px solid var(--border-2); box-shadow: inset 0 0 0 2px var(--surface);
  position: relative;
}
.swatch.is-active { box-shadow: inset 0 0 0 2px var(--surface), 0 0 0 2px var(--text); }
.swatch-custom {
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text-2); cursor: pointer;
}
.swatch-custom input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.app-tile-mini { width: 30px; height: 30px; max-width: none; border-radius: 24%; }
.app-tile-mini svg { width: 62%; height: 62%; }
.mono { font-family: var(--font-mono); font-size: var(--fs-11); }
.icon-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: var(--sp-2);
}
.icon-pick {
  aspect-ratio: 1; border-radius: var(--r-sm); background: var(--surface-2);
  color: var(--text-2); display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent;
}
.icon-pick.is-active { background: var(--accent-weak); color: var(--text); border-color: var(--text); }
.sheet-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.sheet-acts .btn { flex: 1; }

/* 服务配置 */
.svc-dot {
  width: 8px; height: 8px; border-radius: var(--r-full);
  background: var(--border-2);
}
.svc-dot.is-main { background: var(--text); }
.svc-dot.is-spare { box-shadow: inset 0 0 0 1.5px var(--text); background: transparent; }
.svc-tag {
  font-size: var(--fs-11); color: var(--text-2);
  border: 1px solid var(--border-2); border-radius: var(--r-full);
  padding: 1px var(--sp-2);
}
.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* 滑杆加数字框。生成器上每一项都是这一对，所以定义在这儿，各处引用 */
.slider-row { display: flex; align-items: center; gap: var(--sp-3); }
.slider-row input[type="range"] { flex: 1; min-width: 0; }
.slider-num {
  flex: none; width: 58px; text-align: right;
  background: var(--surface-2); border: 0; border-radius: var(--r-sm);
  padding: 5px var(--sp-2); font-size: var(--fs-13); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.slider-unit { flex: none; font-size: var(--fs-12); color: var(--text-3); min-width: 20px; }
/* 没设过的那一档：滑杆压淡一点，一眼看出它现在不生效 */
.slider-row.is-unset input[type="range"] { opacity: .45; }
.slider-row.is-unset .slider-num { color: var(--text-3); }

/* 取色。色块、色值、以及那个「不改」 */
.color-row { display: flex; align-items: center; gap: var(--sp-3); }
.color-swatch {
  flex: none; width: 40px; height: 28px; padding: 0;
  border: 1px solid var(--border-2); border-radius: var(--r-sm); background: none;
}
.color-hex { flex: 1; min-width: 0; font-size: var(--fs-12); color: var(--text-2); }
.color-clear {
  flex: none; border: 1px solid var(--border-2); border-radius: var(--r-sm);
  background: none; color: var(--text-2); font-size: var(--fs-12); padding: 4px var(--sp-2);
}

/* 生成器：上面预览占满整宽，中间一排横着滑的分组，下面旋钮（4.639，从前是左边一条竖栏，4.140）。
   从上到下每一层都要把高度钉死 —— `.page-body` 自己不是 flex 容器，
   中间断一层，里面那个 .scroll 就撑成内容那么高，永远滚不动。 */
.gen { height: 100%; display: flex; flex-direction: column; min-height: 0; }

.gen-rail {
  flex: none; display: flex; flex-direction: row; gap: 2px;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  padding: 6px var(--sp-2); border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.gen-rail::-webkit-scrollbar { display: none; }
/* 旋钮收起时底栏是这一页最下面一条：灰底铺进 Home 横条那一截，不在底下垫一条白（页面那一层不再让，ui.css） */
.gen-rail:last-child { padding-bottom: calc(6px + var(--safe-bottom)); }
.gen-rail-btn {
  position: relative; flex: none; min-width: 54px;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px var(--sp-1); border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text-2); cursor: pointer;
}
.gen-rail-btn.is-on { background: var(--surface); color: var(--text); }
.gen-rail-label { font-size: var(--fs-11); line-height: 1.1; text-align: center; white-space: nowrap; }
.gen-rail-dot {
  position: absolute; top: 5px; right: 8px;
  width: 6px; height: 6px; border-radius: var(--r-full); background: var(--accent);
}
.gen-rail-sep { flex: none; width: 1px; background: var(--border); margin: 6px var(--sp-1); }

.gen-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.gen-stage-wrap {
  flex: none; height: 44%; min-height: 200px;
  border-bottom: 1px solid var(--border); background: var(--surface-2);
}
/* 旋钮收起来时预览占满整块 */
.gen-stage-wrap.is-full { flex: 1; height: auto; }
/* 放大那一层（4.639）：双指捏、双击、角上的加减号。放大后单指拖着看，所以这一块不交给浏览器的手势 */
.gen-zoomer { position: relative; height: 100%; width: 100%; overflow: hidden; touch-action: none; }
.gen-zoom { height: 100%; width: 100%; transform-origin: 0 0; }
.gen-stage { height: 100%; width: 100%; overflow: hidden; position: relative; }
.gen-zoom-bar {
  position: absolute; right: var(--sp-2); bottom: var(--sp-2); z-index: 2;
  display: flex; align-items: center; gap: 2px; padding: 2px;
  border-radius: var(--r-full); background: var(--surface); box-shadow: var(--shadow-1);
}
.gen-zoom-btn, .gen-zoom-num {
  display: flex; align-items: center; justify-content: center;
  min-width: 30px; height: 30px; padding: 0 6px; border: 0; border-radius: var(--r-full);
  background: none; color: var(--text); font-size: var(--fs-12);
}
.gen-zoom-btn:disabled { color: var(--text-3); }

.gen-panel { flex: 1; min-height: 0; padding-bottom: var(--safe-bottom); }
.gen-panel-head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg); border-bottom: 1px solid var(--border);
}
.gen-panel-title { font-size: var(--fs-14); font-weight: var(--fw-semi); color: var(--text); }
/* 「卡片」那一格里先选改哪一种。动过的那几种右上角一个小点，和竖栏上一样 */
.gen-card-pick { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-3); }
.gen-card-pick .chip { position: relative; }
.gen-card-pick .chip.has-dot::after {
  content: ''; position: absolute; top: 2px; right: 2px; width: 6px; height: 6px;
  border-radius: var(--r-full); background: var(--accent);
}
/* 这一组改的是哪个类名。手写 CSS 的人照着抄 */
.gen-panel-desc {
  padding: 0 var(--sp-4) var(--sp-2); font-size: var(--fs-12); color: var(--text-3);
  font-family: var(--font-mono); user-select: text; -webkit-user-select: text;
}
.gen-panel-close {
  border: 0; background: none; color: var(--text-2); font-size: var(--fs-13);
  padding: 2px var(--sp-1);
}
.gen-group { padding: 0 var(--sp-4) var(--sp-4); }
/* 新编辑器（4.836）：一组里先摆几项，其余收在「更多」里；最后一行小字说怎么用 */
.ed-more {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  width: calc(100% - var(--sp-4) * 2); margin: 0 var(--sp-4) var(--sp-3); padding: var(--sp-2) 0;
  border: 1px dashed var(--border); border-radius: var(--r-md); background: none;
  color: var(--text-2); font-size: var(--fs-13);
}
.ed-hint { padding: var(--sp-2) var(--sp-4) var(--sp-5); font-size: var(--fs-12); color: var(--text-3); line-height: 1.6; }
.icon-btn:disabled { opacity: .35; }
.gen-out {
  margin: var(--sp-4); padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text-2);
  font-family: var(--font-mono); font-size: var(--fs-11); line-height: 1.6;
  white-space: pre-wrap; word-break: break-all; max-height: 260px; overflow: auto;
}
.gen-pic { display: flex; align-items: center; gap: var(--sp-3); }
/* 图片旋钮下面那一行：填网址（4.440） */
.gen-pic-url { margin-top: var(--sp-2); }
.gen-pic-link { padding: 0; border: 0; background: none; color: var(--accent); font-size: inherit; }
.gen-pic-box {
  flex: none; width: 46px; height: 46px; border-radius: var(--r-sm);
  border: 1px solid var(--border-2); background-size: contain;
  background-position: center; background-repeat: no-repeat;
}
.btn-row .btn { flex: 1; min-width: 0; }
/* 一排可选的小标签（类型、型号、尺寸）：按内容定宽，放不下就换行，不挤成半截字 */
.btn-row.is-chips .btn { flex: none; }
/* 四个以上同级的按钮排成两列。挤在一行时第一个的字会被裁掉（设置 - 生图） */
.btn-row.is-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* 头像框：编辑页上那一小块试戴。和会话里一样，框挂在头像那个盒子外面，
   所以这里的结构也是「一个 36 见方的盒子 + 一张绝对定位的图」。 */
.frame-try { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; }
.frame-try-face { position: relative; width: 36px; height: 36px; flex: none; }
.frame-try-ring {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  object-fit: contain; pointer-events: none;
}
.frame-try-note { font-size: var(--fs-11); color: var(--text-3); }

/* 美化页的样板间：上面几条消息，下面一条底栏。底栏也画进来，否则
   「底栏按钮大小」「底栏内边距」两项令牌怎么调都看不出动静。 */
.skin-sample-wrap { display: flex; flex-direction: column; border-bottom: 1px solid var(--border); }
/* 样板间不在屏幕底部，Home Indicator 那一块留白挪过来只会多出一条空档 */
.skin-sample-wrap .composer-bar { padding-bottom: var(--composer-pad); }

.picker-state {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-5); color: var(--text-3); font-size: var(--fs-12);
}
.model-list {
  display: flex; flex-direction: column;
  margin-top: var(--sp-3); border-top: 1px solid var(--border);
}
.model-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-1); font-size: var(--fs-13);
  border-bottom: 1px solid var(--border); text-align: left;
  font-family: var(--font-mono);
}
.model-row.is-active { font-weight: var(--fw-semi); }

/* 消息列表与联系人：分组胶囊，细黑边 */
.msg-list { padding: var(--sp-3) var(--sp-4) var(--sp-6); }
/* 顶上「角色 / 联机」两页（4.664） */
.msg-split { margin: var(--sp-3) 0; }
/* 当前用的是小号（4.792）：消息列表顶上一行，写明是哪个小号，右边切回大号 */
.alt-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  margin: 0 var(--sp-4) var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md); background: var(--surface-2); color: var(--text-2); font-size: var(--fs-13);
}
.alt-bar > .nav-text { flex: none; }

.cap-wrap { margin-bottom: var(--sp-4); }
.cap-title {
  font-size: var(--fs-12); color: var(--text-3);
  padding: 0 var(--sp-3) var(--sp-2);
}
.capsule {
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--group-fill);
}
:where(:root[data-wallpaper="on"]) .capsule {
  background: var(--wg-solid);
}
:where(:root[data-wallpaper="on"][data-glass="on"]) .capsule { backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur)); }

.msg-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); min-height: 62px; cursor: pointer;
  position: relative;
}
.msg-row + .msg-row::before {
  content: ''; position: absolute; left: calc(var(--sp-4) + 46px + var(--sp-3));
  right: 0; top: 0; height: 1px; background: var(--group-line);
}
/* 会话行左滑（4.452）：整行跟着手指往左走，右边挂着的三个按钮从胶囊外面露进来。
   位移由 MessagesTab 写进 --swipe-x；跟手时不要过渡，松手吸附时要 */
.swipe-row { transform: translateX(var(--swipe-x, 0px)); transition: transform var(--dur) var(--ease); touch-action: pan-y; }
.swipe-row:where(.is-swiping) { transition: none; }
/* 不挂 .press：它按下时也写 transform，会和位移打架。按下的反馈只留变淡，滑动时不变淡 */
.swipe-row:where(:active:not(.is-swiping)) > * { opacity: .6; }
.swipe-acts { position: absolute; top: 0; bottom: 0; left: 100%; display: flex; }
.swipe-act {
  width: 72px; display: flex; align-items: center; justify-content: center;
  padding: 0 var(--sp-1); background: var(--surface-3); color: var(--text);
  font-size: var(--fs-13); line-height: 1.3; text-align: center;
}
.swipe-act.is-danger { background: var(--danger); color: var(--on-accent); }
.msg-main { flex: 1; min-width: 0; }
.msg-line { display: flex; align-items: baseline; gap: var(--sp-2); }
:where(.msg-line) + .msg-line { margin-top: 3px; }
.msg-name { flex: 1; min-width: 0; font-size: var(--fs-15); font-weight: var(--fw-medium); }
.msg-time { flex: none; font-size: var(--fs-11); color: var(--text-3); }
/* 名字旁的状态小字（autoReply.listTag）：像 QQ 的「忙碌」，一个小点加两个字 */
.msg-state { flex: none; display: inline-flex; align-items: center; gap: 3px; font-size: var(--fs-11); color: var(--text-3); margin-left: 2px; }
.msg-state::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--text-3); }
.msg-preview { flex: 1; min-width: 0; font-size: var(--fs-12); color: var(--text-3); }

.search-bar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); margin-bottom: var(--sp-4);
  background: var(--group-fill); border-radius: var(--r-full);
  color: var(--text-3);
}
.search-bar input {
  flex: 1; min-width: 0; border: none; background: none; padding: 0;
  font-size: var(--fs-14); color: var(--text);
}
.search-bar input:focus { border: none; }
.search-bar button { color: var(--text-3); display: flex; }

/* 表情包 */
.stk-img {
  width: 72px; height: 72px; object-fit: contain;
  border-radius: var(--r-sm); background: var(--group-fill);
}
.stk-miss {
  width: 72px; height: 72px; border-radius: var(--r-sm);
  background: var(--group-fill); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-12);
}

.stk-panel { display: flex; flex-direction: column; gap: var(--sp-2); max-height: 260px; }
.stk-tabs { display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-1); }
/* 分组多了横着滚，不许挤：flex 子项默认会缩，几十个分组一挤名字就溢出来了 */
.stk-tabs > .chip { flex: none; white-space: nowrap; }
.stk-tabs::-webkit-scrollbar { display: none; }
/* 分组条右边的「展开」（4.805）：摊成几行，限高在框里竖着滚；鼠标拖动时不选中文字 */
.stk-tabs-row { display: flex; align-items: flex-start; gap: var(--sp-2); }
.stk-tabs-row > .stk-tabs { flex: 1; min-width: 0; user-select: none; -webkit-user-select: none; }
.stk-tabs:where(.is-wrap) { flex-wrap: wrap; overflow-x: hidden; overflow-y: auto; max-height: 132px; overscroll-behavior: contain; }
.stk-more { flex: none; }
.stk-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--sp-2); max-height: 214px; align-content: start;
}
.stk-manage { max-height: none; padding: 0 var(--sp-1); }
.stk-cell { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 0; }
/* 表情下面那行名字：角色读到的就是它 */
.stk-cap { max-width: 100%; font-size: var(--fs-11); color: var(--text-3); line-height: 1.3; }
.stk-cell .stk-img, .stk-cell .stk-miss { width: 100%; height: auto; aspect-ratio: 1; }
/* 整理分组时选中的那几个 */
.stk-cell.is-picked { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-xs); }

.stk-suggest {
  flex: none; display: flex; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); overflow-x: auto;
}
.stk-suggest::-webkit-scrollbar { display: none; }
.stk-sug { flex: none; }

.bubble-sticker { padding: 0; background: none; }
.bubble-sticker .stk-img {
  width: 112px; height: 112px; background: none; border-radius: var(--r-md);
}
/* 不是正方形的表情缩进 112 的方框里，从前居中：宽的那张浮在方框中间、离头像一截，高的那张往里缩，
   和上下的气泡、头像都对不上（4.657，用户：「表情包突然对不齐了」）。现在方框按表情自己的宽高比画（StickerBits 的 fit）；
   比例还没记下的那一次（第一次显示）仍是正方形，图贴着靠头像的那个角：对方的贴左上，自己的贴右上 */
.bubble-sticker .stk-img { object-position: left top; }
:where(.msg.is-mine) .bubble-sticker .stk-img { object-position: right top; }

.stk-preview {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: var(--sp-2); margin: var(--sp-3) 0;
}
.stk-prev-item { display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 0; }
.stk-prev-item .stk-img, .stk-prev-item .stk-miss { width: 100%; height: auto; aspect-ratio: 1; }
.stk-prev-item span { font-size: var(--fs-11); color: var(--text-3); max-width: 100%; }

.stk-group-head { display: flex; align-items: center; justify-content: space-between; }
.stk-group-head button { color: var(--text-3); display: flex; padding: var(--sp-1); }
.stk-group-acts { display: flex; align-items: center; gap: var(--sp-1); }
.stk-edit-preview { display: flex; justify-content: center; padding: var(--sp-3) 0 var(--sp-4); }
.stk-edit-preview .stk-img, .stk-edit-preview .stk-miss { width: 96px; height: 96px; }

.icon-upload { display: flex; align-items: center; gap: var(--sp-4); }
/* .app-tile-preview（换图标那一页的预览格）搬到了 shell.css，紧跟 .app-tile：
   它和 has-image / is-bare 特异度相同，靠先后决定谁赢，必须排在它们前面 */
.icon-upload-acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* 图片与语音消息 */
.media-pending, .media-failed {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3);
}
.media-failed { flex-direction: column; align-items: flex-start; gap: 3px; }
.media-prompt { font-size: var(--fs-13); color: var(--text-2); }
.media-note { font-size: var(--fs-11); color: var(--text-3); }
/* 识别出的描述（4.594）：默认两行，点一下展开 */
.media-desc { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; cursor: pointer; max-width: 200px; }
.media-desc.is-open { display: block; }

.bubble-image { padding: 0; background: none; max-width: 200px; }
.bubble-image img {
  width: 100%; border-radius: var(--r-md); display: block;
  box-shadow: var(--shadow-1);
}

/* 一次发好几张图：摞成一叠。背后那两张**要漏出图**，所以得摊得开一点 ——
   压得太紧就只剩一道彩色的边，看不出下面还有照片。
   点这一叠换最上面那张，不必展开就能挨个看。 */
.img-stack { display: flex; align-items: center; gap: var(--sp-3); }
.msg.is-mine .img-stack { flex-direction: row-reverse; }

.stack-cards {
  position: relative; flex: none; max-width: 150px;
  cursor: pointer;
  /* 背后那两张往外探，这边留出它们的地方，免得被气泡列裁掉 */
  margin: 4px 26px 20px 0;
}
.msg.is-mine .stack-cards { margin: 4px 0 20px 26px; }

.stack-card {
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--border);
}
.stack-card:not(.is-back) {
  position: relative; z-index: 2; overflow: hidden;
  /* 图一时读不出来也不塌成零宽，页码不会浮到别的气泡上（4.370） */
  min-width: 96px; min-height: 96px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, .10), 0 1px 2px rgba(0, 0, 0, .06);
  transition: transform var(--dur-fast) var(--ease);
}
.stack-cards:active .stack-card:not(.is-back) { transform: scale(.97); }
.stack-card img { width: 100%; height: auto; display: block; }

/* --i 是从上往下数第几张。绕底边转一点，像一摞随手放下的照片。
   偏移给足：下面那张要露出小半个角，不是一条边 */
.stack-card.is-back {
  position: absolute; inset: 0; z-index: 1;
  overflow: hidden;
  transform-origin: 50% 100%;
  transform: translate(calc(var(--i) * 13px), calc(var(--i) * 9px))
             rotate(calc(var(--i) * 3.5deg));
  box-shadow: 0 3px 9px rgba(0, 0, 0, .07);
}
.msg.is-mine .stack-card.is-back {
  transform: translate(calc(var(--i) * -13px), calc(var(--i) * 9px))
             rotate(calc(var(--i) * -3.5deg));
}
.stack-card.is-back img { height: 100%; object-fit: cover; }

/* 第几张。压在右下角，告诉你这一叠还能点 */
.stack-n {
  position: absolute; z-index: 3; right: 7px; bottom: 7px;
  padding: 2px 7px; border-radius: var(--r-full);
  background: rgba(0, 0, 0, .46); color: #fff;
  font-size: var(--fs-11); line-height: 1.5;
}
:root[data-glass="on"] .stack-n { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }

.stack-more, .stack-fold {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 6px var(--sp-4);
  border: 0; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--fs-12); cursor: pointer;
}
.stack-fold {
  align-self: flex-start; margin-top: 2px;
  padding: 6px var(--sp-3);
  color: var(--text-3);
}
.msg.is-mine .stack-fold { align-self: flex-end; }
.stack-fold svg { color: var(--text-3); }

.voice-wrap { display: flex; flex-direction: column; gap: 4px; align-items: inherit; }
.bubble-voice {
  display: flex; align-items: center; gap: var(--sp-2);
  min-width: 108px; text-align: left;
}
.voice-bars { display: flex; align-items: flex-end; gap: 2px; height: 14px; }
.voice-bars i {
  width: 2px; background: currentColor; border-radius: 1px; opacity: .45;
  display: block;
}
.voice-bars i.is-on { opacity: 1; animation: voice-pulse .7s ease-in-out infinite alternate; }
.voice-bars i.is-on:nth-child(2) { animation-delay: .12s; }
.voice-bars i.is-on:nth-child(3) { animation-delay: .24s; }
.voice-bars i.is-on:nth-child(4) { animation-delay: .36s; }
@keyframes voice-pulse { from { transform: scaleY(.5); } to { transform: scaleY(1.5); } }
.voice-len { font-size: var(--fs-11); opacity: .7; }
.voice-acts { display: flex; gap: var(--sp-3); padding: 0 var(--sp-1); }
.voice-acts button { color: var(--text-3); display: flex; }
.voice-text {
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.6;
  background: var(--group-fill); border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3); max-width: 100%;
}

.mo-genning, .mo-genfail {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-2);
}

/* 批量换图标 */
.batch-acts { display: flex; gap: var(--sp-2); }
.batch-list {
  display: flex; flex-direction: column;
  border-radius: var(--r-md); overflow: hidden; background: var(--group-fill);
  margin-bottom: var(--sp-3);
}
.batch-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); text-align: left;
  border-bottom: 1px solid var(--group-line); color: var(--text-3);
}
.batch-row:last-child { border-bottom: none; }
.batch-row.is-on { color: var(--text); }
.batch-num {
  width: 20px; height: 20px; flex: none; border-radius: var(--r-full);
  font-size: var(--fs-11); display: flex; align-items: center; justify-content: center;
  background: var(--surface-3); color: var(--text-2);
}
.batch-row.is-on .batch-num { background: var(--accent); color: var(--on-accent); }
.batch-name { flex: 1; min-width: 0; font-size: var(--fs-14); }

/* 时间感知 */
.zone-now {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-13); color: var(--text-3); font-variant-numeric: tabular-nums;
}
.dt-input {
  width: 100%; box-sizing: border-box;
  padding: var(--sp-3); border: none; border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text);
  font: inherit; font-size: var(--fs-15);
}
.time-preview {
  padding: var(--sp-5) var(--sp-4); border-radius: var(--r-lg);
  background: var(--group-fill); text-align: center;
}
.time-big {
  font-size: var(--fs-56); line-height: 1.1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.time-sub { margin-top: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }
.time-note { margin-top: 3px; font-size: var(--fs-11); color: var(--text-3); }

/* 用户发的图片与语音 */
/* 用文字写的一张图（MediaBubble 的 photo-text）：顶上一行小标「图片」，下面是画面描述 */
.photo-text { max-width: 240px; }
.photo-text-head { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); opacity: .6; margin-bottom: 2px; }
.photo-text-body { white-space: pre-wrap; word-break: break-word; }
.media-wrap { display: flex; flex-direction: column; gap: 4px; align-items: inherit; }

/* 视频消息。海报 + 一个播放标记，点一下才播（长按是消息菜单，见第 12 条） */
.bubble-clip {
  position: relative; padding: 0; background: none; max-width: 200px;
  border-radius: var(--r-md); overflow: hidden; display: block;
}
.bubble-clip img, .bubble-clip video { display: block; width: 100%; height: auto; }
.clip-blank {
  width: 160px; height: 110px; background: var(--surface-3);
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.clip-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 40px; height: 40px; border-radius: var(--r-full);
  background: var(--scrim-strong); color: var(--on-scrim);
  display: flex; align-items: center; justify-content: center;
}
.clip-time {
  position: absolute; right: var(--sp-2); bottom: var(--sp-2);
  padding: 1px var(--sp-2); border-radius: var(--r-xs);
  background: var(--scrim-strong); color: var(--on-scrim); font-size: var(--fs-11);
}
.voice-tone { margin-top: 4px; color: var(--text-3); }
.voice-trans { margin-top: var(--sp-1); padding-top: var(--sp-1); border-top: 1px solid var(--border); color: var(--text-2); }

/* 录音条。和多选栏共用 .select-bar 的位置与留白 */
.rec-live {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-15); color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.rec-dot {
  width: 8px; height: 8px; border-radius: var(--r-full);
  background: var(--accent); animation: rec-blink 1s steps(1) infinite;
}
@keyframes rec-blink { 50% { opacity: .2; } }

/* 角色写了一个表情名，但库里没有对得上的。显示它想发的是哪个，
   总比悄悄吞掉一条消息强。 */
.stk-gone {
  display: inline-block; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md); background: var(--group-fill);
  font-size: var(--fs-12); color: var(--text-3);
  display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px;
}
/* 认不出时点一下自己指认。不写这一句，人只会以为是坏了 */
.stk-gone-hint { font-size: var(--fs-11); color: var(--accent); }

/* 译文收在原文气泡里。点一下展开，不单独占一条消息，也不另加按钮 */
.bubble:where(.has-trans) { cursor: pointer; }
.bubble-trans {
  margin-top: 6px; padding-top: 6px;
  border-top: 1px solid var(--group-line);
  font-size: var(--fs-13); line-height: 1.55; opacity: .72;
}
.msg.is-mine .bubble-trans { border-top-color: var(--capsule-border); }

/* 搜索结果 */
/* 单色界面里不拿颜色做高亮：周围的预览是次级灰，命中处用正文色加重，
   对比够了，深色模式下也不用另写一套 */
.hit { background: none; color: var(--text); font-weight: var(--fw-medium); }
.hit-who { color: var(--text-3); }
.search-note {
  padding: var(--sp-4); text-align: center;
  font-size: var(--fs-12); color: var(--text-3);
}
/* 按类别查找（4.315）：一排类别，选中的那个带一个叉；图片与视频排成格子 */
.search-cats { margin-bottom: var(--sp-3); }
.search-cats-title { font-size: var(--fs-12); color: var(--text-3); padding: 0 var(--sp-2) var(--sp-2); }
.search-cat-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.search-cat {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-full);
  background: var(--group-fill); color: var(--text-2); font-size: var(--fs-13);
}
.search-cat.is-on { background: var(--accent-weak); color: var(--text); }
.search-count { padding-top: 0; text-align: left; }
.search-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; }
.search-thumb {
  aspect-ratio: 1; overflow: hidden; border-radius: var(--r-sm);
  background: var(--group-fill); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}
.search-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 会话里往上翻一段；从搜索跳进来时，底下往下接一段（4.454） */
.conv-earlier, .conv-later {
  display: block; margin: 0 auto var(--sp-3); padding: var(--sp-2) var(--sp-4);
  border: none; border-radius: var(--r-full);
  background: var(--group-fill); color: var(--text-3); font-size: var(--fs-12);
}
.conv-later { margin: var(--sp-3) auto; }
.search-bar .search-hint { flex: 1; text-align: left; font-size: var(--fs-14); }
button.search-bar { width: 100%; border: none; }

/* 转账气泡。单色卡片，金额是主角，状态压在底下一行 */
.bubble-transfer {
  min-width: 168px; max-width: 232px; padding: var(--sp-3) var(--sp-4) 0;
  cursor: default;
}
.bubble-transfer .tr-top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.bubble-transfer .tr-body { min-width: 0; }
.tr-amount { font-size: var(--fs-20); font-weight: var(--fw-medium); line-height: 1.2; }
.tr-note { font-size: var(--fs-12); opacity: .7; margin-top: 2px; }
.tr-foot {
  margin: var(--sp-3) calc(var(--sp-4) * -1) 0; padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--border); font-size: var(--fs-12); opacity: .62;
}
/* 卡片里放文字的那一格（4.716，排查「礼物的内容太长会溢出卡片」的同类）：一律可以收缩。
   少了 min-width: 0，里面的 ellipsis 不生效，字把卡片撑破 —— 礼物、信、外卖、出行都漏过。写在这里，以后新加的卡片不用各写一遍 */
.tr-top > .tr-body { flex: 1; min-width: 0; }
/* 用默认气泡内边距的卡片（转发的聊天记录、转发的动态）：底下那一行左右伸出去的量跟着气泡内边距，不多伸出去 4px */
.bubble-forward .tr-foot, .bubble-moshare .tr-foot {
  margin-left: calc(var(--bubble-px) * -1); margin-right: calc(var(--bubble-px) * -1);
  padding-left: var(--bubble-px); padding-right: var(--bubble-px);
}
/* 自己这边的气泡是深底，分隔线要用亮的那一侧 */
.msg.is-mine .tr-foot { border-top-color: rgba(255, 255, 255, .22); }
.bubble-transfer:where(.is-done) { opacity: .58; }
/* 聊天里的思考（4.739）：一行浅灰小字，点开才展开。不画气泡、不加底色，读着像页边的批注 */
.think-fold { margin: 0 0 var(--sp-1); max-width: 100%; }
.think-fold-head { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-11); color: var(--text-3); padding: 0; background: none; }
.think-fold-body { margin-top: var(--sp-1); padding-left: var(--sp-2); border-left: 1px solid var(--border-2);
  font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); white-space: pre-wrap; overflow-wrap: anywhere; }
/* 群红包（4.736）：和转账同一张卡片，正文是祝福语；点开是整页，谁领了多少 */
.bubble-rp { cursor: pointer; }
.rp-note { font-size: var(--fs-15); font-weight: var(--fw-medium); line-height: 1.35; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rp-head { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); padding: var(--sp-6) var(--sp-4) var(--sp-5); text-align: center; }
.rp-head-note { font-size: var(--fs-15); color: var(--text-2); overflow-wrap: anywhere; }
.rp-head-amount { font-size: var(--fs-28); font-weight: var(--fw-medium); }
.rp-claim { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; font-size: var(--fs-14); }
.rp-best { font-size: var(--fs-11); color: var(--text-2); }

/* 提示行。不是谁说的话，居中一行灰字 */
.conv-notice {
  text-align: center; padding: var(--sp-2) var(--sp-6);
  font-size: var(--fs-12); color: var(--text-3); line-height: 1.6;
  /* 外卖、礼物名这类不带空格的一长串（英文、下划线连写）在哪儿都能断行，不顶出屏幕（4.c158-9） */
  overflow-wrap: anywhere;
}

/* 排在弹性或网格格子里的名字与数字：body 的 break-word 不改格子定宽，格子不肯缩到一个词以下，这几处单独用 anywhere 并允许缩窄
   （4.c158-10，冒烟 SMOKE_LONG=latin 查出来的：扭蛋统计、朋友圈顶上的名字、盲盒的格子与说明、编辑资料头像下的名字、年度回顾的标题） */
.gc-stats > div > span, .mo-header-name, .mz-fact > span, .mz-box-name, .avatar-picker > .char-name, .yr-head > b {
  overflow-wrap: anywhere; min-width: 0;
}

/* 录音条上的「改为输入」 */
.rec-write {
  margin-left: var(--sp-2); padding: 2px var(--sp-2);
  border: none; border-radius: var(--r-full);
  background: var(--group-fill); color: var(--text-3); font-size: var(--fs-12);
}

/* 浏览器识别那一档：录音条上方写出已识别的字（4.356） */
.rec-heard {
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-13); line-height: 1.5; color: var(--text-2);
  max-height: 120px; overflow-y: auto;
}
.rec-heard:where(.is-err) { color: var(--danger); }
/* 点了「语音」、还没开始时中间那颗键（4.357） */
.rec-start {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-4); border: none; border-radius: var(--r-full);
  background: var(--text); color: var(--bg); font-size: var(--fs-15);
}
.rec-heard-end { display: block; margin-top: 2px; color: var(--text-3); font-size: var(--fs-12); }

/* 位置气泡。虚拟定位，没有真地图，所以也不画一块假的地图底纹 */
.bubble-location {
  display: flex; align-items: center; gap: var(--sp-3);
  min-width: 168px; max-width: 244px;
}
.bubble-location .loc-body { min-width: 0; flex: 1; }
.loc-name { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.loc-addr { font-size: var(--fs-12); opacity: .66; margin-top: 2px; }
.bubble-location .loc-map {
  flex: none; width: 44px; height: 44px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--group-fill); opacity: .8;
}
.msg.is-mine .bubble-location .loc-map { background: rgba(255, 255, 255, .16); }

/* ---- 通话 ---- */
.call-layer {
  position: absolute; inset: 0; z-index: var(--z-call);
  display: flex; flex-direction: column;
  padding: calc(var(--safe-top) + var(--sp-8)) var(--sp-5)
           calc(var(--safe-bottom) + var(--sp-5));
  background: var(--bg);
}
.call-head { flex: none; display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.call-name { font-size: var(--fs-20); font-weight: var(--fw-medium); margin-top: var(--sp-2); }
.call-status { font-size: var(--fs-13); color: var(--text-3); font-variant-numeric: tabular-nums; }
.call-error { font-size: var(--fs-12); color: var(--text-2); text-align: center; }

/* 字幕。一句一句往上走，自己说的靠右 */
.call-lines { flex: 1; min-height: 0; padding: var(--sp-6) 0; }
.call-line { margin-bottom: var(--sp-4); }
.call-line.is-mine { text-align: right; }
.call-who { display: block; font-size: var(--fs-12); color: var(--text-3); margin-bottom: 2px; }
.call-text { font-size: var(--fs-17); line-height: 1.65; }
/* 视频通话里的动作（4.483）：不念，和台词分开，一行一个，浅一档、斜体，两头加括号 */
.call-say, .call-act { display: block; }
.call-act { font-size: var(--fs-14); line-height: 1.6; color: var(--text-2); font-style: italic; }
.call-act::before { content: '（'; }
.call-act::after { content: '）'; }
.call-act:empty { display: none; }
/* 画面上叠着最近那一个动作，名字与时长下面 */
.call-now-act {
  max-width: 84%; margin-top: var(--sp-1); text-align: center;
  font-size: var(--fs-14); line-height: 1.5; font-style: italic; color: var(--text-2);
  animation: fade-in var(--dur) var(--ease-out);
}
.log-act { display: block; font-size: var(--fs-13); color: var(--text-2); font-style: italic; }
.log-act::before { content: '（'; }
.log-act::after { content: '）'; }
/* 译文在原文下面另起一行。念出来的是原文，看得懂的是这一行 */
.call-trans { display: block; margin-top: 2px; font-size: var(--fs-14); line-height: 1.6; color: var(--text-2); }
/* 逐句译文（4.633）：一句原文、下面一句译文，句与句之间空一点 */
.call-seg { display: block; }
.call-seg + .call-seg { margin-top: 6px; }
.call-seg > .call-text { display: block; }

.call-heard {
  flex: none; min-height: 22px; text-align: center;
  font-size: var(--fs-13); color: var(--text-3); margin-bottom: var(--sp-3);
}
.call-input {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  background: var(--group-fill); border-radius: var(--r-full);
  padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-5);
}
.call-input input {
  flex: 1; min-width: 0; border: none; background: none; padding: 0;
  font-size: var(--fs-15); color: var(--text);
}
.call-input input:focus { border: none; }
.call-input button { flex: none; color: var(--text-2); display: flex; }
.call-input button:disabled { color: var(--text-3); opacity: .5; }

.call-bar {
  flex: none; display: flex; align-items: center; justify-content: center;
  gap: var(--sp-8);
}
.call-key {
  width: 58px; height: 58px; border-radius: var(--r-full); border: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--group-fill); color: var(--text-2);
}
/* 开着的挡位用实心填；挂断也要实心，所以靠大一号来区分主次 —— 单色界面里
   大小是比颜色更靠得住的主次信号 */
.call-key.is-on { background: var(--accent); color: var(--on-accent); }
.call-key.is-hang,
.call-key.is-take {
  width: 66px; height: 66px; background: var(--accent); color: var(--on-accent);
}
.call-foot {
  flex: none; text-align: center; margin-top: var(--sp-4);
  font-size: var(--fs-12); color: var(--text-3);
}

/* 通话记录气泡与全文 */
.bubble-call { display: flex; align-items: center; gap: var(--sp-2); }
.bubble-call:where(.is-miss) { opacity: .62; }
/* 一起听的邀请卡（4.706）：一行「邀请一起听」，下面邀的是什么、回应了没有 */
.bubble-invite { max-width: 240px; }
.invite-text { display: flex; flex-direction: column; flex: 1; min-width: 0; gap: 2px; }
.invite-what { font-size: var(--fs-13); color: var(--text-2); }
.invite-state { font-size: var(--fs-12); color: var(--text-3); }
.bubble-invite:where([data-state="withdrawn"]) { opacity: .62; }
/* 见面卡片（4.721）：底下三个选项，选过之后收起 */
.bubble-invite:where([data-state="declined"]) { opacity: .62; }
.meet-acts { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-1); padding: 0 var(--sp-1); }
.log-line { margin-bottom: var(--sp-4); }
.log-who { display: block; font-size: var(--fs-12); color: var(--text-3); margin-bottom: 2px; }
.log-text { font-size: var(--fs-15); line-height: 1.65; }
.log-line { display: grid; grid-template-columns: 1fr auto; column-gap: var(--sp-2); align-items: start; }
.log-line .log-who { grid-column: 1 / -1; }
.log-body { display: block; min-width: 0; }
.log-trans { display: block; margin-top: 2px; font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); }
.log-seg { display: block; }
.log-seg + .log-seg { margin-top: 4px; }
.log-play {
  width: 28px; height: 28px; border-radius: var(--r-full); margin-top: 2px;
  background: var(--surface-2); color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
}
/* 总结放最上面：打开记录先看到的是「这通电话说了什么」，不是第一句话 */
.log-sum {
  margin-bottom: var(--sp-5); padding: var(--sp-3);
  border-radius: var(--r-md); background: var(--surface-2);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.log-sum-text { font-size: var(--fs-14); line-height: 1.7; white-space: pre-wrap; }
.log-sum-empty { font-size: var(--fs-13); color: var(--text-3); }

/* 视频通话：对方铺满整屏，字幕压在上面，所以要一层压暗 */
.call-layer.is-video { color: var(--on-scrim); }
.call-back {
  position: absolute; inset: 0; background-size: cover; background-position: center;
}
.call-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    var(--scrim-strong) 0%, var(--scrim) 26%, var(--scrim) 58%, var(--scrim-strong) 100%);
}
/* 铺满的画面和压暗层在最底下，内容全部抬到它们上面。
   这里要一个一个点名，不能写 `> *` —— 那会把小窗的绝对定位一起盖掉，
   它就从右上角掉回文档流里去了。 */
.call-head, .call-lines, .call-heard, .call-input, .call-bar, .call-foot {
  position: relative; z-index: 1;
}
.call-layer.is-video .call-name,
.call-layer.is-video .call-status,
.call-layer.is-video .call-foot,
.call-layer.is-video .call-error { color: var(--on-scrim); }
.call-layer.is-video .call-status,
.call-layer.is-video .call-foot { opacity: .8; }
.call-lines.on-dark .call-who { color: var(--on-scrim); opacity: .7; }
.call-lines.on-dark .call-text { color: var(--on-scrim); }
.call-lines.on-dark .call-trans { color: var(--on-scrim); opacity: .75; }
.call-lines.on-dark .call-act { color: var(--on-scrim); opacity: .78; }
.call-layer.is-video .call-now-act { color: var(--on-scrim); opacity: .9; }
/* 压在画面上时全部半透明；开着的那个加一圈描边，挂断是唯一的实心，
   这样「实心=挂断」在视频里也成立 */
.call-layer.is-video .call-key { background: rgba(255, 255, 255, .2); color: var(--on-scrim); }
.call-layer.is-video .call-key.is-on {
  background: rgba(255, 255, 255, .34);
  box-shadow: inset 0 0 0 1.5px var(--scrim-fill);
}
.call-layer.is-video .call-key.is-hang,
.call-layer.is-video .call-key.is-take {
  background: var(--scrim-fill); color: var(--on-scrim-fill); box-shadow: none;
}
.call-layer.is-video .call-input { background: rgba(255, 255, 255, .22); }
.call-layer.is-video .call-input input { color: var(--on-scrim); }
.call-layer.is-video .call-input input::placeholder { color: rgba(255, 255, 255, .6); }
.call-layer.is-video .call-input button { color: var(--on-scrim); }

/* 我这边的小窗。右上角，摄像头画面按镜像显示 */
.call-self {
  position: absolute; top: calc(var(--safe-top) + var(--sp-4)); right: var(--sp-4);
  width: 96px; height: 128px; border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
}
.call-self video { width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); }

/* ---- 通话缩小（CallLayer 的 CallBall） ---- */
/* 左上角两个小按钮：缩成悬浮球、桌面悬浮窗 */
.call-tools {
  position: absolute; z-index: 2;
  top: calc(var(--safe-top) + var(--sp-4)); left: var(--sp-4);
  display: flex; gap: var(--sp-2);
}
.call-tool {
  width: 38px; height: 38px; border-radius: var(--r-full); border: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--group-fill); color: var(--text-2);
}
.call-tool.is-on { background: var(--accent); color: var(--on-accent); }
.call-layer.is-video .call-tool { background: rgba(255, 255, 255, .2); color: var(--on-scrim); }
.call-layer.is-video .call-tool.is-on { background: var(--scrim-fill); color: var(--on-scrim-fill); }

/* 缩起来时整层留着，只是看不见、点不到（摄像头取帧还要用这一层里的小窗）。
   不用 display:none —— 浏览器会把看不见的静音视频停掉，角色就看不到画面了 */
.call-layer.is-mini { opacity: 0; pointer-events: none; }

.call-ball {
  position: absolute; left: 0; top: 0; z-index: var(--z-call);
  transform: translate(var(--ball-x, 0), var(--ball-y, 0));
  transition: transform var(--dur) var(--ease);
  touch-action: none; user-select: none; -webkit-user-select: none;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-1);
  padding: var(--sp-2); border: none; border-radius: var(--r-lg);
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-2);
}
.call-ball.is-dragging { transition: none; }
.call-ball.is-placing { visibility: hidden; }
.call-ball-face { display: flex; border-radius: var(--r-full); }
/* 对方正在说：头像外面一圈描边，一明一暗 */
.call-ball.is-talking .call-ball-face { animation: call-ball-talk 1.2s var(--ease) infinite; }
@keyframes call-ball-talk {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent); }
  50% { box-shadow: 0 0 0 3px var(--accent); }
}
.call-ball-scene {
  display: block; width: 84px; height: 112px; border-radius: var(--r-md);
  background-size: cover; background-position: center;
}
.call-ball.is-video.is-talking .call-ball-scene { animation: call-ball-talk 1.2s var(--ease) infinite; }
.call-ball-time {
  font-size: var(--fs-12); color: var(--text-2); font-variant-numeric: tabular-nums;
}

/* 画中画的画面来源：一段藏起来的视频，只给系统拿去弹成小窗（system/callfloat.js） */
.pip-source {
  position: fixed; left: 0; top: 0; width: 2px; height: 2px;
  opacity: 0; pointer-events: none;
}

/* 角色卡上的视频画面预览 */
.call-scene-preview {
  margin-top: var(--sp-3); height: 140px; border-radius: var(--r-md);
  background-size: cover; background-position: center;
}

/* 礼物气泡。拆开之前只有封面那一行 */
.bubble-gift { min-width: 168px; max-width: 232px; padding: var(--sp-3) var(--sp-4) 0; }
.bubble-gift .tr-top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
/* 写得长的礼物（4.715，用户：「礼物的内容太长会溢出卡片」）：从前一行加省略号，可放文字那一格没写 min-width: 0，
   省略号不生效，字把卡片撑破。现在各收成两行（再长卡片也不变大），点卡片看全文；底下那一行放不下就折到下一行 */
.bubble-gift .tr-body { flex: 1; min-width: 0; }
.gift-cover, .gift-inner { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.gift-cover { font-size: var(--fs-17); font-weight: var(--fw-medium); line-height: 1.4; }
.gift-inner { font-size: var(--fs-12); opacity: .7; margin-top: 2px; line-height: 1.5; }
.gift-full-cover { font-size: var(--fs-16); line-height: 1.7; overflow-wrap: anywhere; white-space: pre-wrap; }
.gift-full-inner { margin-top: var(--sp-3); font-size: var(--fs-14); color: var(--text-2); line-height: 1.7; overflow-wrap: anywhere; white-space: pre-wrap; }
.bubble-gift .tr-foot { display: flex; flex-wrap: wrap; align-items: center; row-gap: 2px; }
.bubble-gift:where(.is-done) { opacity: .62; }
.face-preview {
  margin-top: var(--sp-3); height: 120px; width: 120px; border-radius: var(--r-md);
  background-size: cover; background-position: center;
}

/* 会话顶上那几条（一起听、一起看、节奏）浮在消息列表上，消息从底下滚过去。
   列表顶上留出同样高的一段（--strips-h，会话页量出来挂上），最早那几条不被压住 */
.conv-strips {
  position: absolute; top: 0; left: 0; right: 0; z-index: 2;
  display: flex; flex-direction: column; padding-top: var(--sp-2);
  pointer-events: none;
}
.conv-strips > * { pointer-events: auto; }
.conv-strips:empty { padding-top: 0; }
:where(.conv-main) > .conv-body { padding-top: calc(var(--sp-4) + var(--strips-h, 0px)); }

/* 一起听的播放条。压在会话顶上，不占页面 —— 听歌是背景，聊天还是主角 */
.listen-bar {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--group-fill); border-radius: var(--r-md);
  margin: 0 var(--sp-4) var(--sp-2);
  box-shadow: var(--shadow-2);
}
.listen-main { flex: 1; min-width: 0; }
.listen-title { font-size: var(--fs-13); font-weight: var(--fw-medium); }
.listen-sub { font-size: var(--fs-12); color: var(--text-3); margin-top: 1px; }
.listen-key {
  flex: none; width: 28px; height: 28px; border: none; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--text-2);
}
.row-acts { display: inline-flex; gap: var(--sp-3); }
/* 一排放不下（320 宽时视频那一行有五个）就折到第二行、靠右，按钮不被挤扁、字不顶出去（4.c158-10） */
.row-acts { flex-wrap: wrap; justify-content: flex-end; row-gap: 0; }
.row-acts > .nav-text { flex: none; white-space: nowrap; }

/* ---- 情侣空间 ---- */
.sp-row {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: var(--sp-3) var(--sp-4); text-align: left;
  border-bottom: 1px solid var(--border);
}
.sp-row:last-child { border-bottom: none; }
.sp-row-body { flex: 1; min-width: 0; }
.sp-row-name { font-size: var(--fs-17); font-weight: var(--fw-medium); }
.sp-row-sub { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }

.sp-head { padding: var(--sp-6) var(--sp-4) var(--sp-4); text-align: center; }
.sp-faces {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-4);
  color: var(--text-3);
}
.sp-days {
  display: block; margin: var(--sp-4) auto 0; padding: var(--sp-2) var(--sp-5);
  border-radius: var(--r-full); background: var(--group-fill); color: var(--text-2);
}
.sp-days b {
  display: block; font-size: var(--fs-24); font-weight: var(--fw-semi);
  color: var(--text); line-height: 1.2; font-variant-numeric: tabular-nums;
}
.sp-days span { font-size: var(--fs-12); }

.sp-thumb {
  width: 32px; height: 32px; border-radius: var(--r-xs);
  object-fit: cover; background: var(--surface-2);
}
.sp-letter {
  white-space: pre-wrap; line-height: 1.8; font-size: var(--fs-15);
  padding: var(--sp-4); border-radius: var(--r-md); background: var(--group-fill);
}
/* 信的译文（4.365）：正文下面，一条细线隔开 */
/* 日记的译文（4.365）：正文下面，一条细线隔开 */
/* 角色手机里生成内容的译文（4.365） */
.tp-trans { display: block; margin-top: var(--sp-1); padding-top: var(--sp-1); border-top: 1px solid var(--group-line); font-size: var(--fs-12); opacity: .72; }
.tp-shot-trans { display: block; font-size: var(--fs-11); color: var(--text-3); }
.li-trans { margin-top: 2px; color: var(--text-3); white-space: pre-wrap; }
.dy-trans { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: var(--fs-14); line-height: 1.8; color: var(--text-2); white-space: pre-wrap; word-break: break-word; }
.sp-letter-trans { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: var(--fs-14); line-height: 1.8; color: var(--text-2); white-space: pre-wrap; word-break: break-word; }

/* 约定与信的气泡。和转账、礼物同一套骨架 */
.bubble-pact, .bubble-letter {
  min-width: 168px; max-width: 232px; padding: var(--sp-3) var(--sp-4) 0;
}
.bubble-pact .tr-top, .bubble-letter .tr-top {
  display: flex; align-items: center; gap: var(--sp-3); min-width: 0;
}
.pact-title { font-size: var(--fs-15); font-weight: var(--fw-medium); line-height: 1.45; }
.letter-title { font-size: var(--fs-17); font-weight: var(--fw-medium); }
.bubble-pact.is-done { opacity: .62; }
.bubble-pact.is-done .pact-title { text-decoration: line-through; }

/* ---- 随机事件库的九宫格 ---- */
.ev-grid {
  display: grid; grid-template-columns: auto repeat(3, 1fr);
  gap: var(--sp-2); align-items: stretch; margin-bottom: var(--sp-4);
}
.ev-head {
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-12); color: var(--text-3); padding: var(--sp-1) 0;
}
.ev-head.is-row { justify-content: flex-end; padding-right: var(--sp-2); }
.ev-cell {
  padding: var(--sp-4) 0; border-radius: var(--r-md);
  background: var(--group-fill); color: var(--text);
}
.ev-cell b { font-size: var(--fs-20); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.ev-cell.is-empty { color: var(--text-3); }
.ev-input { display: flex; flex-direction: column; gap: 2px; }
.ev-have { font-size: var(--fs-11); color: var(--text-3); text-align: center; }

/* 取消掉的事项：留在那儿，但一眼看得出不作数了 */
.list-item.is-dropped .li-title { text-decoration: line-through; color: var(--text-3); }

/* ---- 关系小件 ---- */
/* 头像是可点的：单击看心声，双击拍一拍。所以要禁掉系统的选中浮层 */
.msg-face { flex: none; cursor: pointer; }
/* 头像下方那一行对方的时间（4.614） */
.msg-zone { margin-top: 3px; font-size: var(--fs-11); line-height: 1.2; color: var(--text-3); text-align: center; font-variant-numeric: tabular-nums; }
/* 顶栏名字下方、名字右侧的对方时间 */
.conv-zone { font-size: var(--fs-11); font-weight: var(--fw-regular); color: var(--text-3); font-variant-numeric: tabular-nums; letter-spacing: 0; }
.conv-zone:where(.is-below) { display: block; margin-top: 1px; line-height: 1.25; }
.conv-zone:where(.is-side) { margin-left: 6px; font-size: var(--fs-12); }

.bubble-dice {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 72px; padding: var(--sp-3) var(--sp-4);
}
.dice-num {
  font-size: var(--fs-24); font-weight: var(--fw-semi); line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.dice-face { font-size: var(--fs-11); opacity: .6; }

.inner-voice { margin-top: var(--sp-2); line-height: 1.6; }
/* 心声卡片（4.634）：用户自己的模板，框在气泡下面；打开那一页里占满卡片宽度 */
.inner-tpl { margin-top: var(--sp-2); }
.inner-tpl.is-fluid { margin: 0 0 var(--sp-3); }
.inner-tpl-preview { margin-top: var(--sp-2); }
/* 心声、旁白的译文（4.362）：原文下面一行淡字 */
.inner-trans, .narration-trans { margin-top: 2px; font-size: var(--fs-12); opacity: .72; }
.inner-quiet {
  font-size: var(--fs-12); color: var(--text-3); padding: 0 var(--sp-1);
}
/* 会话「心声」里设的样式（4.398）走 --ph-inner-*，没设的照上面 */
.ph-inner {
  font-size: var(--ph-inner-fs, var(--fs-12)); color: var(--ph-inner-fg, var(--text-3));
  background: var(--ph-inner-bg, transparent); border-radius: var(--ph-inner-r, 0);
  border: var(--ph-inner-bw, 0) solid var(--ph-inner-bc, transparent);
}
.inner-card {
  font-size: var(--fs-13); color: var(--text-2);
  padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--group-fill);
}
:where(.msg.is-mine) .inner-quiet, :where(.msg.is-mine) .inner-card { text-align: right; }

.pool-thumb {
  width: 32px; height: 32px; border-radius: var(--r-full);
  object-fit: cover; background: var(--surface-2);
}
.msg-star { flex: none; color: var(--accent); }

/* ---- 点外卖 ---- */
.bubble-meal { min-width: 168px; max-width: 244px; padding: var(--sp-3) var(--sp-4) 0; }
.bubble-meal .tr-top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.meal-item { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.meal-price { font-size: var(--fs-12); opacity: .7; margin-top: 2px; }
.bubble-meal.is-done { opacity: .6; }

/* 会话顶上那一行状态：自动回复开着，或者正在等她回 */

/* 请求记录。一段可折叠的原文，等宽字体按原样显示，不换行折断单词 */
.trace-block { margin-bottom: var(--sp-3); }
.trace-head {
  width: 100%; display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text-1);
  font-size: var(--fs-13); text-align: left; cursor: pointer;
}
.trace-head > span:first-child { flex: 1; min-width: 0; }
.trace-size { color: var(--text-3); font-size: var(--fs-11); }
.trace-body {
  margin: var(--sp-2) 0 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-2); border-radius: var(--r-md);
  color: var(--text-2); font-size: var(--fs-12); line-height: 1.6;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: pre-wrap; word-break: break-word;
  /* 这一段是拿来读和复制的，放开选中 */
  -webkit-user-select: text; user-select: text; -webkit-touch-callout: default;
  /* 不用 vh：视口单位只许出现在外壳那三层（CLAUDE.md 第 1 条） */
  max-height: 420px; overflow: auto;
}

/* 音乐：三个页签 + 底部那条 */
/* 撑满一屏，底部那条才贴得住（sticky 只在内容够长时才吸底） */
.mu-page { min-height: 100%; }
.mu-wait { display: flex; justify-content: center; padding: var(--sp-8) 0; }

.mu-sec {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-5) var(--sp-4) var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3);
}

.mu-cover { display: block; object-fit: cover; background: var(--group-fill); flex: none; }
.mu-cover-empty {
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: var(--fs-17); font-weight: var(--fw-medium);
}

/* 最近播放：横着推 */
.mu-strip {
  display: flex; gap: var(--sp-3); overflow-x: auto;
  padding: 0 var(--sp-4) var(--sp-2);
  scrollbar-width: none;
}
.mu-strip::-webkit-scrollbar { display: none; }
.mu-card { width: 104px; flex: none; text-align: left; }
.mu-card:active { opacity: .72; }
.mu-card-name { margin-top: var(--sp-2); font-size: var(--fs-13); font-weight: var(--fw-medium); }
.mu-card-sub { font-size: var(--fs-11); color: var(--text-3); }

/* 一行一首 */
.mu-list { padding: 0 var(--sp-2); }
.mu-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
}
.mu-row.is-on .mu-title { color: var(--accent); }
.mu-idx {
  width: 26px; flex: none; text-align: center;
  font-size: var(--fs-13); color: var(--text-3); font-variant-numeric: tabular-nums;
}
.mu-main { flex: 1; min-width: 0; }
.mu-title { font-size: var(--fs-14); }
.mu-sub { margin-top: 1px; font-size: var(--fs-12); color: var(--text-3); }
.mu-keep {
  flex: none; width: 32px; height: 32px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.mu-count {
  flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
  font-size: var(--fs-11); color: var(--text-3); font-variant-numeric: tabular-nums;
}
.mu-count i { display: block; height: 3px; border-radius: var(--r-full); background: var(--accent-weak); }

/* 我的 */
.mu-me { padding: var(--sp-6) var(--sp-4) var(--sp-4); text-align: center; }
.mu-me-face { display: flex; justify-content: center; }
.mu-me-name { margin-top: var(--sp-3); font-size: var(--fs-17); font-weight: var(--fw-semi); }
.mu-me-sign { margin-top: 2px; font-size: var(--fs-12); color: var(--text-3); }
.mu-me-meta { margin-top: var(--sp-2); font-size: var(--fs-11); color: var(--text-3); }
.mu-stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  padding: 0 var(--sp-4) var(--sp-2); text-align: center;
}
.mu-stat b { display: block; font-size: var(--fs-17); font-weight: var(--fw-semi); }
.mu-stat span { font-size: var(--fs-11); color: var(--text-3); }
.mu-total {
  padding: var(--sp-3) var(--sp-4) 0;
  font-size: var(--fs-13); color: var(--text-2);
}
.mu-total-note { margin-top: 2px; font-size: var(--fs-11); color: var(--text-3); }

/* 歌单页头 */
.mu-head { display: flex; gap: var(--sp-4); align-items: center; padding: var(--sp-4); }
/* 搜索页顶上「网易云 / QQ 音乐」（4.609）；QQ 歌单页的两个按钮 */
.mu-src { padding-top: var(--sp-2); padding-bottom: var(--sp-1); }
.mu-head-acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.mu-head-n { font-size: var(--fs-13); color: var(--text-3); margin-bottom: var(--sp-2); }

/* 底部那条 */
.mu-bar {
  position: sticky; bottom: 0; z-index: 2;
  background: var(--surface); border-top: 1px solid var(--border);
}
.mu-bar-line { height: 2px; background: var(--border); position: relative; }
/* 条子只有两像素，手指点不准。伪元素把上下各撑出一截当热区，不影响外观 */
.mu-bar-line::after { content: ""; position: absolute; inset: -9px 0; }
.mu-bar-line i { display: block; height: 100%; background: var(--accent); }
.mu-bar-safe .mu-bar-body { padding-bottom: calc(var(--sp-2) + var(--safe-bottom)); }
.mu-bar-body {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
}
.mu-ctl {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center; color: var(--text);
}
.mu-ctl:active { opacity: .6; }

/* ---- 正在播放（apps/music/NowPage.js）---- */
.mu-bar-body { cursor: pointer; }
.mu-now {
  height: 100%; display: flex; flex-direction: column; min-height: 0;
  padding: 0 var(--sp-5) calc(var(--sp-4) + var(--safe-bottom));
}
.mu-now-artist { text-align: center; font-size: var(--fs-13); color: var(--text-2); margin-bottom: var(--sp-3); }
.mu-now-face {
  flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-4); background: none; border: 0; padding: 0; color: inherit; cursor: pointer;
}
.mu-now-face .mu-cover { box-shadow: var(--shadow-2); }
.mu-now-line { font-size: var(--fs-15); text-align: center; line-height: 1.5; min-height: 1.5em; padding: 0 var(--sp-2); }
.mu-now-line-t { font-size: var(--fs-13); color: var(--text-2); text-align: center; margin-top: calc(var(--sp-3) * -1); }
/* 歌词那一面。上下各留半屏空白，第一句和最后一句也能滚到正中 */
/* 只许上下滚（4.507）：正在唱的那句放大 4%，长句放大后比屏幕宽，从前横向也能滚，手指一斜歌词就左右晃 */
.mu-lyrics { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; touch-action: pan-y; overscroll-behavior-x: none;
  padding-inline: var(--sp-3); /* 放大 4% 的那句左右各探出 2%，留在这圈内边距里，不再撑出横向滚动 */
  -webkit-overflow-scrolling: touch; text-align: center;
  mask-image: linear-gradient(transparent, var(--text) 12%, var(--text) 88%, transparent);
  -webkit-mask-image: linear-gradient(transparent, var(--text) 12%, var(--text) 88%, transparent); }
.mu-lyrics-pad { height: 42%; }
.mu-ly {
  margin: 0; padding: var(--sp-2) var(--sp-2); font-size: var(--fs-15); line-height: 1.55;
  color: var(--text-3); cursor: pointer; transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.mu-ly.is-on { color: var(--text); font-weight: var(--fw-semi); transform: scale(1.04); }
.mu-ly-t { display: block; font-size: var(--fs-12); font-weight: normal; margin-top: 2px; }
.mu-lyrics-empty { height: 100%; display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: var(--fs-14); padding: 0 var(--sp-5); line-height: 1.6; }
.mu-trans-btn { color: var(--text-3); }
.mu-trans-btn.is-on { color: var(--text); }
.mu-now-ctl { flex: none; padding-top: var(--sp-4); }
.mu-now-seek { display: flex; align-items: center; gap: var(--sp-3); }
.mu-now-t { flex: none; width: 3em; font-size: var(--fs-12); color: var(--text-3); font-variant-numeric: tabular-nums; }
.mu-now-t:last-child { text-align: right; }
.mu-range {
  flex: 1; min-width: 0; height: 20px; margin: 0; background: transparent;
  -webkit-appearance: none; appearance: none; cursor: pointer;
}
.mu-range::-webkit-slider-runnable-track {
  height: 3px; border-radius: var(--r-full);
  background: linear-gradient(to right, var(--text) var(--pct, 0%), var(--border) var(--pct, 0%));
}
.mu-range::-moz-range-track { height: 3px; border-radius: var(--r-full); background: var(--border); }
.mu-range::-moz-range-progress { height: 3px; border-radius: var(--r-full); background: var(--text); }
.mu-range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 12px; height: 12px; margin-top: -4.5px;
  border-radius: var(--r-full); background: var(--text); border: 0;
}
.mu-range::-moz-range-thumb { width: 12px; height: 12px; border-radius: var(--r-full); background: var(--text); border: 0; }
.mu-now-err { margin-top: var(--sp-2); text-align: center; font-size: var(--fs-12); color: var(--danger); }
/* 五格：播放方式、上一首、播放、下一首、右边一个同宽的空位（4.507）。从前左边多了播放方式键、右边没有，播放键被挤偏 */
.mu-now-btns { display: grid; grid-template-columns: 40px 48px 64px 48px 40px; align-items: center; justify-content: center;
  justify-items: center; column-gap: var(--sp-6); margin-top: var(--sp-3); }
.mu-now-spacer { width: 40px; height: 40px; }
.mu-now-btn {
  width: 48px; height: 48px; border-radius: var(--r-full); background: none; border: 0;
  display: flex; align-items: center; justify-content: center; color: var(--text);
}
.mu-now-main { width: 64px; height: 64px; background: var(--text); color: var(--bg); }
/* 播放方式那个键（4.470）：小一号、淡一点，排在上一首左边 */
.mu-now-mode { width: 40px; height: 40px; color: var(--text-2); }

/* 片库：转换进度 */
.vd-work { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; }
.vd-work-line { flex: 1; height: 3px; border-radius: var(--r-full); background: var(--border); }
.vd-work-line i { display: block; height: 100%; border-radius: var(--r-full); background: var(--accent); }
.vd-work span { font-size: var(--fs-12); color: var(--text-3); white-space: nowrap; }

/* 一起看 */
.wt { height: 100%; display: flex; flex-direction: column; }
/* 画面这一块按 16:9 留位置。**不能用 vh**（第 1 条），
   aspect-ratio 靠宽度算高度，结果一样而且不跟着地址栏抽动。 */
.wt-stage { position: relative; flex: none; background: var(--stage-bg); aspect-ratio: 16 / 9; }
.wt-video { display: block; width: 100%; height: 100%; object-fit: contain; }
/* 字幕与互动层收在同一个纵向栈里 —— 各自 absolute 会叠在一起，
   互动层打开时字幕正好压在输入框上。 */
.wt-bottom {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding-bottom: var(--sp-2);
}
.wt-cue {
  padding: 0 var(--sp-4);
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  color: var(--on-scrim); font-size: var(--fs-13);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
}
/* 放不出来的原因（4.897）：和台词同一处，颜色淡一档，与台词分开 */
.wt-err {
  padding: 0 var(--sp-4);
  display: flex; align-items: center; justify-content: center;
  color: var(--on-scrim); opacity: .75; font-size: var(--fs-12);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
}
/* 台词旁边那个段评气泡。压在画面上，所以描边要够亮 */
.wt-cue .rd-dot {
  margin-top: 0; opacity: .8;
  border-color: var(--on-scrim); color: var(--on-scrim);
}
.wt-cue .rd-dot.has-n {
  opacity: 1; background: var(--on-scrim);
  color: var(--stage-bg); border-color: var(--on-scrim);
}

/* ---- 影片全屏横屏 ----
   片子是 16:9 的，竖着全屏等于白全屏，所以全屏默认把画面这一层转过来。

   **用容器查询单位 cqw / cqh，不是视口单位。** 它们认的是容器自己的盒子，
   地址栏一收一放动不了它们，也就不碰第 1 条要求整齐划一的那串外壳 ——
   那一条要防的正是这种抽动，这里连量都不用量。

   手机本来就横着拿的时候不要再转一次。系统方向锁成功时也走这一条：
   锁成之后视口自己就是横的，这个 @media 不成立，CSS 这层自动让开。 */
.wt-rot { position: absolute; inset: 0; }
.wt.is-full .wt-stage { container-type: size; }

@media (orientation: portrait) {
  .wt.is-full.is-rot-l .wt-rot,
  .wt.is-full.is-rot-r .wt-rot {
    inset: auto; top: 50%; left: 50%;
    width: 100cqh; height: 100cqw;
  }
  /* 手机向左转（左边朝下）时，画面要顺时针补回来 */
  .wt.is-full.is-rot-l .wt-rot { transform: translate(-50%, -50%) rotate(90deg); }
  .wt.is-full.is-rot-r .wt-rot { transform: translate(-50%, -50%) rotate(-90deg); }
}

/* ---- 一起看的弹幕（4.889） ----
   全屏时新来的消息从右往左飘过画面上部。五条轨道（--dm-lane 由页面给 0 到 4），一条一行不折。
   用 left 从 100% 走到 0 再退一个自身宽度：百分比认的是弹幕层自己的盒子，画面转成横屏时也对（cqw 认的是没转之前的那个盒子）。
   不挡点击：整层 pointer-events: none，点画面照旧叫出控制条 */
.wt-dm { position: absolute; left: 0; right: 0; top: 0; height: 62%; overflow: hidden; pointer-events: none; }
.wt-dm-item {
  position: absolute; left: 100%; top: calc(var(--sp-3) + var(--dm-lane, 0) * 1.9em);
  white-space: nowrap; font-size: var(--fs-15); line-height: 1.5; color: var(--on-scrim);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
  animation: wt-dm 9s linear forwards;
}
/* 自己发的那一条带一圈细框，和 B 站一样认得出 */
.wt-dm-item.is-me { padding: 0 var(--sp-2); border: 1px solid var(--on-scrim); border-radius: var(--r-full); }
.wt-dm-typing {
  position: absolute; left: var(--sp-3); top: var(--sp-3);
  font-size: var(--fs-12); color: var(--on-scrim); opacity: .75; text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}
@keyframes wt-dm { from { left: 100%; transform: translateX(0); } to { left: 0; transform: translateX(-100%); } }
@keyframes wt-dm-fade { 0% { opacity: 0; } 10%, 85% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .wt-dm-item { left: var(--sp-3); animation: wt-dm-fade 5s linear forwards; }
}
.wt-panel-bar .wt-dm-btn:not(.is-on) { opacity: .45; }

/* 正用着的那个方向键点亮 */
.wt-panel-bar .mu-ctl.is-on { color: var(--accent); }

/* ---- 影片全屏 ----
   画面吃掉剩下的全部高度。**不用 vh**（第 1 条）：.wt 本来就是 height:100%
   的 flex 列，这里把 aspect-ratio 撤掉改 flex:1 就够，不必自己量高度。 */
.wt.is-full > :not(.wt-stage) { display: none; }
.wt.is-full .wt-stage { flex: 1; aspect-ratio: auto; min-height: 0; }

.wt-exit {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 34px; height: 34px; border: 0; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .45); color: var(--on-scrim);
}

/* 全屏里点一下画面叫出来的互动层。压在画面底部，不挡字幕上方的内容 */
.wt-panel {
  padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + env(safe-area-inset-bottom));
  margin-bottom: calc(-1 * var(--sp-2));
  background: linear-gradient(to top, rgba(0, 0, 0, .6), rgba(0, 0, 0, 0));
  display: flex; flex-direction: column; gap: var(--sp-1);
}
.wt-panel-bar {
  display: flex; align-items: center; gap: var(--sp-3);
  color: var(--on-scrim);
}
.wt-panel-bar .mu-ctl { color: var(--on-scrim); }
.wt-panel-bar .wt-time { color: var(--on-scrim); margin-left: auto; }
.wt-panel-msgs {
  display: flex; flex-direction: column; gap: var(--sp-2);
  max-height: 9em; overflow-y: auto;
}
.wt-panel .wt-msg { color: var(--on-scrim); background: rgba(255, 255, 255, .14); }
.wt-panel .wt-notice { color: var(--on-scrim); opacity: .75; }
.wt-panel .wt-input { border-top: 0; padding: 0; background: none; }
.wt-panel .wt-input input {
  background: rgba(255, 255, 255, .14); color: var(--on-scrim);
}
/* 全屏里的输入框只占一窄条（4.889，用户：「输入的占位置也小一点」） */
.wt-panel .wt-input input { height: 30px; font-size: var(--fs-13); }
.wt-panel .wt-input .mu-ctl { width: 30px; height: 30px; }
.wt-bar {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border);
}
.wt-line { flex: 1; height: 3px; border-radius: var(--r-full); background: var(--border); position: relative; }
.wt-line::after { content: ""; position: absolute; inset: -10px 0; }
.wt-line i { display: block; height: 100%; border-radius: var(--r-full); background: var(--accent); }
.wt-time { font-size: var(--fs-12); color: var(--text-3); font-variant-numeric: tabular-nums; }
/* 字幕对轴那一条。只在有字幕时出现 */
.wt-sync {
  flex: none; display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-4) var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3);
  border-bottom: 1px solid var(--border);
}
.wt-sync button { color: var(--accent); padding: var(--sp-1) 0; }
.wt-sync button:active { opacity: .6; }
.wt-sync b { font-weight: var(--fw-medium); color: var(--text-2); font-variant-numeric: tabular-nums; }
/* 一起看的方式与回复那一行（4.932）。样子与对轴条相同，类名分开：对轴条只在有字幕时出现，这一行一直在 */
.wt-mode {
  flex: none; display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-12); color: var(--text-3);
  border-top: 1px solid var(--border);
}
.wt-mode button { color: var(--accent); padding: var(--sp-1) 0; }
.wt-mode button:active { opacity: .6; }

.wt-msgs {
  flex: 1; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
}
/* 话贴着下边，和聊天一样。用 margin-top:auto 而不是 justify-content:flex-end ——
   后者在内容超出时，上面那几条会滚不到。 */
.wt-msgs > :first-child { margin-top: auto; }
.wt-msg {
  max-width: 78%; align-self: flex-start;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface-2); font-size: var(--fs-14);
  white-space: pre-wrap; word-break: break-word;
}
.wt-msg.is-me { align-self: flex-end; background: var(--accent); color: var(--on-accent); }
.wt-notice { color: var(--text-3); font-size: var(--fs-12); }
.wt-msg.is-me .wt-notice { color: var(--on-accent); }
.wt-input {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + var(--safe-bottom));
  border-top: 1px solid var(--border);
}
.wt-input input {
  flex: 1; min-width: 0; height: 38px; padding: 0 var(--sp-3);
  border-radius: var(--r-full); background: var(--surface-2);
  font-size: var(--fs-14); color: var(--text);
}

/* ---- 记账 ----
   全套黑白，进账出账只靠正负号和字重分，不引入颜色相（第 4 条）。 */
.bl-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-4);
}
.bl-card-head { font-size: var(--fs-13); color: var(--text-3); margin-bottom: var(--sp-3); }
.bl-card-row { display: flex; gap: var(--sp-6); }
/* 支出与收入各占一半（4.767）。用户：「支出太多了然后完全看不见收入的字了」：两栏都不许缩，支出的数一长就把收入挤出卡片。
   现在两栏等宽、可以缩，数太长时在栏里折行，不再挤掉另一边 */
.bl-card-row > div { display: flex; flex-direction: column; gap: var(--sp-1); flex: 1 1 0; min-width: 0; }
.bl-card-row .bl-money.bl-lg { overflow-wrap: anywhere; line-height: 1.15; }
.bl-lab { font-size: var(--fs-12); color: var(--text-3); }
.bl-card-foot {
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--fs-12); color: var(--text-3);
}

.bl-money { font-variant-numeric: tabular-nums; color: var(--text); }
.bl-money.bl-lg { font-size: var(--fs-24); }
/* 进账写得轻一些：一列账单里，扎眼的应该是花出去的那些 */
.bl-money.bl-in { color: var(--text-2); font-weight: 400; }

.bl-list { padding-bottom: var(--safe-bottom); }
.bl-day {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: var(--sp-5) var(--sp-4) var(--sp-2);
  font-size: var(--fs-12); color: var(--text-3);
}
.bl-day-sum { font-variant-numeric: tabular-nums; }
.bl-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.bl-cat {
  flex: none; width: 44px; height: 44px; border-radius: var(--r-md);
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-12);
}
.bl-main { flex: 1; min-width: 0; }
.bl-title { font-size: var(--fs-15); color: var(--text); }
.bl-sub { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
/* 申请气泡的标题比金额短，不必用金额那个字号 */
.bl-req-title { font-size: var(--fs-15); }
.bl-pend { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); }
.bl-pend-act { display: flex; gap: var(--sp-2); }

/* ---- 书 ---- */

.rd { display: flex; flex-direction: column; height: 100%; }
.rd-body { flex: 1; padding: var(--sp-4) var(--sp-5) var(--sp-5); }
.rd-chapter {
  font-size: var(--fs-13); color: var(--text-3);
  padding-bottom: var(--sp-3); margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.rd-p {
  margin: 0 0 var(--sp-4); text-indent: 2em;
  font-size: var(--fs-17); line-height: 1.9; color: var(--text);
}
.rd-bar {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border); background: var(--surface);
}
.rd-meta { text-align: center; display: flex; flex-direction: column; gap: 2px; }
.rd-meta > span:first-child { font-size: var(--fs-14); font-weight: var(--fw-semi); }
.rd-sub { font-size: var(--fs-11); color: var(--text-3); }

/* 一起读时她说的那几句。压在正文和翻页条之间，不遮正文 */
.rd-say {
  flex: none; max-height: 9em; overflow-y: auto;
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border); background: var(--surface-2);
}
.rd-say-who { font-size: var(--fs-11); color: var(--text-3); margin-bottom: 4px; }
.rd-say-line {
  font-size: var(--fs-14); line-height: 1.7; color: var(--text);
  margin-bottom: var(--sp-2);
}
.rd-say-line:last-child { margin-bottom: 0; }

/* ---- 封面 ---- */
.cv {
  flex: none; width: 100%; aspect-ratio: 2 / 3;
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface-2);
  /* 白封面压在白列表上，靠发丝线与阴影站住，不靠灰底 */
  box-shadow: 0 0 0 1px var(--border-2), var(--shadow-1);
}
.cv-mini { width: 30px; border-radius: var(--r-xs); }
.cv-photo { width: 100%; height: 100%; background-size: cover; background-position: center; }
.cv-drawn { display: block; width: 100%; height: 100%; }

.cv-ground { fill: var(--cv-bg); }
.cv-frame  { fill: none; stroke: var(--cv-ink); stroke-width: .4; opacity: .45; }
.cv-title  { fill: var(--cv-ink); font-family: var(--font-serif); }
.cv-rule   { stroke: var(--cv-ink); stroke-width: .6; opacity: .55; }
.cv-author { fill: var(--cv-ink); font-family: var(--font-serif); opacity: .62; }

/* 黑白两版。底色与墨色直接取 --surface / --text，
   暗色模式下这两个本来就是对调的，不必另写一套 */
.cv-t1 { --cv-bg: var(--surface); --cv-ink: var(--text); }
.cv-t2 { --cv-bg: var(--text);    --cv-ink: var(--surface); }

/* ---- 角色的书架 ---- */
/* minmax(0,1fr) 而不是 1fr：1fr 的下限是 auto，书名又带 .ellipsis（nowrap），
   于是一本长书名的最小内容宽就把自己那一格撑开，旁边两格被压到看不见。
   同样的道理，格子里每一层都要 min-width:0，否则下限照样往上顶。 */
.shelf-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-4); padding: var(--sp-4) var(--sp-5);
}
.shelf-item {
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
  background: none; border: 0; padding: 0; text-align: left;
}
.shelf-item > * { min-width: 0; max-width: 100%; }
.shelf-item.is-ghost .cv { opacity: .62; }
.shelf-name { font-size: var(--fs-13); color: var(--text); }
.shelf-sub { font-size: var(--fs-11); color: var(--text-3); }


/* 影评与书评 */
.rv-when { font-size: var(--fs-12); color: var(--text-3); padding: var(--sp-2) 0 var(--sp-3); }
.rv-p {
  margin: 0 0 var(--sp-4); text-indent: 2em;
  font-size: var(--fs-15); line-height: 1.85; color: var(--text);
}

/* ---- 一起看：顶部那两个大切换 ---- */
/* 比 .segmented 高一档，也更靠上 —— 它是这一页的主导航，不是一个表单控件 */
.top-switch {
  display: flex; gap: 2px; padding: 3px; margin: 0 var(--sp-5) var(--sp-3);
  background: var(--surface-2); border-radius: var(--r-md);
}
.top-switch-item {
  flex: 1; height: 38px; border-radius: var(--r-sm);
  font-size: var(--fs-15); font-weight: var(--fw-medium);
  color: var(--text-2); background: none; border: 0;
  transition: all var(--dur-fast) var(--ease);
}
.top-switch-item.is-active {
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-1);
}

/* ---- 阅读器外观 ----
   纸色、字号、字体走 --rd-* 变量，由 system/reader.js 按用户设置生成。
   它们只作用在 .rd 里面，不碰 app 的主题。 */
.rd {
  --rd-bg: var(--surface);
  --rd-ink: var(--text);
  --rd-fs: var(--fs-17);
  --rd-lh: 1.9;
  --rd-font: var(--font-serif);
  background: var(--rd-bg);
  background-image: var(--rd-bg-image, none);
  background-size: cover; background-position: center;
}
.rd-paper-paper { --rd-bg: var(--rd-paper-bg); --rd-ink: var(--rd-paper-ink); }
.rd-paper-sepia { --rd-bg: var(--rd-sepia-bg); --rd-ink: var(--rd-sepia-ink); }
.rd-paper-night { --rd-bg: var(--rd-night-bg); --rd-ink: var(--rd-night-ink); }

.rd .rd-p {
  font-size: var(--rd-fs); line-height: var(--rd-lh);
  color: var(--rd-ink); font-family: var(--rd-font);
}
.rd .rd-chapter { color: var(--rd-ink); opacity: .62; border-bottom-color: currentColor; }
.rd-paper-theme .rd-chapter { border-bottom-color: var(--border); }

/* 点区盖住整块正文。左右各三分之一翻页，中间在全屏时收放顶栏 */
.rd-tap { flex: 1; display: flex; min-height: 0; }
.rd-tap > .rd-body { flex: 1; }

/* 全屏：顶栏和翻页条都不在，正文自己留出安全区。用 --top-inset 不用 env()：
   状态栏由 .root 让掉的时候它是 0，env() 却还是刘海那一条，会让两次（4.277） */
.rd.is-bare .rd-body { padding-top: calc(var(--sp-6) + var(--top-inset)); }
.rd.is-bare { padding-bottom: env(safe-area-inset-bottom); }

/* 翻页动画。旧的一页先出去，换页，新的一页再进来 —— 同一份正文做变换，
   不复制第二份 DOM。四种都是这一条路子。 */
.rd-body.is-out { animation: rd-out var(--rd-out) var(--ease) both; }
.rd-body.is-in  { animation: rd-in var(--rd-in) var(--ease) both; }
.rd-body { --rd-out: 170ms; --rd-in: 190ms; --rd-from: 0; --rd-to: 0; }

.fx-slide.is-out.is-fwd  { --rd-to: -18%; }
.fx-slide.is-out.is-back { --rd-to: 18%; }
.fx-slide.is-in.is-fwd   { --rd-from: 18%; }
.fx-slide.is-in.is-back  { --rd-from: -18%; }
.fx-slide.is-out { animation-name: rd-out-x; }
.fx-slide.is-in  { animation-name: rd-in-x; }

.fx-vertical.is-out.is-fwd  { --rd-to: -12%; }
.fx-vertical.is-out.is-back { --rd-to: 12%; }
.fx-vertical.is-in.is-fwd   { --rd-from: 12%; }
.fx-vertical.is-in.is-back  { --rd-from: -12%; }
.fx-vertical.is-out { animation-name: rd-out-y; }
.fx-vertical.is-in  { animation-name: rd-in-y; }

@keyframes rd-out   { from { opacity: 1; } to { opacity: 0; } }
@keyframes rd-in    { from { opacity: 0; } to { opacity: 1; } }
@keyframes rd-out-x { from { opacity: 1; transform: none; }
                      to { opacity: 0; transform: translateX(var(--rd-to)); } }
@keyframes rd-in-x  { from { opacity: 0; transform: translateX(var(--rd-from)); }
                      to { opacity: 1; transform: none; } }
@keyframes rd-out-y { from { opacity: 1; transform: none; }
                      to { opacity: 0; transform: translateY(var(--rd-to)); } }
@keyframes rd-in-y  { from { opacity: 0; transform: translateY(var(--rd-from)); }
                      to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .rd-body.is-out, .rd-body.is-in { animation-duration: 1ms; }
}

/* 顶栏上并排的几个动作 */
.nav-acts { display: flex; align-items: center; gap: var(--sp-1); }

/* 取色器 + 手填色值 */
.rd-color { display: flex; align-items: center; gap: var(--sp-3); }
.rd-color .rd-swatch {
  flex: none; width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-xs); background: none;
}
.rd-color > *:nth-child(2) { flex: 1; }

/* ---- 书摘卡片 ---- */
.xc-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); padding: var(--sp-4); max-width: 17em;
}
.xc-from { font-size: var(--fs-11); color: var(--text-3); margin-bottom: var(--sp-2); }
.xc-quote {
  font-family: var(--font-serif); font-size: var(--fs-15); line-height: 1.8;
  color: var(--text); border-left: 2px solid var(--border-2);
  padding-left: var(--sp-3); margin: 0;
}
.xc-note {
  margin: var(--sp-3) 0 0; font-size: var(--fs-13);
  color: var(--text-2); line-height: 1.6;
}

/* ---- 段评 ----
   每一段正文旁边一个小气泡。有评论显示条数，没有就是个淡的，点开是那一段的评论页。
   气泡占一条固定窄列，不压在正文上，也不让正文每段宽度不一。 */
.rd-para { display: flex; align-items: flex-start; gap: var(--sp-2); }
.rd-para > .rd-p { flex: 1; min-width: 0; }
.rd-dot {
  flex: none; width: 22px; height: 22px; margin-top: .5em;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-2); border-radius: var(--r-full);
  background: none; color: var(--text-3); opacity: .5;
}
.rd-dot.has-n {
  opacity: 1; color: var(--surface);
  background: var(--text); border-color: var(--text);
}
.rd-dot-n { font-size: 10px; font-weight: var(--fw-medium); line-height: 1; }

/* 评论页顶上那一段原文 */
.pr-passage {
  font-family: var(--font-serif); font-size: var(--fs-16); line-height: 1.85;
  color: var(--text); padding: var(--sp-4);
  border-left: 2px solid var(--border-2); background: var(--surface-2);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.pr-from { text-align: right; }

/* 她说的话默认收着，点一下才展开 */
.rd-say-head {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 0; background: none; border: 0; color: var(--text-3);
}
.rd-say.is-folded { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }

/* 先读的那个角色读到哪儿了。一条细线，不抢正文 */
.ra-line {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-5);
  font-size: var(--fs-11); color: var(--text-3);
  border-top: 1px solid var(--border);
}

/* ---- 健康 ---- */
/* 四个大格子。数字要一眼看见，所以标题小、数值大 */
.hl-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3); padding: var(--sp-4) var(--sp-5);
}
.hl-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-width: 0; padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text-3); text-align: left;
}
.hl-tile b {
  font-size: var(--fs-20); font-weight: var(--fw-semi); color: var(--text);
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.hl-tile span {
  font-size: var(--fs-11); color: var(--text-3);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 加减那一格。数字仍然是一眼看见的那个，两个键靠右，不抢它的位置 */
.hl-tile-count { text-align: left; }
.hl-count { display: flex; align-items: center; gap: var(--sp-2); width: 100%; }
.hl-count b { flex: 1; min-width: 0; }
.hl-count-acts { flex: none; display: flex; gap: var(--sp-1); }
.hl-count-acts button {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-2);
}
.hl-count-acts button:disabled { opacity: .35; }

/* 排便一次一条。每条上面一行是序号、时间、删除，下面一行是形态 */
.hl-poop {
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.hl-poop:first-child { padding-top: var(--sp-2); }
.hl-poop-head { display: flex; align-items: center; gap: var(--sp-3); }
.hl-poop-no {
  flex: none; font-size: var(--fs-12); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.hl-poop-head input { flex: 1; min-width: 0; }
.hl-poop-head button { flex: none; color: var(--text-3); }

/* 趋势那一条。黑白，跟着 currentColor 走 */
.hl-trend { padding: var(--sp-3) 0 var(--sp-2); }
.hl-spark {
  display: block; width: 100%; height: 44px;
  fill: none; stroke: var(--text); stroke-width: 1.5;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.hl-spark path { vector-effect: non-scaling-stroke; }
.hl-trend-foot {
  display: flex; justify-content: space-between;
  font-size: var(--fs-11); color: var(--text-3); padding-top: var(--sp-2);
}

/* ---- 角色手机 ---- */
/* 一块主屏。**做成一块真的桌面**：壁纸铺满、顶上时间、底下一排图标。
   从前这里是两列带副标题的卡片，看着像一页设置 —— 而这是「拿起别人的
   手机」这件事的第一眼。没有导航栏（Page 的 hideBar），顶上那一行自己画。 */
.tp-desk {
  /* .page-body 是个普通块，不是 flex 容器，所以这里得写 height: 100%
     才真的铺到底；写 flex: 1 只会缩成内容那么高，底下那一条就吊在半空 */
  height: 100%; display: flex; flex-direction: column;
  /* 整页就是一块屏（Page hideBar），刘海那一条自己让，壁纸照样铺到顶边（4.277） */
  padding: calc(var(--top-inset) + var(--sp-5)) var(--sp-5) var(--sp-3);
  background-size: cover; background-position: center;
}
.tp-desk.has-img { position: relative; }
/* 壁纸上压一层，不然浅色壁纸上的字读不出来 */
.tp-desk.has-img::before {
  content: ''; position: absolute; inset: 0;
  background: var(--scrim); pointer-events: none;
}
.tp-desk > * { position: relative; }

/* 顶上那一行：角色那边此刻几点。真机上这一行没有名字，
   但这里同时开着好几台，不写是谁会认错 */
.tp-desk-top {
  flex: none; display: flex; flex-direction: column;
  align-items: center; gap: 2px; padding: var(--sp-4) 0 var(--sp-6);
}
.tp-desk-top b {
  font-size: var(--fs-28); font-weight: var(--fw-semi); line-height: 1.1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.tp-desk-top span { font-size: var(--fs-12); color: var(--text-2); }
.tp-desk.has-img .tp-desk-top b { color: var(--on-scrim); }
.tp-desk.has-img .tp-desk-top span { color: var(--on-scrim); opacity: .85; }

/* 图标网格。四列，和真的主界面一样是圆角方块加下面一行名字，
   不写副标题 —— 桌面上的图标不解释自己里面有几条 */
.tp-apps {
  flex: 1; min-height: 0; overflow-y: auto;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-5) var(--sp-3); align-content: start;
  /* 能滚动的框会把贴边那一圈切掉：第一排图标的描边与投影露在框外，顶上那一条看着不完整（4.933，用户：「软件框顶上展现不完整」）。四周留一点 */
  padding: var(--sp-2) var(--sp-1);
}
.tp-cell {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  min-width: 0; background: none; border: 0; padding: 0;
}
.tp-tile {
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 58px; aspect-ratio: 1;
  border-radius: 24%; background: var(--tile-bg); color: var(--icon-color);
  box-shadow: var(--tile-shadow);
  transition: transform var(--dur-fast) var(--ease);
}
.tp-cell:active .tp-tile { transform: scale(.93); }
/* 图标整张放进去，永远不裁 —— 和主界面那套同一个理由 */
.tp-tile.has-image {
  background-size: contain; background-position: center; background-repeat: no-repeat;
}
.tp-name {
  font-size: var(--fs-11); font-weight: var(--fw-normal);
  color: var(--text-2); max-width: 100%; text-align: center;
}
.tp-desk.has-img .tp-name {
  color: var(--on-scrim); text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
}

/* 底下那一条。生成、外观、锁上是**你的**工具，不是这台手机上的应用，
   所以和上面的图标分开摆，做成一条而不是几格 */
.tp-dock {
  flex: none; display: flex; justify-content: space-around; gap: var(--sp-2);
  margin-top: var(--sp-4); padding: var(--sp-3) var(--sp-2);
  border-radius: var(--r-xl);
  background: var(--capsule-bg); border: 1px solid var(--capsule-border);
}
.tp-dock-btn {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  flex: 1; min-width: 0; padding: var(--sp-1) 0;
  color: var(--text-2); font-size: var(--fs-11);
}
.tp-desk.has-img .tp-dock-btn { color: var(--on-scrim); }


/* 换成图片的图标，和换壁纸那一块的预览 */
.tp-ico-img {
  display: block; width: 28px; height: 28px; border-radius: var(--r-sm);
  background: var(--surface-2) center / cover no-repeat;
}
.tp-wallpick {
  display: flex; align-items: center; justify-content: center;
  /* 固定像素，不用 vh —— 第 1 条：vh 只许出现在外壳那三条上 */
  width: 100%; height: 240px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2) center / cover no-repeat;
  color: var(--text-3); font-size: var(--fs-12);
}

/* 相册。一格一张，图在上描述在下 —— 没有图的那些只剩描述，
   所以格子不做成纯图的正方形网格 */
.tp-shots {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3); padding: var(--sp-4) var(--sp-5);
}
.tp-shot {
  display: flex; flex-direction: column; gap: var(--sp-2);
  min-width: 0; padding: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); text-align: left;
}
.tp-shot-img, .tp-shot-none {
  display: flex; align-items: center; justify-content: center;
  width: 100%; aspect-ratio: 1; border-radius: var(--r-sm);
  background: var(--surface-2) center / cover no-repeat; color: var(--text-3);
}
.tp-shot-note { font-size: var(--fs-12); color: var(--text-2); max-width: 100%; }
/* 「你发的」那一枚。角色自己存下来的和生成出来的混在一起分不清哪张是真的 */
.tp-shot-from {
  align-self: flex-start; padding: 1px var(--sp-2);
  border-radius: var(--r-full); background: var(--accent-weak);
  color: var(--accent); font-size: var(--fs-11);
}

/* 生成出来的那一段对话。不复用会话页那套气泡：那一套跟着用户的美化 CSS 走，
   这里是「别人手机上的聊天」，不该被自己的皮肤影响 */
.tp-who {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-13);
}
.tp-who span { flex: 1; min-width: 0; }
.tp-wait {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-6); color: var(--text-3); font-size: var(--fs-13);
}
.tp-talk { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
.tp-line { display: flex; align-items: flex-end; gap: var(--sp-2); }
.tp-line.is-me { flex-direction: row-reverse; }
.tp-bubble {
  max-width: 72%; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md); background: var(--surface);
  border: 1px solid var(--border);
  font-size: var(--fs-14); line-height: 1.5; color: var(--text);
  white-space: pre-wrap; word-break: break-word;
}
.tp-line.is-me .tp-bubble { background: var(--accent-weak); border-color: var(--accent-weak); }
/* 代发（4.308）：被对方拒收的那一句，旁边一行小字；输入框上面选角色知不知道 */
.tp-reject { align-self: center; color: var(--danger); font-size: var(--fs-12); }
.tp-proxy { padding-bottom: var(--sp-2); }
/* 和你那一段里的图片。只画缩略图 —— 这一页是看个样子，不是会话页 */
.tp-bubble-img { padding: 3px; }
.tp-bubble-img img {
  display: block; max-width: 180px; width: 100%; height: auto;
  border-radius: var(--r-sm);
}

/* 锁屏。壁纸铺底，上面时间与头像，下面数字键盘 */
.tp-lock {
  /* 同 .tp-desk：要 height: 100%，否则 space-between 无从分配 */
  height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: space-between;
  padding: calc(var(--top-inset) + var(--sp-6)) var(--sp-5) var(--sp-5);
  background-size: cover; background-position: center;
}
.tp-lock.has-img { position: relative; }
.tp-lock.has-img::before {
  content: ''; position: absolute; inset: 0;
  background: var(--scrim-strong); pointer-events: none;
}
.tp-lock > * { position: relative; }
/* 上面只有一张头像。时刻与星期撤了：主屏上它是「这台手机此刻几点」，
   有用；锁屏上你是来输密码的，那两行只占地方 */
.tp-lock-top { display: flex; align-items: center; justify-content: center; }

/* 圆点与那一行说明是一件事，拢在一起 —— 分成两个 flex 子项的话
   space-between 会把它们撑开老远 */
.tp-lock-mid { display: flex; flex-direction: column; align-items: center; }
.tp-dots { display: flex; gap: var(--sp-3); }
.tp-dots i {
  width: 11px; height: 11px; border-radius: var(--r-full);
  border: 1px solid var(--text-3); background: transparent;
}
.tp-dots i.is-on { background: var(--text); border-color: var(--text); }
.tp-lock-note { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-4); }

.tp-keys {
  display: grid; grid-template-columns: repeat(3, 72px);
  gap: var(--sp-3); justify-content: center;
}
.tp-key {
  display: flex; align-items: center; justify-content: center;
  width: 72px; height: 72px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text);
  font-size: var(--fs-24); font-variant-numeric: tabular-nums;
}
.tp-lock-acts { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.tp-lock-acts button { font-size: var(--fs-13); color: var(--text-2); padding: var(--sp-2); }

/* ---- 相册 ---- */
.photo-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3px; padding: 0 var(--sp-3) var(--sp-4);
}
.photo-cell { padding: 0; border: 0; background: none; min-width: 0; }
.photo-tile {
  width: 100%; aspect-ratio: 1 / 1; border-radius: var(--r-xs);
  background-size: cover; background-position: center;
  background-color: var(--surface-2);
}
.photo-tile.is-blank {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; color: var(--text-3);
  box-shadow: inset 0 0 0 1px var(--border);
}
.photo-tile.is-blank span { font-size: var(--fs-11); }
.photo-pick-head { display: flex; align-items: center; justify-content: space-between; padding-right: var(--sp-3); }
.photo-cell:where(.is-picked) { position: relative; }
.photo-cell:where(.is-picked) .photo-tile { box-shadow: inset 0 0 0 2px var(--text); opacity: .85; }
.photo-order {
  position: absolute; top: var(--sp-1); right: var(--sp-1);
  min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--text); color: var(--bg); font-size: var(--fs-11);
}

.photo-stage {
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-4) var(--sp-3); background: var(--surface-2);
}
.photo-full { max-width: 100%; display: block; border-radius: var(--r-sm); }
/* 卡片那一层：里面是 shadow root，外面只管给它一个白底和圆角 */
.cardbox {
  max-width: 100%; overflow: hidden;
  border-radius: var(--r-sm); background: var(--surface);
  box-shadow: var(--shadow-1);
}

/* ---- 出行 ---- */
/* 详情页顶上那一块。写的是算出来的数（还有几天、第几天），不写形容 */
.trip-head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4); border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-2);
}
.trip-head > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.trip-head b { font-size: var(--fs-15); font-weight: var(--fw-semi); color: var(--text); }
.trip-head span { font-size: var(--fs-12); color: var(--text-3); }

/* 会话里那条出行提议。和外卖那一条共用 tr-top / tr-body / tr-foot 那几层 */
.bubble-trip { min-width: 190px; max-width: 244px; padding: var(--sp-3) var(--sp-4) 0; }
/* 票那一行右边的两个动作。按钮与删除挨着，不各占一行 */
.tk-acts { display: flex; align-items: center; gap: var(--sp-2); }

/* ---- 线下 ----
   见 ARCHITECTURE 4.107。颜色、字号、行距全走 --sg-* 变量，由
   system/stage.js 按用户设置生成，只作用在 .sg 里面，不碰 app 的主题。
   和阅读器的 --rd-* 是两套：线下想要的纸色字号，和读书时想要的不是一回事。 */
.sg {
  --sg-bg: var(--surface);
  --sg-ink: var(--text);
  --sg-dim: var(--text-2);
  --sg-line: var(--border);
  --sg-mark: var(--accent);
  --sg-mark-soft: transparent;
  --sg-fs: var(--fs-17);
  --sg-lh: 1.9;
  --sg-gap: 1em;
  --sg-measure: 34em;
  --sg-font: var(--font-serif);

  /* .page-body 是块级容器，flex:1 在它里面撑不开，要 height */
  position: relative;
  height: 100%;
  display: flex; flex-direction: column;
  background: var(--sg-bg);
  background-image: var(--sg-bg-image, none);
  background-size: cover; background-position: center;
  color: var(--sg-ink);
}

/* 刊头。整块顶栏归线下自己画 —— 用 app 的 navbar 会在深色主题上方
   留一条白边，那就不是「整个页面进入线下」了。铺满屏幕时整条不在。
   上方安全区用 --top-inset 让（外壳那一层对 is-bare 的页不让，见 shell.css） */
.sg-head {
  flex: none;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  padding-top: calc(var(--sp-2) + var(--top-inset));
  border-bottom: 1px solid var(--sg-line);
}
.sg-head-text { flex: 1; min-width: 0; }
/* 开了左上角的悬浮返回键：它正压在刊头的返回箭头上，箭头让位（和 .navbar .nav-left 同一条规矩） */
:root[data-nav="back"] .sg-head > .sg-icon:first-child { visibility: hidden; }
.sg-icon {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: var(--r-md);
  color: var(--sg-ink); background: none; border: 0;
}
.sg-eyebrow {
  font-size: var(--fs-11); letter-spacing: .1em;
  color: var(--sg-dim); text-transform: uppercase;
}
.sg-title {
  font-family: var(--sg-font); font-size: var(--fs-15);
  color: var(--sg-ink); text-wrap: balance;
}

/* 点区盖住整块正文，左右各三分之一翻页 */
.sg-tap { flex: 1; display: flex; min-height: 0; }
.sg-body {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--sp-6) var(--sp-4);
  -webkit-overflow-scrolling: touch;
}
/* 铺满屏幕时没有顶栏，正文自己让出上方的安全区。
   下方不用管：.page-body 是最后一个孩子，安全区由它让（见 ui.css） */
.sg.is-spread .sg-body {
  padding-top: calc(var(--sp-8) + var(--top-inset));
  padding-bottom: var(--sp-8);
}

/* 正文栏。宽度归它，排版归 .sg-text —— 邮戳要和正文同一条栏宽对齐 */
.sg-col { max-width: var(--sg-measure); margin: 0 auto; }

/* 正文。一行三十来个汉字，段距分段，首行不缩进 ——
   屏幕上缩进远不如段距清楚 */
.sg-text {
  font-family: var(--sg-font);
  font-size: var(--sg-fs);
  line-height: var(--sg-lh);
  color: var(--sg-ink);
}
.sg-text p { margin: 0 0 var(--sg-gap); }
.sg-text p:last-child { margin-bottom: 0; }
.sg-q { color: var(--sg-ink); }
.sg-act { color: var(--sg-dim); font-style: italic; }

/* 生成中那一段直接往这里塞 textContent，绕开 diff ——
   几万字走 Preact 每秒几十次 diff 一个巨大文本节点，界面会僵住 */
.sg-live { white-space: pre-wrap; }

/* 一段开头的署名。全是小字 —— 撑开篇那一页的是正文的首字下沉，不是这里。
   刊物里的页码（folio）一向是小的、推到页边的，所以编号并进这一行，
   不再是上一版那个 56px 的大数字（见 ARCHITECTURE 4.107）。 */
.sg-sign {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: 0 0 var(--sp-5);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--sg-line);
  /* 跟着正文那套字走。从前这里落回系统黑体，正文是宋体，两种字挤在
     一块儿，署名就显得比正文硬 */
  font-family: var(--sg-font);
}
.sg-sign-text { min-width: 0; }
.sg-sign-name {
  font-size: var(--fs-12); letter-spacing: .2em; line-height: 1.6;
  color: var(--sg-ink);
}
:where(.sg-sign.is-mine) .sg-sign-name { color: var(--sg-dim); }
/* 不用 tabular-nums：这里的数字不排成列，等宽只会让时刻看着像块表 */
.sg-sign-meta {
  font-size: 10px; letter-spacing: .14em; line-height: 1.6;
  color: var(--sg-dim);
}
/* 头像。方的，一道发丝框，不做圆 —— 圆头像一出现，整页就读成聊天了 */
.sg-face {
  flex: none; width: 46px; height: 46px; object-fit: cover;
  border-radius: 3px; border: 1px solid var(--sg-line);
}

/* 只要一行的那一档。同一份字距，去掉头像与细线 */
.sg-byline {
  font-family: var(--sg-font);
  font-size: 10px; letter-spacing: .16em; color: var(--sg-dim);
  margin-bottom: var(--sp-5);
}

/* 明信片那一档。竖着滑，一张一张排下去 */
.sg-feed {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--sp-4);
  -webkit-overflow-scrolling: touch;
}
.sg-card {
  max-width: var(--sg-measure); margin: 0 auto var(--sp-4);
  padding: var(--sp-5) var(--sp-4);
  border: 1px solid var(--sg-line);
  border-radius: 3px;
  background: var(--sg-bg);
  display: flex; flex-direction: column;
}
.sg-card:last-child { margin-bottom: 0; }
/* 每片一样大那一档：真明信片的比例（105 × 148 毫米），文字在片内滚。
   高度不能用 vh —— 第 1 条只许外壳那三层用，这里靠比例 */
.sg-card:where(.is-fixed) { aspect-ratio: 105 / 148; }
.sg-card-body { flex: 1; min-height: 0; }
:where(.sg-card.is-fixed) .sg-card-body { overflow-y: auto; -webkit-overflow-scrolling: touch; }
.sg.is-spread .sg-feed {
  padding-top: calc(var(--sp-4) + var(--top-inset));
}

/* 场外指示的标记。不占一张，只在刊头留一个点得开的记号 */
.sg-note {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-11); letter-spacing: .1em;
  color: var(--sg-dim);
  border: 1px solid var(--sg-line); border-radius: var(--r-full);
  padding: 2px var(--sp-2);
  background: none;
}

/* 页码那一条。一根细线加一个数 */
.sg-foot {
  flex: none;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4) var(--sp-3);
  color: var(--sg-dim); font-size: var(--fs-11);
  font-variant-numeric: tabular-nums;
}
.sg-rule { flex: 1; height: 1px; background: var(--sg-line); }
/* 收了场的那一场（4.833）：输入栏上面写一行，点「角色写」会先问要不要重新开启 */
.sg-ended { flex: none; padding: 0 var(--sp-4) var(--sp-2); color: var(--sg-dim); font-size: var(--fs-12); text-align: center; }

/* 底下那一条：输入框就在这里（4.512）。从前点「写一段」跳一整页编辑器，写一句也要进出一次。
   和聊天的底栏一样：框跟着字数长高，到 max-height 后在框里滚；键盘升起时整条跟着上来（外壳让出键盘高度） */
.sg-compose { flex: none; background: var(--sg-bg); border-top: 1px solid var(--sg-line); }
.sg-bar {
  display: flex; align-items: flex-end; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
}
.sg-input {
  flex: 1; min-width: 0; min-height: 36px; max-height: 200px; resize: none; overflow-y: auto;
  font-family: var(--sg-font); font-size: var(--fs-15); line-height: 1.5; color: var(--sg-ink);
  padding: 6px var(--sp-3); border: 1px solid var(--sg-line); border-radius: var(--r-md);
  background: none;
}
.sg-input::placeholder { color: var(--sg-dim); }
/* 写场外指示时换成虚线框，一眼分得出写的不是正文 */
.sg-input:where(.is-director) { border-style: dashed; }
.sg-act-btn:where(.is-on) { color: var(--sg-bg); background: var(--sg-ink); border-color: var(--sg-ink); }
/* 场外指示时右边那个「一直有效」：一个小开关，不另起一行 */
.sg-hold {
  flex: none; height: 36px; padding: 0 var(--sp-2); border-radius: var(--r-md);
  font-size: var(--fs-12); color: var(--sg-dim); background: none; border: 1px dashed var(--sg-line);
}
.sg-hold:where(.is-on) { color: var(--sg-ink); border-style: solid; border-color: var(--sg-ink); }
.sg-act-btn {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: var(--r-md);
  color: var(--sg-ink); background: none; border: 1px solid var(--sg-line);
}
.sg-act-btn:disabled { opacity: .4; }
/* 底栏右端那个写字的主按钮：「角色写」，写着时是「停止」（4.281）。图标按钮没人猜得出哪个是哪个 */
.sg-go {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
  height: 36px; padding: 0 var(--sp-3); border-radius: var(--r-md);
  font-size: var(--fs-13); font-weight: var(--fw-semi);
  color: var(--sg-bg); background: var(--sg-ink); border: 1px solid var(--sg-ink);
}
.sg-go:disabled { opacity: .4; }
.sg-act-text {
  flex: none; height: 36px; padding: 0 var(--sp-3); border-radius: var(--r-md);
  font-size: var(--fs-13); color: var(--sg-ink); background: none; border: 1px solid var(--sg-line);
}
/* 还没有正文：两条明确的开头 */
.sg-empty { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); padding: var(--sp-6) 0; }
.sg-empty-acts { display: flex; gap: var(--sp-2); }

/* 铺满屏幕：刊头、页码、底栏都退掉，只剩正文 */
.sg.is-spread .sg-head, .sg.is-spread .sg-foot, .sg.is-spread .sg-compose { display: none; }
/* 铺满时右上角留一个「…」，点它退出铺满（4.706）。从前铺满之后只能点正文收回，用户找不到 */
.sg-unspread {
  position: absolute; z-index: 2;
  top: calc(var(--sp-2) + var(--top-inset)); right: var(--sp-3);
  background: var(--sg-bg); opacity: .8;
}

/* 翻页。旧的一页先出去，换页，新的一页再进来 —— 同一份正文做变换 */
.sg-body.is-out { animation: sg-out 160ms var(--ease) both; }
.sg-body.is-in  { animation: sg-in 200ms var(--ease) both; }
@keyframes sg-out { to { opacity: 0; } }
@keyframes sg-in { from { opacity: 0; } }
.sg[data-effect="slide"] .sg-body.is-out { animation-name: sg-out-slide; }
.sg[data-effect="slide"] .sg-body.is-in  { animation-name: sg-in-slide; }
@keyframes sg-out-slide { to { opacity: 0; transform: translateX(-12%); } }
@keyframes sg-in-slide { from { opacity: 0; transform: translateX(12%); } }
.sg[data-effect="vertical"] .sg-body.is-out { animation-name: sg-out-up; }
.sg[data-effect="vertical"] .sg-body.is-in  { animation-name: sg-in-up; }
@keyframes sg-out-up { to { opacity: 0; transform: translateY(-8%); } }
@keyframes sg-in-up { from { opacity: 0; transform: translateY(8%); } }
.sg[data-effect="instant"] .sg-body.is-out,
.sg[data-effect="instant"] .sg-body.is-in { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .sg-body.is-out, .sg-body.is-in { animation: none; }
}

/* 场次列表。每一条是一篇稿子的目录行，不画卡片 */
.sc-row { display: flex; flex-direction: column; gap: 2px; }
.sc-meta { font-size: var(--fs-12); color: var(--text-2); letter-spacing: .04em; }

/* 一段的第几版。重写不删旧的，在这儿翻 */
.sg-vers {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  margin-top: var(--sp-5);
  color: var(--sg-dim); font-size: 10px; letter-spacing: .16em;
}
.sg-vers-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--r-sm);
  color: inherit; background: none; border: 1px solid var(--sg-line);
}
.sg-vers-btn:disabled { opacity: .35; }
.sg-vers-no { font-variant-numeric: tabular-nums; }

/* ---- 线下：就在聊天里演的那一档 ----
   见 ARCHITECTURE 4.110。整场戏渲染在一条消息里，--sg-* 只作用在这个块上，
   块外面仍然是聊天的样子。 */
.sc-block {
  margin: var(--sp-4) 0;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--sg-bg);
  color: var(--sg-ink);
  font-family: var(--sg-font);
}
.sc-block .sg-text {
  font-size: var(--sg-fs); line-height: var(--sg-lh); color: var(--sg-ink);
}
.sc-block .sg-text p { margin: 0 0 var(--sg-gap); }
.sc-block .sg-text p:last-child { margin-bottom: 0; }

/* 划的那条线。开场一条，收场一条 */
.sc-div {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-2) 0 var(--sp-5);
}
.sc-div-line { flex: 1; height: 1px; background: var(--sg-line); }
.sc-div-text {
  flex: none; font-size: 10px; letter-spacing: .22em; color: var(--sg-dim);
}
.sc-div.is-end { margin: var(--sp-5) 0 var(--sp-2); }

.sc-beat + .sc-beat { margin-top: var(--sp-6); }
.sc-empty { text-align: center; padding: var(--sp-4) 0; }

/* 底下那三个。线下自己的色，不跟 app 的按钮走 */
.sc-acts {
  display: flex; gap: var(--sp-2); justify-content: flex-end;
  margin-top: var(--sp-5); padding-top: var(--sp-3);
  border-top: 1px solid var(--sg-line);
}
.sc-act {
  font-size: var(--fs-12); letter-spacing: .1em;
  color: var(--sg-dim); background: none;
  border: 1px solid var(--sg-line); border-radius: var(--r-sm);
  padding: var(--sp-1) var(--sp-3);
}

/* 正在写的那一段。铺在列表末尾，不进块里 —— 块是 memo 过的 */
.sc-live { opacity: .85; }
.sc-live .sg-text { white-space: pre-wrap; }

/* 线下开着时的输入框。换个底色，一眼看出发出去的是正文不是消息 */
.composer-input:where(.is-scene) {
  background: var(--wg-bg);
  border-radius: var(--r-sm);
}

/* 悬浮窗。内联时没有线下那一页的菜单可挂，常用的几项浮在这儿 */
.sc-float-wrap {
  position: absolute; inset: 0; z-index: var(--z-sheet);
  background: var(--scrim);
  display: flex; align-items: flex-end; justify-content: center;
  padding: var(--sp-4);
  padding-bottom: calc(var(--sp-8) + var(--safe-bottom));
}
.sc-float {
  width: 100%; max-width: 360px;
  max-height: 70%;
  display: flex; flex-direction: column;
  background: var(--surface); color: var(--text);
  border-radius: var(--r-lg); box-shadow: var(--shadow-3);
  overflow: hidden;
}
.sc-float-head {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-15); font-weight: var(--fw-medium);
}
.sc-float-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-sm);
  color: var(--text-2); background: none; border: 0;
}
.sc-float-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--sp-3) 0; }
.sc-float-themes {
  display: flex; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-2);
}
.sc-swatch {
  flex: 1; padding: var(--sp-3) 0; border-radius: var(--r-sm);
  border: 1px solid; font-size: var(--fs-12);
}
.sc-swatch.is-on { box-shadow: 0 0 0 2px var(--accent); }
.sc-float-note {
  padding: 0 var(--sp-4) var(--sp-2);
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.5;
}

/* ---- 我们：目录上那几个小按钮 ---- */
.wk-ops { display: inline-flex; align-items: center; gap: 2px; }
.wk-op {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-sm);
  color: var(--text-3); background: none; border: 0;
}

/* ---- 气泡那一档：一段一个长气泡，气泡里按句断行 ---- */
/* 见 ARCHITECTURE 4.118。阅读那两档是刊物的排法，这一档是另一种读法。
   封面不在这儿 —— 读的时候上面不该压着一张图，那是扉页的事（.wk-hero） */
.sg-bubs {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--sp-4) var(--sp-4) var(--sp-6);
  -webkit-overflow-scrolling: touch;
}

.sg-bub {
  max-width: var(--sg-measure); margin: 0 auto var(--sp-4);
  padding: var(--sp-4) var(--sp-4) var(--sp-5);
  border-radius: 20px;
  background: var(--sg-mark-soft);
  border: 1px solid transparent;
}
/* 自己写的那些不填底，只描一道线 —— 一屏全是实心块会糊成一片 */
.sg-bub:where(.is-mine) { background: none; border-color: var(--sg-line); }
.sg-bub:last-child { margin-bottom: 0; }
.sg-bub-who {
  font-family: var(--sg-font); font-size: var(--fs-11);
  letter-spacing: .22em; color: var(--sg-dim);
  margin-bottom: var(--sp-3);
}
/* 气泡版式署名旁的头像（4.690）：比明信片那一档小一号，仍是方的 */
.sg-bub-who { display: flex; align-items: center; gap: var(--sp-2); }
:where(.sg-bub.is-mine) .sg-bub-who { flex-direction: row-reverse; }
.sg-bub-who .sg-face { width: 26px; height: 26px; }

/* 歌词页那样：一句一行，行距拉开，字比正文大一号 */
.sg-lyric {
  font-family: var(--sg-font);
  font-size: calc(var(--sg-fs) * 1.18);
  line-height: 1.5;
  color: var(--sg-ink);
}
.sg-lyric p { margin: 0 0 .6em; }
.sg-lyric p:last-child { margin-bottom: 0; }
.sg-lyric p:where(.is-said) { font-weight: var(--fw-medium); }
/* 正文附带的译文（4.366）：跟在它那一段下面，小一号、淡一层。线下的自定义样式里写 .sg-trans 可改 */
.sg-trans { margin: 0 0 var(--sg-gap); font-size: .86em; line-height: 1.7; color: var(--sg-dim); }
/* 多人线下（4.439）：这一段里谁来了、谁走了，一行小字 */
.sg-cast { margin: 0 0 var(--sg-gap); font-size: .8em; line-height: 1.6; color: var(--sg-dim); }
.sg-trans:last-child { margin-bottom: 0; }
/* 说的话后面接的译文（4.394）：「原话（译文）」。同样淡一层；线下的自定义样式里写 .sg-trans-q 或 .ph-trans 可改 */
.sg-trans-q { font-size: .92em; color: var(--sg-dim); }
.sg-text p:has(+ .sg-trans), .sg-lyric p:has(+ .sg-trans) { margin-bottom: .3em; }

/* 我们：作品封面那一格 */
.wk-cover-row { display: flex; align-items: center; gap: var(--sp-3); }
.wk-cover {
  flex: none; width: 96px; height: 96px;
  border-radius: var(--r-sm); overflow: hidden;
  border: 1px dashed var(--line); background: var(--surface);
  color: var(--text-3); font-size: var(--fs-12);
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.wk-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- 我们：扉页 ----
   点进一部作品先看到的那一屏。用这部作品自己的纸色，不是 app 的底色 ——
   它是作品的一部分，不是列表的表头 */
.wk-hero {
  background: var(--sg-bg); color: var(--sg-ink);
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  text-align: center;
  border-bottom: 1px solid var(--sg-line);
}
.wk-hero-art {
  width: 168px; aspect-ratio: 1; margin: 0 auto var(--sp-4);
  border-radius: 4px; overflow: hidden;
  background: var(--sg-mark-soft);
  border: 1px solid var(--sg-line);
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-2);
}
.wk-hero-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wk-hero-glyph { font-family: var(--sg-font); font-size: 64px; color: var(--sg-mark); line-height: 1; }
.wk-hero-title {
  font-family: var(--sg-font); font-size: var(--fs-20);
  color: var(--sg-ink); line-height: 1.3;
}
.wk-hero-names {
  margin-top: 8px; font-family: var(--sg-font);
  font-size: var(--fs-13); letter-spacing: .18em; color: var(--sg-dim);
}
.wk-hero-meta {
  margin-top: 5px; font-family: var(--sg-font);
  font-size: var(--fs-11); letter-spacing: .1em; color: var(--sg-dim);
}

/* ---- 群聊（ARCHITECTURE 4.162） ---- */
/* 发起群聊：群名称固定在上面，角色列表占住剩下的高度、自己滚 */
.ng-body { height: 100%; display: flex; flex-direction: column; min-height: 0; }
.ng-list { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  padding-bottom: var(--safe-bottom); }
/* 群头像：最多四个成员拼一格。尺寸由 GroupFace 以自定义属性传入 */
.group-face {
  flex: none; width: var(--gf-size); height: var(--gf-size);
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  display: grid; grid-template-columns: 1fr; place-items: center;
}
.group-face:where(.n-2), .group-face:where(.n-3), .group-face:where(.n-4) {
  grid-template-columns: 1fr 1fr; gap: 2px; padding: 2px; align-content: center;
}
.group-face:where(.n-3) > :first-child { grid-column: 1 / 3; }
.group-head {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-5) 0 var(--sp-2);
}
.group-head-acts { display: flex; gap: var(--sp-4); }
.group-add-foot { padding: var(--sp-4); }
/* 群里别人说的话，气泡上方写着是谁 */
.msg-who { font-size: var(--fs-11); color: var(--text-3); padding: 0 var(--sp-1); }
.mention-bar { padding: 0 var(--sp-3) var(--sp-2); margin-top: 0; }

/* ---- 互动标识（ARCHITECTURE 4.164） ----
   单色：一律是 currentColor。动效只在形态上做：火苗晃、快断时一明一暗、
   余烬暗着、太阳慢慢转、满级那一圈的亮点绕着走。
   系统设置里开了「减弱动态效果」的，全部停下来 */
.bd-g { display: inline-flex; align-items: center; justify-content: center; color: var(--text); line-height: 0; }
.bd-g:where(.is-off) { color: var(--text-3); }
.bd-g:where(.is-ember) { color: var(--text-3); }
.bd-g.is-lit.is-spark svg, .bd-g.is-lit.is-flame svg, .bd-g.is-lit.is-torch svg, .bd-g.is-lit.is-flameFill svg {
  transform-origin: 50% 90%; animation: bd-flicker calc(var(--dur-slow) * 6) var(--ease) infinite;
}
.bd-g.is-risk svg { animation: bd-risk calc(var(--dur-slow) * 4) ease-in-out infinite; }
.bd-g.is-lit.is-sun svg { animation: bd-spin calc(var(--dur-slow) * 60) linear infinite; }
.bd-g.is-lit.is-star svg { animation: bd-twinkle calc(var(--dur-slow) * 8) ease-in-out infinite; }
@keyframes bd-flicker {
  0%, 100% { transform: scale(1, 1) rotate(0); }
  30% { transform: scale(.96, 1.05) rotate(-2deg); }
  60% { transform: scale(1.03, .97) rotate(2deg); }
}
@keyframes bd-risk { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes bd-spin { to { transform: rotate(360deg); } }
@keyframes bd-twinkle { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

.bd-streak { display: inline-flex; align-items: center; gap: 2px; margin-left: var(--sp-1); vertical-align: middle; }
.bd-num { font-size: var(--fs-11); color: var(--text-2); font-weight: var(--fw-medium); }
.bd-num.is-risk { color: var(--text-3); }
/* 天数嵌在火焰右下角（4.872）：挖空用 SVG 遮罩（BadgeBits 的 CountGlyph），不依赖底色 */
.bd-g:where(.is-risk) .bd-xt { opacity: .6; }
/* 带数字的那一枚不晃：数字跟着晃读不清 */
.bd-g.is-lit.has-count svg { animation: none; }
.bd-list { flex: none; display: inline-flex; align-items: center; gap: var(--sp-1); }
/* 名字与标识挨着，时刻仍然靠右 */
.msg-name-wrap { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-1); }
:where(.msg-name-wrap) .msg-name { flex: 0 1 auto; }

/* 头像外那一圈：比头像大一圈，圈本身不挡点击 */
.lv-ring { position: relative; display: inline-flex; width: var(--lv-size); height: var(--lv-size); color: var(--text); }
.lv-svg { position: absolute; inset: -6px; width: calc(100% + 12px); height: calc(100% + 12px);
  transform: rotate(-90deg); pointer-events: none; overflow: visible; }
.lv-track { fill: none; stroke: var(--border-2); stroke-width: 1.5; }
.lv-arc { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;
  transition: stroke-dasharray var(--dur-slow) var(--ease-out); }
.lv-orbit { fill: currentColor; transform-origin: 50% 50%; animation: bd-spin calc(var(--dur-slow) * 16) linear infinite; }

.bd-strip {
  display: flex; align-items: center; gap: var(--sp-2); width: calc(100% - var(--sp-8));
  margin: var(--sp-2) var(--sp-4) 0; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md); background: var(--surface-2); color: var(--text); font-size: var(--fs-12);
}
.bd-strip .bd-streak { margin-left: 0; }
.bd-strip-lv { font-weight: var(--fw-medium); }
.bd-strip-n { margin-left: auto; color: var(--text-2); }

.bd-award {
  display: flex; align-items: center; gap: var(--sp-3); min-width: 200px; max-width: 260px;
  padding: var(--sp-3); border-radius: var(--r-lg); border: 1px solid var(--border-2);
  background: var(--surface);
}
.bd-award-body { min-width: 0; }
.bd-award-tag { font-size: var(--fs-11); color: var(--text-3); }
.bd-award-name { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.bd-award-why { font-size: var(--fs-12); color: var(--text-2); margin-top: 2px; }

/* 解锁那一下：从上面落下来，图形放大后落定 */
.bd-toast {
  position: absolute; left: var(--sp-4); right: var(--sp-4); top: var(--sp-3); z-index: 30;
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg); background: var(--surface); box-shadow: var(--shadow-3);
  animation: bd-drop var(--dur-slow) var(--ease-out);
}
.bd-toast-glyph { animation: bd-pop calc(var(--dur-slow) * 2) var(--ease-out); }
.bd-toast-tag { font-size: var(--fs-11); color: var(--text-3); }
.bd-toast-name { font-size: var(--fs-17); font-weight: var(--fw-medium); }
.bd-toast-desc { font-size: var(--fs-12); color: var(--text-2); }
@keyframes bd-drop { from { transform: translateY(-120%); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes bd-pop { 0% { transform: scale(.2); } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }
.conv { position: relative; }

.bd-hero { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: var(--sp-6) 0 var(--sp-2); }
.bd-hero-face { width: 100%; height: 100%; border-radius: var(--r-full); background: var(--surface-2);
  display: flex; align-items: center; justify-content: center; }
.bd-hero-lv { font-size: var(--fs-17); font-weight: var(--fw-medium); margin-top: var(--sp-2); }
.bd-hero-sub { font-size: var(--fs-12); color: var(--text-3); }
.bd-forms { display: flex; justify-content: space-between; padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.bd-form { display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: var(--fs-12); color: var(--text-3); }
.bd-form.is-got { color: var(--text); }
.bd-form small { font-size: var(--fs-11); color: var(--text-3); }
.bd-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); padding: var(--sp-3); }
.bd-cell { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); text-align: center;
  padding: var(--sp-3) var(--sp-2); border-radius: var(--r-md); background: var(--surface-2); color: var(--text-3); }
.bd-cell.is-got { color: var(--text); }
.bd-cell b { font-size: var(--fs-13); font-weight: var(--fw-medium); }
.bd-cell small { font-size: var(--fs-11); color: var(--text-3); line-height: 1.4; }

.yr-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-4); }
.yr-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-2); }
.yr-cell { display: flex; flex-direction: column; padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.yr-cell b { font-size: var(--fs-24); font-weight: var(--fw-medium); }
.yr-cell span { font-size: var(--fs-12); color: var(--text-2); }
.yr-note { padding: var(--sp-4); font-size: var(--fs-14); line-height: 1.7; white-space: pre-wrap; }

/* 那年今天。一行一条：谁、几点、说了什么。不画成气泡 —— 这是翻旧账，不是再聊一遍 */
.otd-back { display: flex; justify-content: center; margin-top: calc(var(--sp-2) * -1); padding-bottom: var(--sp-2); }
.otd-day { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.otd-line { display: grid; grid-template-columns: auto 1fr; column-gap: var(--sp-2); row-gap: var(--sp-1); }
.otd-who { font-size: var(--fs-12); color: var(--text-2); }
.otd-line.is-mine .otd-who { color: var(--accent); }
.otd-time { font-size: var(--fs-12); color: var(--text-3); }
.otd-text { grid-column: 1 / -1; font-size: var(--fs-14); line-height: 1.6; white-space: pre-wrap; word-break: break-word; }

@media (prefers-reduced-motion: reduce) {
  .bd-g svg, .lv-orbit, .bd-toast, .bd-toast-glyph { animation: none !important; }
}

/* 分享的一首歌（chat/pages/SongCard.js）。会话气泡与朋友圈共用，照 Apple Music 的分享卡片。
   底色是封面主色按两成多混进面板底色（--song-tint 由脚本从封面取），取不到就是面板底色 */
.song-card {
  --song-bg: var(--surface-2);
  display: flex; text-align: left; color: var(--text); cursor: pointer;
  background: var(--song-bg); border-radius: var(--r-lg); overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}
.song-card.is-tinted { --song-bg: color-mix(in srgb, var(--song-tint) 26%, var(--surface-2)); }
.song-card:active { filter: brightness(.97); }
.song-card.is-off { cursor: default; }
.song-card.is-off:active { filter: none; }
.song-art {
  flex: none; display: flex; align-items: center; justify-content: center; overflow: hidden;
  background: var(--surface-3); color: var(--text-3);
}
.song-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.song-art.is-pending { animation: song-wait 1.4s var(--ease-out) infinite alternate; }
@keyframes song-wait { from { opacity: 1; } to { opacity: .55; } }
.song-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.song-title { font-size: var(--fs-15); font-weight: var(--fw-semi); line-height: 1.35; }
.song-artist { font-size: var(--fs-13); color: var(--text-2); line-height: 1.35; }
.song-note { font-size: var(--fs-11); color: var(--text-3); line-height: 1.4; margin-top: 3px; }

/* 会话里：上封面、下文字 */
.song-card.is-tile { flex-direction: column; width: 216px; max-width: 100%; box-shadow: var(--shadow-1); }
.song-top { position: relative; display: block; }
.song-card.is-tile .song-art { width: 100%; aspect-ratio: 1 / 1; }
.song-card.is-tile .song-key { position: absolute; right: var(--sp-2); bottom: var(--sp-2); }
.song-foot { display: flex; padding: var(--sp-2) var(--sp-3) var(--sp-3); }

/* 朋友圈：一行 */
.song-card.is-row { align-items: center; gap: var(--sp-3); padding: var(--sp-2); width: 100%; }
.song-card.is-row .song-art { width: 52px; height: 52px; border-radius: var(--r-sm); }
.song-card.is-row .song-title { font-size: var(--fs-14); }
.song-card.is-row .song-key { margin-right: var(--sp-1); }

/* 圆形播放键。放着的时候外面一圈是进度 */
.song-key {
  position: relative; flex: none; width: var(--key); height: var(--key); border-radius: 50%;
  display: flex; align-items: center; justify-content: center; border: 0; padding: 0;
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-2); cursor: pointer;
}
.song-key:disabled { opacity: .4; }
.song-key svg:not(.song-ring) { margin-left: 2px; }
.song-key.is-playing svg:not(.song-ring) { margin-left: 0; }
.song-ring { position: absolute; inset: -3px; width: calc(100% + 6px); height: calc(100% + 6px); transform: rotate(-90deg); pointer-events: none; }
.song-ring circle { fill: none; stroke: var(--surface); stroke-width: 2.4; }
.song-ring .song-ring-on { stroke: var(--text); transition: stroke-dashoffset .5s linear; }

/* 会话里这张不挂 .bubble：卡片自己就是那一块，两边一样，不跟着强调色变黑 */
.mo-song { margin-top: var(--sp-2); }
.mo-song-pick { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-3) 0; }
.mo-song-pick .song-card { flex: 1; width: auto; }
.song-search { display: flex; gap: var(--sp-2); align-items: center; padding: 0 0 var(--sp-3); }
.song-search input { flex: 1; min-width: 0; }

@media (prefers-reduced-motion: reduce) {
  .song-art.is-pending { animation: none; }
  .song-ring .song-ring-on { transition: none; }
}
button.conv-notice { background: none; border: 0; font: inherit; cursor: pointer; }

/* 角色调用 MCP 工具的那一条（chat/pages/ToolBits.js） */
.tool-card { display: flex; flex-direction: column; gap: 4px; width: 260px; max-width: 100%; cursor: pointer; }
.tool-head { display: flex; align-items: center; gap: 6px; font-size: var(--fs-13); font-weight: var(--fw-semi); min-width: 0; }
.tool-name { flex: 1; min-width: 0; }
.tool-server { flex: none; max-width: 40%; font-size: var(--fs-11); font-weight: var(--fw-normal); color: var(--text-3); }
.tool-args { font-size: var(--fs-12); color: var(--text-2); }
.tool-state { display: flex; align-items: center; gap: 6px; font-size: var(--fs-12); color: var(--text-3); }
.tool-state.is-error { color: var(--danger); display: block; word-break: break-word; }
.tool-result {
  font-size: var(--fs-13); line-height: 1.5; white-space: pre-wrap; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
  border-top: 1px solid var(--border); padding-top: 4px;
}
.tool-acts { display: flex; gap: var(--sp-2); justify-content: flex-end; }
.tool-detail { font-size: var(--fs-13); display: flex; flex-direction: column; gap: 4px; }
.tool-detail-k { font-size: var(--fs-11); color: var(--text-3); margin-top: var(--sp-2); }
.tool-detail pre {
  margin: 0; white-space: pre-wrap; word-break: break-word; font-size: var(--fs-12);
  background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-2);
}

/* MCP app 的「试用」页（apps/mcp/ServersPage.js 的 ToolPage） */
.mcp-tool { display: flex; flex-direction: column; gap: var(--sp-2); }
.mcp-tool-meta { font-size: var(--fs-12); color: var(--text-3); }
.mcp-tool-desc { font-size: var(--fs-14); line-height: 1.6; }
.mcp-tool-k { font-size: var(--fs-11); color: var(--text-3); margin-top: var(--sp-3); }
.mcp-pre {
  margin: 0; white-space: pre-wrap; word-break: break-word; font-size: var(--fs-12);
  background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-2);
}
.mcp-pre.is-error { color: var(--danger); }


/* 管理页：刚生成的账号与密码，整段可选中复制 */
.acct-out { font-size: var(--fs-13); line-height: 1.8; white-space: pre-wrap; word-break: break-all;
  background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-3); margin: var(--sp-3) 0;
  max-height: 320px; overflow-y: auto; }

/* 自己的动态：请角色评论 */
.mo-ask { padding: var(--sp-3) 0; border-top: 1px solid var(--border); margin-top: var(--sp-2); }
.mo-ask-title { font-size: var(--fs-13); color: var(--text); font-weight: var(--fw-medium); }
.mo-ask-desc { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; margin: var(--sp-1) 0 var(--sp-2); }

/* 发布动态：谁可以看 */
.mo-vis { margin: var(--sp-3) 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.mo-vis-title { font-size: var(--fs-13); color: var(--text-2); }
.mo-vis-desc { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }

/* ---- 聊天背景与上下栏（system/chatlook.js，ARCHITECTURE 4.198）----
   值由会话页以 --ph-* 挂在 .page 上；没设过的那一栏不挂类名，保持应用本来的样子。
   背景画在整页上（顶栏、输入栏底下也是它），遮罩朝当前主题的底色淡过去，
   浅色主题上是一层白、深色主题上是一层黑，气泡外那些灰字都还看得清 */
.page:where(.has-chat-bg) {
  background:
    linear-gradient(color-mix(in srgb, var(--bg) var(--ph-chat-veil, 0%), transparent),
                    color-mix(in srgb, var(--bg) var(--ph-chat-veil, 0%), transparent)),
    var(--ph-chat-bg, none) center / cover no-repeat,
    var(--bg);
}
/* 压在图上、不在气泡里的那几行字，垫一块底 */
:where(.has-chat-bg) .time-sep,
:where(.has-chat-bg) .conv-hint,
:where(.has-chat-bg) .conv-notice {
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  border-radius: var(--r-full); padding-inline: var(--sp-3);
}
:where(.has-chat-bg) .conv-notice {
  width: fit-content; max-width: 86%; margin-inline: auto; border-radius: var(--r-md);
}

/* 上下两栏。下面那一栏是输入框连同压在它上面的那几条（引用、待办、表情联想、@ 成员）
   以及展开的面板、多选栏 —— 看上去是同一块，一起换 */
:where(.page.look-top) > .navbar {
  background: var(--ph-bar-top, var(--bg));
  -webkit-backdrop-filter: blur(var(--ph-bar-top-blur, 0px));
  backdrop-filter: blur(var(--ph-bar-top-blur, 0px));
}
:where(.page.look-bottom) :is(.composer-bar, .composer-panel, .select-bar, .quote-bar,
                      .todo-bar, .stk-suggest, .mention-bar) {
  background: var(--ph-bar-bottom, var(--bg));
  -webkit-backdrop-filter: blur(var(--ph-bar-bottom-blur, 0px));
  backdrop-filter: blur(var(--ph-bar-bottom-blur, 0px));
}
/* 切换条那一行透明，只有标签本身跟底栏同色（4.506） */
:where(.page.look-bottom) .composer-tabs { --tab-on: var(--ph-bar-bottom, var(--bg)); }
:where(.page.look-bottom) .composer-tab::before {
  -webkit-backdrop-filter: blur(var(--ph-bar-bottom-blur, 0px)); backdrop-filter: blur(var(--ph-bar-bottom-blur, 0px));
}
/* 字色。深色的栏配浅字：栏里用到的几档字色与输入框底色就地换掉，
   里面的元素照旧读 --text 那几个，不必一个个改 */
:where(.page.look-top-light) > .navbar,
:where(.page.look-bottom-light) :is(.composer-bar, .composer-panel, .select-bar, .quote-bar,
                            .todo-bar, .stk-suggest, .mention-bar, .composer-tabs) {
  --text: var(--on-scrim);
  --text-2: color-mix(in srgb, var(--on-scrim) 78%, transparent);
  --text-3: color-mix(in srgb, var(--on-scrim) 58%, transparent);
  --surface-2: color-mix(in srgb, var(--on-scrim) 14%, transparent);
  --border: color-mix(in srgb, var(--on-scrim) 22%, transparent);
  color: var(--text);
}
:where(.page.look-top-dark) > .navbar,
:where(.page.look-bottom-dark) :is(.composer-bar, .composer-panel, .select-bar, .quote-bar,
                           .todo-bar, .stk-suggest, .mention-bar, .composer-tabs) {
  --text: var(--on-scrim-fill);
  --text-2: color-mix(in srgb, var(--on-scrim-fill) 72%, transparent);
  --text-3: color-mix(in srgb, var(--on-scrim-fill) 50%, transparent);
  --surface-2: color-mix(in srgb, var(--on-scrim-fill) 6%, transparent);
  --border: color-mix(in srgb, var(--on-scrim-fill) 14%, transparent);
  color: var(--text);
}

/* 调节面板 */
.look-colors { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) var(--sp-3); }
.look-color {
  width: 30px; height: 30px; border-radius: var(--r-full);
  border: 1px solid var(--border-2); background: var(--c, var(--bg));
  position: relative;
}
.look-color.is-on { outline: 2px solid var(--accent); outline-offset: 2px; }
.look-color.is-theme::after {
  content: ''; position: absolute; inset: 6px; border-radius: var(--r-full);
  border: 1px dashed var(--text-3);
}
.look-color input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.look-bg {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
}
.look-bg-thumb {
  width: 56px; height: 84px; flex: none; border-radius: var(--r-sm);
  background: var(--surface-2) center / cover no-repeat; background-image: var(--thumb, none);
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.look-bg-acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* 一组列表里，某一行下面自己带一排东西（颜色块）时的那行小标题 */
.list-sub-title { font-size: var(--fs-14); padding: var(--sp-3) var(--sp-4) 0; }

/* 输入栏那一组（会话页底部）。平时就是按顺序叠着，和从前一样 */
.conv-foot { flex: none; display: flex; flex-direction: column; }

/* ---- 栏浮在消息列表上（聊天背景里栏不是实色，system/chatlook.js）----
   消息从栏底下滚过去，半透明、毛玻璃才透得出东西。
   顶栏高度是定的，直接算；输入栏那一组会变高，会话页量出来挂成 --foot-h */
:where(.page.float-top) > .navbar {
  position: relative; z-index: 3;
  margin-bottom: calc(-1 * (var(--navbar-h) + var(--top-inset)));
}
/* 会话顶上那几条（一起听、一起看、节奏）浮在顶栏下沿，列表一直伸到顶栏底下 */
:where(.page.float-top) .conv { padding-top: calc(var(--navbar-h) + var(--top-inset)); }
:where(.page.float-top .conv) > .conv-main:where(:first-child) { margin-top: calc(-1 * (var(--navbar-h) + var(--top-inset))); }
:where(.page.float-top .conv) > .conv-main:where(:first-child) > .conv-body {
  /* 浮着的顶栏（连状态栏那一条）与会话顶上那几条一共多高。美化生成器「第一条与顶部的距离」在它下面另算（4.781） */
  --float-top: calc(var(--navbar-h) + var(--top-inset) + var(--strips-h, 0px));
  padding-top: calc(var(--float-top) + var(--sp-4));
}
:where(.page.float-top .conv) > .conv-main:where(:first-child) > .conv-strips { top: calc(var(--navbar-h) + var(--top-inset)); }
:where(.page.float-bottom) .conv-foot {
  position: relative; z-index: 3;
  margin-top: calc(-1 * var(--foot-h, 0px));
}
:where(.page.float-bottom) .conv-body { --float-bottom: var(--foot-h, 0px); padding-bottom: calc(var(--foot-h, 0px) + var(--sp-4)); }
:where(.page.float-bottom) .to-bottom { bottom: calc(var(--foot-h, 0px) + var(--sp-3)); }

/* 「消息 旁白」两个标签叠在消息列表的底边上，不另占一行（4.516）。
   从前它在输入栏那一组里、消息列表的下面，后面透出来的是页面本身的底色：美化只给消息列表涂了颜色时，
   标签那一行是一整条白（用户反馈）。现在它后面就是消息列表，涂的什么就露出什么。
   列表底下多留出标签的高度，最后一条不被挡住。标签上面压着待办、引用那几条时照旧排在它们下面 */
.conv-foot { position: relative; }
.composer-tabs:where(:first-child) { position: absolute; left: 0; right: 0; bottom: calc(100% - 1px); margin-bottom: 0; pointer-events: none; }
:where(.composer-tabs) .composer-tab { pointer-events: auto; }
:where(.conv:has(.conv-foot > .composer-tabs:first-child)) .conv-body { padding-bottom: calc(var(--sp-4) + 28px); }
:where(.page.float-bottom .conv:has(.conv-foot > .composer-tabs:first-child)) .conv-body {
  padding-bottom: calc(var(--foot-h, 0px) + var(--sp-4) + 28px);
}

/* ---- 角色卡展示页：拍立得（chat/pages/CharCard.js）----
   相纸是 --surface，深色主题下跟着变深。微微斜一点，像随手放在桌上的一张 */
.pola-stage { display: flex; justify-content: center; padding: var(--sp-6) var(--sp-5) var(--sp-4); }
.pola {
  width: 78%; max-width: 320px; display: block; text-align: center;
  background: var(--surface); border: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-3) 0; border-radius: var(--r-xs);
  box-shadow: var(--shadow-3); transform: rotate(-2deg);
}
.pola-photo {
  aspect-ratio: 4 / 5; width: 100%;
  background: var(--surface-2) center / cover no-repeat; background-image: var(--pola, none);
  display: flex; align-items: center; justify-content: center;
}
.pola-hint { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); color: var(--text-3); font-size: var(--fs-13); }
.pola-foot { padding: var(--sp-4) var(--sp-2) var(--sp-5); }
/* 个性签名用手写体放大写在白边上；下面一行小小的 @名字，像照片背后顺手签的名 */
.pola-sign { font-family: var(--font-hand); font-size: var(--fs-24); color: var(--text); line-height: 1.35; word-break: break-word; }
.pola-at { font-size: var(--fs-11); color: var(--text-3); margin-top: var(--sp-2); text-align: right; letter-spacing: .5px; }
.hand-sample { font-family: var(--hand), var(--font-hand-base); font-size: var(--fs-20); color: var(--text); }

/* 朋友圈评论表：输入框在最上面（MomentBits.js 的 CommentSheet），键盘只盖得住下半截 */
.mo-comment-input { padding: 0 0 var(--sp-3); border-bottom: 1px solid var(--border); }
/* 回复某条评论时，输入框上面一行写明回复谁（4.538） */
.mo-reply-to { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  font-size: var(--fs-12); color: var(--text-2); padding: var(--sp-1) 0; }
.mo-edit-input { width: 100%; min-height: 140px; resize: vertical; }
.mo-comment-list { padding-top: var(--sp-3); }

/* 角色撤回的动态：折成一行，点开是原来那张卡片，压淡、不收赞与评论（ARCHITECTURE 4.207） */
.mo-recalled { border-bottom: 1px solid var(--border); background: var(--surface); }
.mo-recalled-line {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4); font-size: var(--fs-12); color: var(--text-3);
}
.mo-recalled .mo-card { border-bottom: none; }
.mo-card.is-gone { opacity: .6; }
.mo-gone-note { padding: var(--sp-2) var(--sp-4); font-size: var(--fs-12); color: var(--text-3); }

/* 换图标那张表里的两个开关（ui/iconpicker.js） */
.icon-switch { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0; }
.icon-switch-text { flex: 1; min-width: 0; }
.icon-switch-text .field-desc { margin-top: 2px; }

/* ---- 衣帽间（apps/closet，ARCHITECTURE 4.213） ---- */
.cl-owners { display: flex; gap: var(--sp-2); overflow-x: auto; padding: var(--sp-3) var(--sp-4) var(--sp-2); }
.cl-owners::-webkit-scrollbar { display: none; }
.cl-owner {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: 4px var(--sp-3) 4px 4px; border-radius: var(--r-full);
  background: var(--surface-2); font-size: var(--fs-13); color: var(--text-2);
}
.cl-owner.is-active { background: var(--accent); color: var(--on-accent); }

.cl-strip {
  margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-1);
}
.cl-strip.is-warn { background: var(--danger-weak); box-shadow: none; }
.cl-strip-head { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-14); }
.cl-strip-row { display: flex; gap: var(--sp-2); overflow-x: auto; margin-top: var(--sp-2); }
.cl-strip-row::-webkit-scrollbar { display: none; }
.cl-strip-item { flex: none; width: 64px; display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-11); color: var(--text-2); }
.cl-strip-empty { margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); line-height: 1.6; }
.cl-alert { width: 100%; display: flex; align-items: baseline; gap: var(--sp-2); padding: var(--sp-2) 0 0; font-size: var(--fs-13); text-align: left; }
.cl-alert span { flex: 1; min-width: 0; }
.cl-alert em { flex: none; font-style: normal; font-size: var(--fs-12); color: var(--danger); }

.cl-unsorted {
  display: flex; align-items: center; gap: var(--sp-2); width: calc(100% - var(--sp-8));
  margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-3); border-radius: var(--r-lg);
  border: 1px dashed var(--border-2); font-size: var(--fs-13); text-align: left;
}
.cl-unsorted em { margin-left: auto; font-style: normal; font-size: var(--fs-12); color: var(--text-3); }

/* 三列：九个大类一屏看全，这是「总览」这一层的意义 */
.cl-groups { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.cl-group { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2); border-radius: var(--r-lg); background: var(--surface); box-shadow: var(--shadow-1); text-align: left; min-width: 0; }
.cl-group.is-empty { opacity: .6; }
/* 大类卡片上拼几张：一件铺满，两件左右各半，三四件四宫格 */
.cl-mosaic {
  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 2px;
  aspect-ratio: 1; border-radius: var(--r-md); overflow: hidden; background: var(--surface-2); position: relative;
}
.cl-mosaic .cl-thumb, .cl-mosaic .cl-blank { border-radius: 0; aspect-ratio: auto; height: 100%; box-shadow: none; }
.cl-mosaic.n1 > * { grid-column: 1 / -1; grid-row: 1 / -1; }
.cl-mosaic.n2 > * { grid-row: 1 / -1; }
.cl-mosaic-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-3); }
.cl-group-foot { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); padding: 0 var(--sp-1); font-size: var(--fs-13); min-width: 0; }
/* 搭配名再长也收成省略号，件数照旧贴在右边（4.c158-10） */
.cl-group-foot b { min-width: 0; }
.cl-group-foot span { font-size: var(--fs-12); color: var(--text-3); flex: none; }
.cl-all {
  display: flex; align-items: center; justify-content: space-between; width: calc(100% - var(--sp-8));
  margin: 0 var(--sp-4) var(--sp-4); padding: var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface); font-size: var(--fs-14);
}

.cl-thumb, .cl-blank { width: 100%; aspect-ratio: 1; border-radius: var(--r-md); }
.cl-thumb { background: var(--img) center / cover no-repeat, var(--surface-2); }
.cl-blank { background: var(--sw, var(--surface-2)); box-shadow: inset 0 0 0 1px var(--border); }
.cl-blank.is-empty { display: flex; align-items: center; justify-content: center; color: var(--text-3); }
.cl-photo { margin: var(--sp-3) var(--sp-4); aspect-ratio: 1; border-radius: var(--r-lg); background: var(--img) center / contain no-repeat, var(--surface-2); overflow: hidden; }
.cl-photo.is-blank .cl-blank { height: 100%; border-radius: 0; }

.cl-subs { display: flex; gap: var(--sp-2); overflow-x: auto; padding: var(--sp-3) var(--sp-4) 0; }
.cl-subs::-webkit-scrollbar { display: none; }
.cl-subs .chip { flex: none; }
.cl-search { padding-top: var(--sp-3); padding-bottom: var(--sp-2); }

.cl-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) var(--sp-5); }
.cl-card { position: relative; display: flex; flex-direction: column; gap: 4px; min-width: 0; text-align: left; }
.cl-card.is-gone { opacity: .45; }
.cl-card-name { font-size: var(--fs-12); color: var(--text); }
.cl-card-marks { position: absolute; top: 4px; right: 4px; display: flex; gap: 3px; }
.cl-mark {
  width: 18px; height: 18px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--text-2); box-shadow: var(--shadow-1);
}
.cl-mark.is-on { background: var(--accent); color: var(--on-accent); }
.cl-mark.is-warn { color: var(--danger); }
.cl-meter { height: 3px; border-radius: var(--r-full); background: var(--surface-3); overflow: hidden; }
.cl-meter i { display: block; height: 100%; width: var(--pct, 0%); background: var(--accent); }
.cl-meter.is-big { height: 6px; margin-bottom: var(--sp-2); }

.cl-sw { display: inline-block; flex: none; width: 12px; height: 12px; border-radius: var(--r-full); background: var(--sw); border: 1px solid var(--border); margin-right: 4px; vertical-align: -1px; }
.cl-filter-label { padding: var(--sp-3) 0 0; font-size: var(--fs-12); color: var(--text-3); }
.cl-switch-row { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-14); }

.cl-acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-2); }
/* 单品页的表单。Field 自己不带左右留白，整段收在这里 */
.cl-form { padding: 0 var(--sp-4); }
.cl-form .cl-readout { margin: 0 0 var(--sp-3); }
.cl-row-btn { padding-bottom: var(--sp-3); }
.cl-section { padding: var(--sp-5) 0 var(--sp-1); font-size: var(--fs-12); color: var(--text-3); letter-spacing: .5px; }
/* 衣帽间单品页：次数加减、穿着记录的日期、日期框加按钮一行（4.344） */
.cl-stepper { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.cl-stepper button { width: 40px; height: 36px; display: flex; align-items: center; justify-content: center; color: var(--text-2); background: var(--surface-2); }
.cl-stepper button:disabled { opacity: .35; }
.cl-stepper span { min-width: 52px; text-align: center; font-size: var(--fs-15); font-weight: var(--fw-semi); }
.cl-dates { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.cl-date { font-size: var(--fs-12); padding: 4px 9px; border-radius: var(--r-sm); border: 1px solid var(--border); color: var(--text-2); }
.cl-inline { display: flex; gap: var(--sp-2); align-items: center; }
/* 衣帽间统计（4.344 第二步） */
.cl-stat-head { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); padding: var(--sp-3) var(--sp-4) var(--sp-1); }
.cl-stat-head > div { background: var(--surface-2); border-radius: var(--r-md); padding: var(--sp-3); display: flex; flex-direction: column; gap: 2px; }
.cl-stat-head b { font-size: var(--fs-20); font-weight: var(--fw-semi); color: var(--text); }
.cl-stat-head span { font-size: var(--fs-12); color: var(--text-3); }
.cl-stat-bar { padding: var(--sp-2) var(--sp-4); }
.cl-stat-bar-top { display: flex; justify-content: space-between; font-size: var(--fs-14); margin-bottom: 6px; }
.cl-stat-bar-top em { font-style: normal; color: var(--text-3); font-size: var(--fs-12); }
.cl-stat-thumb { width: 36px; height: 36px; border-radius: var(--r-sm); overflow: hidden; display: block; flex: none; }
.cl-all-sub { flex: 1; font-style: normal; font-size: var(--fs-12); color: var(--text-3); text-align: right; margin-right: var(--sp-1); }
.cl-inline input { flex: 1; min-width: 0; }
.cl-inline { display: flex; align-items: center; gap: var(--sp-3); }
.cl-inline .segmented { flex: 1; }
.cl-readout { margin: 0 var(--sp-4) var(--sp-3); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); font-size: var(--fs-13); line-height: 1.6; }

.cl-add-ways { display: flex; flex-direction: column; gap: var(--sp-3); }
.cl-add-way {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--sp-3); row-gap: 2px; align-items: center;
  padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); text-align: left;
}
.cl-add-way svg { grid-row: span 2; }
.cl-add-way b { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.cl-add-way span { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }

.cl-today-group { padding-bottom: var(--sp-2); }
.cl-today-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); margin-top: var(--sp-2); }
.cl-today-pick { position: relative; display: flex; flex-direction: column; gap: 3px; min-width: 0; font-size: var(--fs-11); color: var(--text-2); }
.cl-today-pick.is-on .cl-thumb, .cl-today-pick.is-on .cl-blank { outline: 2px solid var(--accent); outline-offset: -2px; }
.cl-tick {
  position: absolute; top: 4px; right: 4px; width: 18px; height: 18px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center; background: var(--accent); color: var(--on-accent);
}
.cl-sub-edit { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-3); }
.cl-sub-edit .chip { display: inline-flex; align-items: center; gap: 4px; }
/* 会话里的搭配卡片（OutfitBits.js）。一行四件，多了换行 */
.bubble-outfit { min-width: 200px; max-width: 260px; padding: var(--sp-3) var(--sp-4) 0; }
.bubble-outfit .tr-top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.bubble-outfit .tr-body { min-width: 0; }
.fit-tag { font-size: var(--fs-12); opacity: .7; }
.fit-name { font-size: var(--fs-15); font-weight: var(--fw-medium); margin-top: 2px; }
.fit-pieces { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.fit-piece { flex: none; width: 48px; display: flex; flex-direction: column; gap: 3px; font-size: var(--fs-11); }
.fit-piece.is-miss { opacity: .5; }
.fit-img {
  width: 48px; height: 48px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center;
  background: var(--img) center / cover no-repeat, var(--surface-2); color: var(--text-3);
}
.fit-img.is-blank { background: var(--sw, var(--surface-2)); box-shadow: inset 0 0 0 1px var(--border); }
/* 「今天穿的」右上角那两个按钮 */
.cl-strip-acts { display: flex; gap: var(--sp-4); }
/* 穿搭盲盒揭晓后「我为对方挑的」那一行；动作卡片左边那一件东西 */
.fit-sub { margin-top: var(--sp-3); font-size: var(--fs-12); opacity: .7; }
.bubble-outfit .tr-top .fit-piece { width: 40px; }
.bubble-outfit .tr-top .fit-img { width: 40px; height: 40px; }
.ph-dresscode.is-done { opacity: .75; }
/* 衣帽间的分享卡片（ui/sharecard.js，4.344）。宽一些、短一些：照片 4:3 内嵌，名称、想说的话、勾选的几项三层字重 */
.share-card {
  width: 272px; max-width: 100%; box-sizing: border-box; padding: var(--sp-2) var(--sp-2) var(--sp-3);
  border-radius: var(--r-xl); background: var(--surface); border: 1px solid var(--border); color: var(--text); text-align: left;
}
.share-card-img {
  display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3; border-radius: var(--r-lg);
  background: var(--img) center / cover no-repeat, var(--surface-2); color: var(--text-3);
}
.share-card-top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); padding: 10px 6px 0; }
.share-card-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-15); font-weight: var(--fw-semi); }
.share-card-tag { flex: none; display: inline-flex; align-items: center; gap: 3px; font-size: var(--fs-11); color: var(--text-3); }
.share-card-note { padding: var(--sp-1) 6px 0; font-size: var(--fs-14); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.share-card-meta { padding: 5px 6px 0; font-size: var(--fs-12); line-height: 1.55; color: var(--text-2); overflow-wrap: anywhere; }
/* 发送面板：预览、勾选项（选中是实心，这一件没填的是虚线框）、底下一行说明 */
.share-preview { display: flex; justify-content: center; margin: var(--sp-3) 0 var(--sp-2); padding: var(--sp-4) var(--sp-3); border-radius: var(--r-xl); background: var(--surface-2); }
.share-chip { display: inline-flex; align-items: center; gap: 4px; }
.share-chip.is-active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.share-chip:disabled { background: transparent; color: var(--text-3); border: 1px dashed var(--border-2); }
.share-fine { text-align: center; }
/* 单品页：借出那一行、回忆 */
.cl-loan { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-14); padding-bottom: var(--sp-2); }
.cl-mems { display: flex; flex-direction: column; gap: var(--sp-2); padding-bottom: var(--sp-3); }
.cl-mem { padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface-2); }
.cl-mem-head .nav-text { font-size: var(--fs-12); }
.cl-mem-head { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-12); color: var(--text-3); }
.cl-mem-head span { margin-right: auto; }
.cl-mem p { margin: var(--sp-1) 0 0; font-size: var(--fs-14); line-height: 1.55; }
/* 记到衣帽间：一行一件，左边缩略图 */
.cl-pick-row { align-items: center; box-shadow: none; }
.cl-pick-thumb { width: 44px; flex: none; }
/* 套装格子下面「谁搭配的」那一行 */
.cl-fit-by { padding: 0 var(--sp-1); margin-top: calc(var(--sp-2) * -1); font-size: var(--fs-11); color: var(--text-3); }
/* 按角色设定生成的结果：一行一件，点一下取消勾选 */
.cl-gen { display: flex; flex-direction: column; gap: var(--sp-2); padding: 0 var(--sp-4); }
.cl-gen-row {
  position: relative; display: flex; gap: var(--sp-3); padding: var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface); text-align: left; opacity: .5;
}
.cl-gen-row.is-on { opacity: 1; box-shadow: inset 0 0 0 1.5px var(--accent); }
.cl-gen-row .cl-tick { position: static; flex: none; }
.cl-gen-row:not(.is-on) .cl-tick { background: var(--surface-2); color: var(--text-3); }
.cl-gen-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: var(--fs-13); }
.cl-gen-body span { font-size: var(--fs-12); color: var(--text-3); }
.cl-gen-body em { font-style: normal; font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; }
/* 礼物气泡上的「收进衣帽间」（TransferBits.js 的 GiftBubble） */
.gift-closet, .gift-collect { margin-left: var(--sp-2); font-size: var(--fs-11); color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* 一起听页里的网易云搜索（chat/pages/ListenPage.js） */
.ls-search { padding-bottom: var(--sp-2); }
.ls-wait { display: flex; justify-content: center; padding: var(--sp-4) 0; }
.ls-hint { font-size: var(--fs-12); color: var(--text-3); }

/* 线上旁白（Conversation.js，ARCHITECTURE 4.221）。夹在消息中间的一行小字，没有气泡。
   颜色走 --ph-narration-color（会话「聊天背景」里改，美化作者也可以写）；
   有聊天背景图时加一层淡阴影，换了壁纸也读得清 */
/* 字号、名字颜色也走公开变量（4.648），美化生成器的「旁白」一组与作者手写的 CSS 都改这几个 */
.msg-narration {
  max-width: 86%; margin: var(--sp-2) auto; padding: 0 var(--sp-2);
  text-align: center; font-size: var(--ph-narration-fs, var(--fs-13)); line-height: 1.65; white-space: pre-wrap;
  color: var(--ph-narration-color, var(--text-3));
}
/* 群聊里旁白前面的名字（4.648）：默认按成员轮着配一种颜色（--ph-narration-auto），一眼分得清是谁写的 */
.narration-name { font-weight: 600; color: var(--ph-narration-name-color, var(--ph-narration-auto, inherit)); }
:where(.narr-c1) { --ph-narration-auto: var(--narr-p1); }
:where(.narr-c2) { --ph-narration-auto: var(--narr-p2); }
:where(.narr-c3) { --ph-narration-auto: var(--narr-p3); }
:where(.narr-c4) { --ph-narration-auto: var(--narr-p4); }
:where(.narr-c5) { --ph-narration-auto: var(--narr-p5); }
:where(.narr-c6) { --ph-narration-auto: var(--narr-p6); }
:where(.narr-c7) { --ph-narration-auto: var(--narr-p7); }
:where(.narr-c8) { --ph-narration-auto: var(--narr-p8); }
:where(.narr-cme) { --ph-narration-auto: var(--text-2); }
:where(.has-chat-bg) .msg-narration { text-shadow: 0 0 6px var(--bg), 0 0 2px var(--bg); }

/* 场外的问与答（Conversation.js，ARCHITECTURE 4.819）。不是剧情里的话：虚线框的一块，标明「场外」，不画头像与气泡 */
.msg-ooc {
  margin: var(--sp-2) var(--sp-3); padding: var(--sp-2) var(--sp-3);
  border: 1px dashed var(--border-2); border-radius: var(--r-md); background: var(--surface);
  font-size: var(--fs-13); line-height: 1.65; color: var(--text);
}
.msg-ooc.is-mine { margin-left: 18%; }
.msg-ooc:not(.is-mine) { margin-right: 6%; }
.msg-ooc.is-picked { box-shadow: inset 0 0 0 2px var(--accent); }
.ooc-tag { font-size: var(--fs-11); color: var(--text-3); margin-bottom: var(--sp-1); letter-spacing: .04em; }
.ooc-text { white-space: pre-wrap; word-break: break-word; }
.ooc-text .md { white-space: normal; }
/* 自动检查的结果：一轮最后一条下面一行小字，点开看逐条与操作 */
.ooc-check { margin: var(--sp-1) var(--sp-3) var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.ooc-check.is-failed { color: var(--text-3); }
.ooc-check-head { background: none; border: 0; padding: 0; color: inherit; font: inherit; text-align: left; text-decoration: underline dotted; text-underline-offset: 3px; }
.ooc-check-list { margin-top: var(--sp-2); display: grid; gap: var(--sp-2); }
.ooc-issue { padding: var(--sp-2); border-radius: var(--r-sm); background: var(--surface-2); line-height: 1.6; }
.ooc-k { display: inline-block; min-width: 3.5em; color: var(--text-3); margin-right: var(--sp-1); }
.ooc-check-acts { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
/* 多选时被选中的旁白（4.343）：换成强调色。状态类包进 :where，不压美化钩子（第 18 条） */
.msg-narration:where(.is-picked) { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

/* 世界书批量导入：每本一块，不导入的那本变淡 */
.lb-draft { margin-bottom: var(--sp-4); }
.lb-draft.is-off { opacity: .55; }

/* ---- 工具箱（apps/tools） ---- */
.tb-out-wrap {
  border-radius: var(--r-md); background: var(--surface-2);
  margin-bottom: var(--sp-4); overflow: hidden;
}
.tb-out-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-12); color: var(--text-2);
  border-bottom: 1px solid var(--border);
}
.tb-out-copy {
  display: inline-flex; align-items: center; gap: 4px; border: 0; background: none;
  color: var(--accent); font-size: var(--fs-12);
}
.tb-out {
  padding: var(--sp-3); font-size: var(--fs-14); line-height: 1.7; color: var(--text);
  white-space: pre-wrap; word-break: break-word; user-select: text; -webkit-user-select: text;
}
.tb-out-plain { background: var(--surface-2); border-radius: var(--r-md); margin: 0 var(--sp-4); }
.tb-out-acts { padding: 0 var(--sp-3) var(--sp-3); }
.tb-code-view, .tb-code {
  font-family: var(--font-mono); font-size: var(--fs-11); line-height: 1.55;
}
.tb-code-view { background: var(--surface-2); border-radius: var(--r-md); word-break: break-all; }
.tb-ask { background: var(--surface-2); border-radius: var(--r-md); font-size: var(--fs-13); max-height: 240px; overflow: auto; }
.tb-call { font-size: var(--fs-11); color: var(--text-3); text-align: center; margin-top: var(--sp-2); }
.tb-icons { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.tb-icon {
  width: 40px; height: 40px; border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-2); display: inline-flex;
  align-items: center; justify-content: center;
}
.tb-icon.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-weak); }
.tb-input-row {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2);
  margin-bottom: var(--sp-3);
}
.tb-input-head { display: flex; align-items: center; gap: var(--sp-2); }
.tb-input-head input { flex: 1; min-width: 0; }
.tb-pick {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-3); border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: var(--fs-14); text-align: left;
}
.tb-bar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); font-size: var(--fs-11); color: var(--text-2);
  background: var(--surface-2); border-bottom: 1px solid var(--border);
}
.tb-bar-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-bar-count { color: var(--text); }
.tb-bar-stop {
  border: 0; border-radius: var(--r-xs); padding: 2px var(--sp-2);
  background: var(--danger-weak); color: var(--danger); font-size: var(--fs-11);
}
.tb-frame-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; height: 100%; }
.tb-frame { flex: 1; width: 100%; height: 100%; border: 0; background: var(--surface); display: block; }
.tb-img-check { margin-top: var(--sp-3); text-align: center; }
.tb-img-check img { max-width: 100%; max-height: 220px; border-radius: var(--r-sm); }
.tb-img-check img.is-hidden { display: none; }
.tb-mod-acts { display: inline-flex; gap: var(--sp-3); }
.tb-mod-acts .tb-out-copy:disabled { opacity: .4; }
.tb-tpl { width: 100%; min-height: 320px; }
.tb-chip-x { margin-left: 4px; display: inline-flex; opacity: .6; }
.tb-npc { border-radius: var(--r-md); background: var(--surface-2); margin: 0 var(--sp-4) var(--sp-3); overflow: hidden; }
.tb-npc.is-off { opacity: .45; }
.tb-npc-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3); border-bottom: 1px solid var(--border); }
.tb-npc-name { flex: 1; min-width: 0; font-size: var(--fs-15); font-weight: var(--fw-semi); }
.tb-npc-rel { font-size: var(--fs-12); color: var(--text-2); font-weight: normal; margin-left: var(--sp-2); }
.tb-npc-btn {
  width: 30px; height: 30px; border-radius: var(--r-xs); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-2); display: inline-flex; align-items: center; justify-content: center;
}
.tb-npc-btn.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-weak); }
.tb-npc-meta { padding: var(--sp-2) var(--sp-3) 0; font-size: var(--fs-12); color: var(--text-2); }
.tb-npc-body { padding: var(--sp-2) var(--sp-3) var(--sp-3); font-size: var(--fs-13); line-height: 1.7; white-space: pre-wrap; word-break: break-word; user-select: text; -webkit-user-select: text; }
.tb-detail { padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); margin-bottom: var(--sp-3); }
.tb-detail-head { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-13); font-weight: var(--fw-semi); margin-bottom: var(--sp-2); }
.tb-add-row { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.tb-add-row input { flex: 1; min-width: 0; }
.chip.is-neg.is-active { background: var(--danger-weak); color: var(--danger); border-color: var(--danger); }
.tb-neg-desc { margin: calc(var(--sp-2) * -1) 0 var(--sp-4); }
.tb-st { font-size: var(--fs-11); padding: 2px var(--sp-2); border-radius: var(--r-xs); background: var(--surface-2); color: var(--text-2); white-space: nowrap; }
.tb-st-pass { color: var(--accent); }
.tb-st-fail { background: var(--danger-weak); color: var(--danger); }
.tb-st-warn { color: var(--text); background: var(--surface-3); }

/* ---- 工具箱首页：应用商店的排法 ---- */
.tb-store { padding-bottom: var(--sp-6); }
.tb-search {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-2) var(--sp-4) 0; padding: 0 var(--sp-3);
  border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-3);
}
.tb-search input { flex: 1; min-width: 0; border: 0; background: none; padding: var(--sp-2) 0; }
.tb-tags { display: flex; gap: var(--sp-2); overflow-x: auto; padding: var(--sp-3) var(--sp-4) 0; }
.tb-tags .chip { flex: none; }
.tb-hero-row {
  display: flex; gap: var(--sp-3); overflow-x: auto; scroll-snap-type: x mandatory;
  padding: var(--sp-4) var(--sp-4) var(--sp-2); scroll-padding: 0 var(--sp-4);
}
.tb-hero {
  flex: none; width: 78%; scroll-snap-align: start;
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface-2); border: 1px solid var(--border);
}
.tb-hero-top { display: flex; align-items: flex-start; justify-content: space-between; }
.tb-hero-tag { font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; }
.tb-hero-icon {
  width: 56px; height: 56px; border-radius: var(--r-md); background: var(--surface);
  color: var(--text); display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border);
}
.tb-hero-name { font-size: var(--fs-20); font-weight: var(--fw-semi); color: var(--text); }
.tb-hero-desc {
  font-size: var(--fs-13); color: var(--text-2); line-height: 1.55; min-height: calc(1.55em * 2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tb-hero-foot {
  display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-1);
  font-size: var(--fs-12); color: var(--text-3);
}
.tb-sec { margin-top: var(--sp-4); }
.tb-sec-head {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding: 0 var(--sp-4) var(--sp-1); font-size: var(--fs-17); font-weight: var(--fw-semi); color: var(--text);
}
.tb-sec-n { font-size: var(--fs-12); font-weight: normal; color: var(--text-3); }
.tb-app, .tb-add {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); position: relative;
}
.tb-app + .tb-app::before, .tb-app + .tb-add::before {
  content: ''; position: absolute; top: 0; right: var(--sp-4); left: calc(var(--sp-4) + 52px + var(--sp-3));
  border-top: 1px solid var(--border);
}
.tb-app-icon {
  flex: none; width: 52px; height: 52px; border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
}
.tb-add .tb-app-icon { border-style: dashed; color: var(--text-3); background: none; }
.tb-app-body { flex: 1; min-width: 0; }
.tb-app-name { font-size: var(--fs-15); font-weight: var(--fw-semi); color: var(--text); }
.tb-app-desc {
  font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; margin-top: 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tb-app-meta { font-size: var(--fs-11); color: var(--text-3); margin-top: 2px; }
.tb-get {
  flex: none; border: 0; border-radius: var(--r-full); padding: var(--sp-1) var(--sp-4);
  background: var(--surface-2); color: var(--accent); font-size: var(--fs-13); font-weight: var(--fw-semi);
}
.tb-hero .tb-get { background: var(--surface); }

/* 世界观生成器：每个模块一张可展开的卡片，里面按小类列标签 */
.tb-wmod { border-radius: var(--r-md); background: var(--surface-2); margin-bottom: var(--sp-3); overflow: hidden; }
.tb-wmod.is-off .tb-wmod-head { opacity: .5; }
.tb-wmod-head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); color: var(--text-3); }
.tb-wmod-title { flex: 1; min-width: 0; }
.tb-wmod-body { padding: 0 var(--sp-4) var(--sp-4); border-top: 1px solid var(--border); padding-top: var(--sp-3); }
.tb-wmod-body .chip:not(.is-active), .tb-wmod-body input, .tb-wmod-body textarea { background: var(--surface); }

/* ---- 图床（apps/tools/ImgHost.js） ---- */
.ih-step { display: flex; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.ih-step-n {
  flex: none; width: 26px; height: 26px; border-radius: var(--r-full); background: var(--surface-2);
  color: var(--text); font-size: var(--fs-13); font-weight: var(--fw-semi);
  display: flex; align-items: center; justify-content: center; border: 1px solid var(--border);
}
.ih-step-body { flex: 1; min-width: 0; }
.ih-step-title { font-size: var(--fs-15); font-weight: var(--fw-semi); color: var(--text); margin-top: 2px; }
.ih-step-text { font-size: var(--fs-13); color: var(--text-2); line-height: 1.65; margin-top: var(--sp-1); }
.ih-links { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0; }
.ih-ext { display: inline-flex; align-items: center; gap: 4px; text-decoration: none; }
.ih-note { margin: var(--sp-2) 0 var(--sp-3); }
.ih-code { margin: var(--sp-2) 0; }
.ih-pre { max-height: 240px; overflow: auto; margin-top: var(--sp-2); }
.ih-switch { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-13); color: var(--text-2); margin-bottom: var(--sp-3); }
.ih-thumb { width: 40px; height: 40px; border-radius: var(--r-xs); object-fit: cover; background: var(--surface-2); }
.ih-row-acts { display: inline-flex; gap: var(--sp-3); }
.ih-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); padding: 0 var(--sp-4); }
.ih-cell { border-radius: var(--r-md); background: var(--surface-2); overflow: hidden; display: flex; flex-direction: column; }
.ih-cell.is-off { opacity: .45; }
.ih-cell-img {
  position: relative; aspect-ratio: 1; background: var(--surface-3); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}
.ih-cell-img img { width: 100%; height: 100%; object-fit: contain; }
.ih-cell-n {
  position: absolute; left: var(--sp-2); top: var(--sp-2); font-size: var(--fs-11);
  padding: 1px var(--sp-2); border-radius: var(--r-xs); background: var(--surface); color: var(--text-2);
}
.ih-cell-on {
  position: absolute; right: var(--sp-2); top: var(--sp-2); width: 20px; height: 20px; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent); display: flex; align-items: center; justify-content: center;
}
.ih-cell-meta, .ih-cell-new, .ih-cell-err { font-size: var(--fs-11); padding: var(--sp-1) var(--sp-2) 0; word-break: break-all; }
.ih-cell-meta { color: var(--text-3); }
.ih-cell-new { color: var(--text-2); }
.ih-cell-err { color: var(--danger); }
.ih-cell-input { margin: var(--sp-2); font-size: var(--fs-11); padding: var(--sp-1) var(--sp-2); }

/* ---- HTML 卡片（ARCHITECTURE 4.250）----
   卡片本身在 iframe 里，样式与应用互不相通。这里只管外面那一圈：细栏、框、全屏。
   宽度由卡片自己的设置给（--hc-w），整行宽的卡片把这一列放宽 */
.hc-card {
  width: var(--hc-w, 270px); max-width: 100%;
  border-radius: var(--r-lg); overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
}
.msg-col:has(.hc-card.is-full) { max-width: calc(100% - 52px); }
.hc-bar {
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-2);
  font-size: var(--fs-11); color: var(--text-3);
  border-bottom: 1px solid var(--border);
}
.hc-bar-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hc-bar-open { font-size: var(--fs-11); color: var(--accent); padding: 0 var(--sp-1); }
.hc-frame { width: 100%; height: var(--hc-h, 200px); }
.hc-frame.is-fluid { height: auto; aspect-ratio: var(--hc-ratio, 3 / 4); }
.hc-frame iframe { display: block; width: 100%; height: 100%; border: 0; background: transparent; }
.hc-note {
  display: flex; align-items: center; justify-content: center; height: 100%;
  padding: var(--sp-3); text-align: center;
  font-size: var(--fs-12); color: var(--text-3);
}
.hc-full { padding: var(--sp-4); }
.hc-full .hc-frame { border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--border); }
.hc-gone { padding: var(--sp-2) var(--sp-3) 0; font-size: var(--fs-11); color: var(--text-3); }
.hc-plain { padding: var(--sp-2) var(--sp-3) var(--sp-3); font-size: var(--fs-13); }
.hc-plain-row { display: flex; gap: var(--sp-2); white-space: pre-wrap; }
.hc-plain-key { flex: none; color: var(--text-3); }
.hc-syntax-toggle { font-size: var(--fs-12); color: var(--accent); padding: var(--sp-2) 0; }
.hc-syntax { display: grid; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.hc-syntax-row { display: grid; gap: 2px; }
.hc-syntax-row code { font-family: var(--font-mono); color: var(--text); }
.hc-field-group { margin-bottom: var(--sp-3); }
.hc-field {
  display: grid; gap: var(--sp-2); padding: var(--sp-3);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.hc-field-sub { margin: var(--sp-2) 0 0 var(--sp-4); }
.hc-field-name { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.hc-field-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.hc-field-k { font-size: var(--fs-13); color: var(--text-2); }
.hc-preview { padding-bottom: var(--sp-4); }
.hint-box.is-warn { background: var(--danger-weak); color: var(--danger); }
.hc-field-kind { padding: var(--sp-2) var(--sp-3) 0; }

/* 会话菜单「上一轮发送的内容」（4.776）：折叠块沿用请求记录那一套（.trace-block），这里只有分组的小标题 */
.sent-label { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }

/* ---- 小剧场（ARCHITECTURE 4.769）----
   聊天里一张暗的封面；点开整页，页面占满，底下一条细栏。页面本身在 iframe 里，与应用的样式互不相通 */
.th-cover {
  display: grid; gap: var(--sp-1); justify-items: start; text-align: left;
  width: 240px; max-width: 100%;
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  border-radius: var(--r-lg); border: 1px solid var(--th-line);
  background: var(--th-curtain); color: var(--th-on);
}
.th-cover-eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-11); letter-spacing: .12em; color: var(--th-on-3);
}
.th-cover-title { font-family: var(--font-serif); font-size: var(--fs-17); line-height: 1.35; }
.th-cover-brief { font-size: var(--fs-13); color: var(--th-on-2); line-height: 1.5; }
.th-cover-foot {
  margin-top: var(--sp-2); padding-top: var(--sp-2); width: 100%;
  border-top: 1px solid var(--th-line); font-size: var(--fs-11); color: var(--th-on-3);
}
.th-sheet .page-body { display: flex; flex-direction: column; }
.th-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.th-stage { flex: 1; min-height: 0; position: relative; background: var(--surface); }
.th-frame { display: block; width: 100%; height: 100%; border: 0; background: transparent; }
.th-stage-note {
  display: flex; align-items: center; justify-content: center; height: 100%;
  padding: var(--sp-4); font-size: var(--fs-13); color: var(--text-3); text-align: center;
}
.th-curtain {
  height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); padding: var(--sp-6); text-align: center;
  background: var(--th-curtain); color: var(--th-on);
}
.th-curtain-title { font-family: var(--font-serif); font-size: var(--fs-24); line-height: 1.3; }
.th-curtain-brief { font-size: var(--fs-14); color: var(--th-on-2); line-height: 1.6; max-width: 300px; }
.th-curtain .btn { color: var(--th-on); border-color: var(--th-line); }
.th-curtain-busy { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-13); color: var(--th-on-2); }
.th-curtain-cost { font-size: var(--fs-11); color: var(--th-on-3); }
.th-curtain-err { font-size: var(--fs-12); color: var(--danger); }
.th-old { padding: var(--sp-2) var(--sp-4); font-size: var(--fs-12); color: var(--text-3); background: var(--surface-2); }
.th-bar {
  flex: none; display: grid; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-4) calc(var(--sp-2) + var(--safe-bottom));
  border-top: 1px solid var(--border); background: var(--bg);
}
.th-bar-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.th-bar-row.is-meta { font-size: var(--fs-11); color: var(--text-3); }
.th-bar-label { font-size: var(--fs-13); color: var(--text-2); flex: none; }
.th-bar-clear { font-size: var(--fs-11); color: var(--accent); }
.th-again { display: inline-flex; align-items: center; padding: var(--sp-1); color: var(--text-2); }

/* ---- HTML 卡片生成器（ARCHITECTURE 4.252）---- */
.cg-sec { display: grid; gap: var(--sp-2); padding-bottom: var(--sp-3); }
.cg-group { display: grid; gap: var(--sp-1); }
.cg-group-name { font-size: var(--fs-12); color: var(--text-3); padding-top: var(--sp-1); }
.cg-ref { display: flex; align-items: center; gap: var(--sp-3); }
.cg-ref-img { max-width: 50%; border-radius: var(--r-md); border: 1px solid var(--border); }
.cg-pals { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--sp-2); }
.cg-pal {
  display: grid; gap: var(--sp-1); justify-items: start; padding: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface);
  font-size: var(--fs-12); color: var(--text-2);
}
.cg-pal.is-active { border-color: var(--accent); color: var(--text); }
.cg-sws { display: flex; gap: 3px; }
.cg-sw { width: 14px; height: 14px; border-radius: var(--r-full); background: var(--sw); border: 1px solid var(--border); }
.cg-deco { display: grid; gap: var(--sp-1); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); }
.cg-deco-del { justify-self: start; font-size: var(--fs-12); color: var(--danger); }
.cg-example { text-align: left; white-space: normal; }

/* ---- 悬浮球（ARCHITECTURE 4.256）----
   仿 iOS 辅助触控（用户要求）：半透明深色圆角方块，里面三层同心白圈；点开是屏幕中间一块深色毛玻璃，
   白色图标与白字九宫格。只用黑白两色的半透明，跟深浅色模式无关（iOS 上也是这样）。
   位置由 --qb-x / --qb-y 给（shell/QuickBall.js 每次按当下的屏幕算好、夹回可见区域） */
.qb-ball {
  position: absolute; left: 0; top: 0; z-index: calc(var(--z-sheet) + 5);
  width: var(--qb-size, 56px); height: var(--qb-size, 56px);
  transform: translate(var(--qb-x, 0), var(--qb-y, 0));
  transition: transform var(--dur) var(--ease), opacity var(--dur-slow) var(--ease);
  touch-action: none; user-select: none; -webkit-user-select: none;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 28%;
  background: rgba(0, 0, 0, 0.62);
  -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}
.qb-ball:active { transform: translate(var(--qb-x, 0), var(--qb-y, 0)) scale(0.92); }
.qb-ball:where(.is-dragging) { transition: none; }
.qb-ball:where(.is-idle) { opacity: var(--qb-idle, 0.45); }
.qb-ball:where(.is-placing) { visibility: hidden; }
/* 展开时球「变成」面板，不同时留在屏幕上 */
.qb-ball:where(.is-open) { opacity: 0; pointer-events: none; }
/* 拖动中、编辑外观时当场看得到：浮在面板那层之上，但不接手势 */
.qb-ball:where(.is-preview) { z-index: calc(var(--z-modal) + 1); pointer-events: none; }
/* 用户自己写的 CSS 只作用在这一层里（system/quickball.js 的 scopeCss）。本身不占位置 */
.qb-layer { display: contents; }
/* 换成自己的图：没有底板、没有毛玻璃，图按「边长 × 倍数」居中压在球上，可以比球大（溢出） */
.qb-ball:where(.has-img) { background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; overflow: visible; }
.qb-ball:where(.has-img.has-plate) { background: rgba(0, 0, 0, 0.62); box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22); }
.qb-img {
  position: absolute; left: 50%; top: 50%;
  width: calc(var(--qb-size, 56px) * var(--qb-scale, 1)); height: calc(var(--qb-size, 56px) * var(--qb-scale, 1));
  transform: translate(-50%, -50%);
  background: var(--qb-img) center / contain no-repeat;
}
/* 三层同心圈：最里面实心，外面两圈一圈比一圈淡 */
.qb-core {
  width: 40%; height: 40%; border-radius: 50%;
  background: rgba(255, 255, 255, 0.94);
  box-shadow:
    0 0 0 calc(var(--qb-size, 56px) * 0.07) rgba(255, 255, 255, 0.34),
    0 0 0 calc(var(--qb-size, 56px) * 0.14) rgba(255, 255, 255, 0.16);
}

.qb-scrim {
  position: absolute; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.12);
  /* 只淡入底色，不动整层的透明度：祖先透明度不到 1 时 WebKit 不画面板的毛玻璃，从前打开时先是一块纯黑半透明，过一会儿才糊（4.950） */
  animation: qb-fade var(--dur) var(--ease-out);
}
/* 面板本身不滚：标题与下面是同一块底、同一层毛玻璃（4.950，从前标题自己又叠一层底色，上半截看着是另一块）。滚的是 .qb-body */
.qb-panel {
  width: min(312px, calc(100% - 48px)); max-height: 72%;
  display: flex; flex-direction: column; overflow: hidden;
  border-radius: calc(var(--r-xl) + 8px);
  background: rgba(0, 0, 0, 0.72);
  -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur));
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
  color: rgba(255, 255, 255, 0.96);
  animation: qb-pop var(--dur) var(--ease-out);
}
.qb-panel > * { animation: qb-show var(--dur) var(--ease-out); }
.qb-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 var(--sp-4) var(--sp-5); }
@keyframes qb-pop { from { transform: scale(0.82); } to { transform: none; } }
@keyframes qb-show { from { opacity: 0; } to { opacity: 1; } }
@keyframes qb-fade { from { background-color: transparent; } to { background-color: rgba(0, 0, 0, 0.12); } }
.qb-head { flex: none; display: flex; align-items: center; justify-content: space-between; min-height: 36px; padding: var(--sp-3) var(--sp-4) var(--sp-2); }
.qb-title { font-size: var(--fs-15); font-weight: var(--fw-semi); color: rgba(255, 255, 255, 0.96); }
.qb-head-btn { min-width: 44px; display: flex; justify-content: center; font-size: var(--fs-13); color: rgba(255, 255, 255, 0.7); }
.qb-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-4) var(--sp-2); padding-top: var(--sp-2); }
.qb-item { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); min-width: 0; color: rgba(255, 255, 255, 0.96); }
.qb-icon {
  width: 48px; height: 48px; display: flex; align-items: center; justify-content: center;
  border-radius: 50%; color: rgba(255, 255, 255, 0.96);
}
.qb-icon svg { width: 28px; height: 28px; }
/* 开着的那几项：白底圆，图标反色 */
:where(.qb-item.is-on) .qb-icon { background: rgba(255, 255, 255, 0.94); color: rgba(0, 0, 0, 0.88); }
.qb-label { font-size: var(--fs-11); line-height: 1.3; text-align: center; color: rgba(255, 255, 255, 0.92); }
.qb-note { font-size: var(--fs-9); color: rgba(255, 255, 255, 0.55); }
.qb-hint { font-size: var(--fs-12); line-height: 1.6; padding: var(--sp-1) 0 var(--sp-2); color: rgba(255, 255, 255, 0.6); }

/* 二级页面（世界书开关、切换模型、编辑）也是深色 */
.qb-books { display: grid; gap: var(--sp-2); }
.qb-book { border-radius: var(--r-md); padding: var(--sp-2) var(--sp-3); background: rgba(255, 255, 255, 0.08); }
.qb-book-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.qb-book-name { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); text-align: left; color: rgba(255, 255, 255, 0.96); }
.qb-book-name span { display: grid; min-width: 0; }
.qb-book-name b, .qb-pick b { font-size: var(--fs-14); font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qb-book-name small, .qb-pick small { font-size: var(--fs-11); color: rgba(255, 255, 255, 0.55); }
.qb-entries { display: grid; gap: var(--sp-1); padding: var(--sp-2) 0 0 var(--sp-5); }
.qb-entry { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); min-height: 32px; font-size: var(--fs-13); color: rgba(255, 255, 255, 0.9); }
.qb-group-name { font-size: var(--fs-12); padding-top: var(--sp-2); color: rgba(255, 255, 255, 0.55); }
.qb-pick {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); text-align: left;
  background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.96);
}
.qb-pick span { display: grid; min-width: 0; }
.qb-pick:where(.is-on) { background: rgba(255, 255, 255, 0.2); }
.qb-more { font-size: var(--fs-13); padding: var(--sp-2) 0; text-align: left; color: rgba(255, 255, 255, 0.75); }
.qb-order { display: flex; gap: var(--sp-1); color: rgba(255, 255, 255, 0.8); }
.qb-order button { color: inherit; }
.qb-order button:disabled { opacity: 0.3; }
.qb-tabs { padding-bottom: var(--sp-2); }
.qb-panel .segmented { background: rgba(255, 255, 255, 0.1); }
.qb-panel .seg-item { color: rgba(255, 255, 255, 0.75); }
.qb-panel .seg-item:where(.is-active) { background: rgba(255, 255, 255, 0.94); color: rgba(0, 0, 0, 0.88); }
.qb-range { display: grid; gap: var(--sp-1); font-size: var(--fs-13); color: rgba(255, 255, 255, 0.9); }
.qb-range input { width: 100%; }
.qb-img-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.qb-img-thumb {
  width: 44px; height: 44px; flex: none; display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.6); overflow: hidden;
}
.qb-img-thumb img { width: 100%; height: 100%; object-fit: contain; }
.qb-panel textarea { background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.92); border-color: rgba(255, 255, 255, 0.14); font-family: var(--font-mono); font-size: var(--fs-12); }
.qb-panel .mono { color: rgba(255, 255, 255, 0.85); }
.qb-panel .chip { background: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.9); border-color: rgba(255, 255, 255, 0.12); }
.qb-panel .chip:where(.is-active) { background: rgba(255, 255, 255, 0.94); color: rgba(0, 0, 0, 0.88); }
.qb-panel .switch { background: rgba(255, 255, 255, 0.2); }
.qb-panel .switch:where(.is-on) { background: var(--ios-green); }
.qb-panel .switch-dot { background: rgba(255, 255, 255, 0.98); }

/* 会话里切到线下（ARCHITECTURE 4.269）：顶上那一条，和消息流里的分隔线 */
/* 线下时顶上那一枚：也是居中的小胶囊，左边写在哪儿，右边「回到线上」，中间一道发丝线 */
.face-bar {
  flex: none; align-self: center; display: flex; align-items: stretch; max-width: 90%;
  margin-bottom: var(--sp-2); font-size: var(--fs-11); line-height: 1.5;
  background: var(--group-fill); border-radius: var(--r-full); overflow: hidden;
}
.face-bar-main { flex: 1; min-width: 0; padding: 3px var(--sp-3); text-align: left; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.face-bar-back { flex: none; padding: 3px var(--sp-3); color: var(--text-2); border-left: 1px solid var(--border-2); }
.side-div {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-3) var(--sp-4);
}
.side-div-line { flex: 1; height: 1px; background: var(--border-2); }
.side-div-text { flex: none; font-size: var(--fs-11); letter-spacing: .12em; color: var(--text-3); }

/* 聊天里的文件卡（ARCHITECTURE 4.271） */
.file-card {
  display: flex; align-items: center; gap: var(--sp-3);
  min-width: 180px; max-width: 260px; padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border);
  text-align: left;
}
.file-card:where(.is-failed) .file-card-meta { color: var(--danger); }
.file-card-icon { flex: none; display: flex; color: var(--text-2); }
.file-card-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.file-card-name { font-size: var(--fs-14); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-card-meta { font-size: var(--fs-11); color: var(--text-3); }
.file-actions { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.file-preview {
  margin: var(--sp-3) 0 0; padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--group-fill); font-size: var(--fs-12); line-height: 1.6; color: var(--text-2);
  white-space: pre-wrap; word-break: break-all; max-height: 420px; overflow: auto;
}
.diag-strip { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.diag-strip img { width: 44px; height: 44px; object-fit: cover; border-radius: var(--r-sm); background: var(--surface-2); }

/* 心声那张卡（ARCHITECTURE 4.274）：正中一张纸，像明信片，不做拟物 */
.inner-layer {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-6); background: var(--scrim);
  animation: fade-in var(--dur-fast) var(--ease);
}
.inner-postcard {
  width: 100%; max-width: 340px; aspect-ratio: 3 / 4;
  display: flex; flex-direction: column;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  border-radius: var(--ph-inner-card-r, var(--r-sm)); background: var(--ph-inner-card-bg, var(--surface));
  color: var(--ph-inner-card-fg, var(--text));
  border: var(--ph-inner-card-bw, 1px) solid var(--ph-inner-card-bc, var(--border));
  box-shadow: var(--shadow-3);
}
.inner-postcard-head { display: flex; align-items: center; gap: var(--sp-2); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border); }
.inner-postcard-face { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: none; }
.inner-postcard-face-fallback { display: inline-flex; align-items: center; justify-content: center; background: var(--surface-3); color: var(--text-2); font-size: var(--fs-12); }
.inner-postcard-name { font-size: var(--fs-13); color: var(--text-2); }
.inner-postcard-stamp { margin-left: auto; font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; }
.inner-postcard-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4) 0; overflow: auto; }
/* 上下居中靠首尾两项的 auto 外边距：内容超过卡片时从顶上开始滚，不会被 justify-content: center 切掉开头（4.570） */
.inner-postcard-body > :first-child { margin-top: auto; }
.inner-postcard-body > :last-child { margin-bottom: auto; }
.inner-postcard-text { font-family: var(--font-serif); font-size: var(--ph-inner-card-fs, var(--fs-17)); line-height: 1.8; white-space: pre-wrap; word-break: break-word; }
.inner-postcard-trans { margin-top: var(--sp-2); font-size: var(--fs-13); line-height: 1.6; color: var(--text-3); white-space: pre-wrap; }
.inner-postcard-said { font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); white-space: pre-wrap; word-break: break-word; }
.inner-postcard-said::before { content: "「"; }
.inner-postcard-said::after { content: "」"; }
.inner-postcard-empty { text-align: center; font-size: var(--fs-13); color: var(--text-3); }
.inner-postcard-foot { display: flex; align-items: center; justify-content: space-between; padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.inner-postcard-count { font-size: var(--fs-11); color: var(--text-3); letter-spacing: .08em; }
.inner-postcard-nav { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; color: var(--text-2); }
.inner-postcard-nav:disabled { opacity: .25; }
.inner-postcard-head { width: 100%; text-align: left; }
.inner-postcard-list { flex: 1; min-height: 0; overflow: auto; padding: var(--sp-2) 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.inner-postcard-item { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) var(--sp-2); border-radius: var(--r-xs); text-align: left; }
.inner-postcard-item:where(.is-cur) { background: var(--group-fill); }
.inner-postcard-item-stamp { font-size: var(--fs-11); color: var(--text-3); }
.inner-postcard-item-text { font-size: var(--fs-13); color: var(--text-2); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* 群资料里挂在父开关下面的子项（4.300）：往里缩一截，看得出从属关系 */
.list-item:where(.li-child) { padding-left: calc(var(--sp-4) + var(--sp-5)); }

/* ---- 短信（4.307）---- */
.sms-meta { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-11); color: var(--text-3); }
.sms-dot {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--danger); color: var(--on-accent); font-size: var(--fs-11); font-weight: var(--fw-semi);
  display: inline-flex; align-items: center; justify-content: center;
}
.sms-page { height: 100%; display: flex; flex-direction: column; min-height: 0; }
.sms-from { flex: none; text-align: center; font-size: var(--fs-11); color: var(--text-3); padding: var(--sp-2) 0; }
.sms-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.sms-row { display: flex; }
.sms-row.is-mine { justify-content: flex-end; }
.sms-bubble {
  max-width: 76%; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface-2); color: var(--text); font-size: var(--fs-15); line-height: 1.5;
  white-space: pre-wrap; word-break: break-word;
}
.sms-bubble.is-mine { background: var(--accent); color: var(--on-accent); }
.sms-bubble.is-mms { padding: 3px; }
/* 短信的译文（4.364）：气泡里原文下面，一条细线隔开 */
.sms-trans { margin-top: var(--sp-1); padding-top: var(--sp-1); border-top: 1px solid var(--group-line); font-size: var(--fs-13); line-height: 1.55; opacity: .72; }
.sms-img { display: block; max-width: 220px; max-height: 280px; border-radius: var(--r-md); }
.sms-wait { display: inline-block; padding: var(--sp-2) var(--sp-3); font-size: var(--fs-12); opacity: .7; }
.sms-notice { align-self: center; font-size: var(--fs-11); color: var(--text-3); padding: var(--sp-1) 0; }
.sms-guess {
  flex: none; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); font-size: var(--fs-13); color: var(--text-2);
  border-top: 1px solid var(--border);
}
.sms-guess > span { flex: 1; min-width: 0; line-height: 1.5; }
.sms-guess .nav-text { flex: none; }
.sms-composer {
  flex: none; display: flex; align-items: flex-end; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + var(--safe-bottom));
  border-top: 1px solid var(--border);
}
.sms-input {
  flex: 1; min-width: 0; resize: none; max-height: 120px;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface-2); color: var(--text); font-size: var(--fs-15); line-height: 1.4; border: none;
}

/* 心愿星空（4.317）。卡片是一张黑卡（--film），深色下多一圈发丝边；全景整屏黑，不跟主题走。
   星光在画布里画，一律是白的 */
.wish-sky {
  position: relative; margin: var(--sp-1) var(--sp-3) 0; aspect-ratio: 5 / 4;
  border-radius: var(--r-lg); background: var(--film); overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--film-edge);
}
.wish-sky canvas, .wish-pano-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.stage-full { position: absolute; inset: 0; z-index: var(--z-modal); animation: stage-in var(--dur) var(--ease-out); }
@keyframes stage-in { from { opacity: 0; } to { opacity: 1; } }
.wish-pano { background: var(--film); color: var(--on-film); touch-action: none; }
.wish-pano-close {
  position: absolute; left: var(--sp-2); top: calc(var(--top-inset) + var(--sp-2));
  width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; color: var(--on-film-2);
}
.wish-pano-card {
  position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: calc(var(--safe-bottom) + var(--sp-4));
  max-height: 46%; overflow-y: auto; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: rgba(255, 255, 255, .08); -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur));
  font-size: var(--fs-14); line-height: 1.5; animation: stage-in var(--dur) var(--ease-out);
}
.wpc-h { font-size: var(--fs-12); color: var(--on-film-2); margin-bottom: var(--sp-1); }
.wpc-foot { margin: var(--sp-1) 0 0; }
.wpc-row { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 6px 0; border-top: 1px solid rgba(255, 255, 255, .08); }
.wpc-row:first-of-type { border-top: none; }
.wpc-row span:last-child { flex: none; font-size: var(--fs-12); color: var(--on-film-2); }

/* 自定义互动标识（4.320） */
.bdd-img { width: var(--bdd-size, 20px); height: var(--bdd-size, 20px); border-radius: var(--r-full); object-fit: cover; display: block; }
.bdd-img.is-off { opacity: .35; filter: grayscale(1); }
.bdd-preview { display: flex; justify-content: center; padding: var(--sp-2) 0 var(--sp-4); }
.bdd-select { width: 100%; height: 40px; border: none; border-radius: var(--r-sm); padding: 0 var(--sp-3);
  background: var(--surface-2); color: var(--text); font: inherit; font-size: var(--fs-14); }
.bdd-icons { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--sp-2); padding: var(--sp-4); }
.bdd-icon { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border-radius: var(--r-sm); color: var(--text-2); }
.bdd-icon.is-on { background: var(--accent-weak); color: var(--text); }
.bdd-acts { display: inline-flex; gap: var(--sp-3); }

/* ---- 我的日程（4.321）：一周一张表 ---- */
.us-wrap { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.us-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-2); }
.us-nav { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--r-full); color: var(--text-2); }
.us-range { font-size: var(--fs-13); color: var(--text-2); font-variant-numeric: tabular-nums; }
.us-week { display: grid; grid-template-columns: 18px repeat(7, minmax(0, 1fr)); column-gap: 2px; }
.us-head {
  height: 38px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  font-size: var(--fs-11); color: var(--text-3); font-variant-numeric: tabular-nums;
}
.us-head b { font-weight: var(--fw-medium); }
.us-col.is-today .us-head { color: var(--text); }
.us-col.is-today .us-head span {
  min-width: 18px; padding: 0 4px; border-radius: var(--r-full); background: var(--accent); color: var(--on-accent);
}
.us-body {
  position: relative; height: calc(var(--us-hours) * 34px);
  border-radius: var(--r-xs); background: var(--surface-2);
  background-image: repeating-linear-gradient(to bottom, transparent 0, transparent 33px, var(--border) 33px, var(--border) 34px);
}
.us-axis .us-body { background: none; }
.us-hour { position: absolute; top: var(--us-top); right: 2px; font-size: var(--fs-9); color: var(--text-3); line-height: 1; font-variant-numeric: tabular-nums; }
.us-item {
  position: absolute; left: 1px; right: 1px; top: var(--us-top); height: var(--us-h); min-height: 18px;
  display: flex; flex-direction: column; gap: 1px; overflow: hidden; text-align: left;
  padding: 2px 3px; border-radius: var(--r-xs);
  background: var(--surface); color: var(--text); border: 1px solid var(--text);
  font-size: var(--fs-9); line-height: 1.25;
}
/* 某一天的那种用虚线，和每周重复的分开 */
.us-item:where(.is-once) { border-style: dashed; }
/* 通勤：左边一道粗线（4.326） */
.us-item:where(.is-commute) { border-left-width: 3px; }
/* 定了时间的任务：虚线，做完的变淡划掉 */
.us-item:where(.is-todo) { border-style: dashed; }
.us-item:where(.is-done), .us-task:where(.is-done) { color: var(--text-3); border-color: var(--border-2); text-decoration: line-through; }
/* 不到 45 分钟的一段只排一行，地点不显示 */
.us-item:where(.is-short) { flex-direction: row; align-items: center; gap: 2px; white-space: nowrap; padding-top: 0; padding-bottom: 0; }
.us-item:where(.is-short) .us-p { display: none; }
.us-item:where(.is-short) .us-t { overflow: hidden; text-overflow: ellipsis; }
.us-k { font-size: 8px; color: var(--text-3); letter-spacing: 1px; flex: none; }
/* 每一天最上面放任务的那一行 */
.us-tasks {
  min-height: 24px; margin-bottom: 2px; padding: 2px; border-radius: var(--r-xs);
  background: var(--surface-2); display: flex; flex-direction: column; gap: 2px;
}
.us-axis .us-tasks { background: none; font-size: var(--fs-9); color: var(--text-3); align-items: flex-end; justify-content: center; padding-right: 2px; }
.us-task {
  font-size: var(--fs-9); line-height: 1.25; padding: 2px 3px; border-radius: 4px; text-align: left; word-break: break-all;
  background: var(--surface); color: var(--text); border: 1px solid var(--text);
}
/* 今天的任务：打勾的圆圈 */
.us-check { width: 20px; height: 20px; border-radius: var(--r-full); border: 1.5px solid var(--text); flex: none; display: grid; place-items: center; }
.us-check:where(.is-on) { background: var(--accent); }
.us-check:where(.is-on)::after {
  content: ''; width: 8px; height: 5px; border: 2px solid var(--on-accent); border-top: 0; border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}
/* 这一页自己换的背景（「这一页的样子」），遮罩朝主题底色淡过去 */
.page:where(.has-sched-bg) {
  background:
    linear-gradient(color-mix(in srgb, var(--bg) var(--ph-sched-veil, 30%), transparent),
                    color-mix(in srgb, var(--bg) var(--ph-sched-veil, 30%), transparent)),
    var(--ph-sched-bg, none) center / cover no-repeat,
    var(--bg);
}
.us-t { font-weight: var(--fw-medium); word-break: break-all; }
.us-p { opacity: .7; word-break: break-all; }
.us-times { display: flex; align-items: center; gap: var(--sp-2); }
.us-times input { flex: 1; min-width: 0; }
.us-times span { color: var(--text-3); font-size: var(--fs-13); }
.us-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1); }
.us-day { height: 34px; border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-2); font-size: var(--fs-13); }
.us-day.is-on { background: var(--accent); color: var(--on-accent); }

/* ---- 小红书笔记卡片（4.327）---- */
.xhs-card {
  display: flex; flex-direction: column; width: 232px; max-width: 100%; overflow: hidden; text-align: left;
  border-radius: var(--r-md); background: var(--surface); color: var(--text); border: 1px solid var(--border);
}
.xhs-card:where(.is-pending, .is-error) { padding: var(--sp-3); gap: var(--sp-1); }
.xhs-cover { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--surface-2); }
.xhs-body { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3) var(--sp-3); }
.xhs-title { font-size: var(--fs-14); font-weight: var(--fw-medium); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.xhs-desc { font-size: var(--fs-12); color: var(--text-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; white-space: pre-line; }
.xhs-why { font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; overflow-wrap: anywhere; }
.xhs-from { font-size: var(--fs-11); color: var(--text-3); }
/* 一长串没有空格的标题、作者名（英文、链接）折行，不在卡片右边被切掉（4.716） */
.xhs-title, .xhs-desc, .xhs-from { overflow-wrap: anywhere; }
.xhs-wait { font-size: var(--fs-13); color: var(--text-2); }
.xhs-acts { display: flex; gap: var(--sp-3); }

/* ---- 日记（4.333）。纸张默认白纸，横线、方格、米色可选 ---- */
.dy-cal { padding: 0 var(--sp-4) var(--sp-2); }
.dy-month { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) 0 var(--sp-3); }
.dy-month-t { flex: 1; display: flex; align-items: baseline; gap: var(--sp-2); }
.dy-m { font-size: var(--fs-24); font-weight: var(--fw-semi); }
.dy-y { font-size: var(--fs-14); color: var(--text-3); }
.dy-arrow { width: 36px; height: 36px; display: grid; place-items: center; border-radius: var(--r-sm); color: var(--text-2); }
.dy-chips { display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-3); scrollbar-width: none; }
.dy-chips::-webkit-scrollbar { display: none; }
.dy-chip { flex: none; border: 1px solid var(--border); color: var(--text-2); font-size: var(--fs-12); padding: 3px 10px; border-radius: var(--r-full); }
.dy-chip.is-on { color: var(--text); border-color: var(--text); }
.dy-week, .dy-days { display: grid; grid-template-columns: repeat(7, 1fr); }
.dy-week div { text-align: center; font-size: var(--fs-11); color: var(--text-3); padding-bottom: var(--sp-2); }
.dy-day { position: relative; aspect-ratio: 1 / 1.15; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding-top: 6px; border-radius: var(--r-sm); color: var(--text); }
.dy-day.is-empty { pointer-events: none; }
.dy-day.is-sel { background: var(--surface-2); }
.dy-day.is-future .dy-n { color: var(--text-3); }
.dy-n { font-size: var(--fs-14); line-height: 22px; width: 22px; height: 22px; border-radius: var(--r-full); text-align: center; }
.dy-day.is-today .dy-n { background: var(--accent); color: var(--on-accent); }
.dy-marks { display: flex; gap: 3px; height: 10px; align-items: center; }
.dy-mark { display: inline-flex; color: var(--text); }
.dy-slot { width: 10px; height: 10px; display: inline-flex; }
.dy-mark.is-dim { color: var(--text-2); }
.dy-dot { position: absolute; bottom: 5px; width: 4px; height: 4px; border-radius: var(--r-full); background: var(--text-3); }
.dy-legend { display: flex; flex-wrap: wrap; gap: var(--sp-3); font-size: var(--fs-11); color: var(--text-2); padding: var(--sp-3) 0 0; }
.dy-legend span { display: inline-flex; align-items: center; gap: 4px; }
.dy-legend .dy-legend-r { margin-left: auto; color: var(--text-3); }

.dy-dayhead { padding: var(--sp-1) var(--sp-4) var(--sp-3); }
.dy-dayhead-d { font-size: var(--fs-24); font-weight: var(--fw-semi); }
.dy-dayhead-w { font-size: var(--fs-13); color: var(--text-3); }
.dy-moods { display: flex; gap: var(--sp-3); padding: 0 var(--sp-4) var(--sp-4); }
.dy-mood { flex: 1; display: flex; align-items: center; gap: var(--sp-2); background: var(--surface-2); border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-13); }
.dy-mood-l { font-size: var(--fs-11); color: var(--text-3); }
.dy-tl { position: relative; margin: 0 var(--sp-4); padding-left: 22px; }
.dy-tl::before { content: ""; position: absolute; left: 6px; top: 8px; bottom: 8px; width: 1px; background: var(--border); }
.dy-past { margin-top: var(--sp-2); padding-top: var(--sp-4); border-top: 1px dashed var(--border); }
.dy-ev { position: relative; display: block; width: 100%; text-align: left; padding: 0 0 var(--sp-4); color: var(--text); }
.dy-ev::before { content: ""; position: absolute; left: -20px; top: 6px; width: 9px; height: 9px; border-radius: var(--r-full);
  background: var(--bg); border: 1.5px solid var(--text-2); box-sizing: border-box; }
.dy-ev.is-strong::before { background: var(--text); border-color: var(--text); }
.dy-ev-tm { font-size: var(--fs-11); color: var(--text-3); }
.dy-ev-t { font-size: var(--fs-14); display: flex; align-items: center; gap: var(--sp-2); }
.dy-ev-s { font-size: var(--fs-12); color: var(--text-2); overflow-wrap: anywhere; }
.dy-tag { font-size: var(--fs-11); line-height: 16px; border: 1px solid var(--border); color: var(--text-2);
  border-radius: var(--r-full); padding: 0 6px; }

.dy-seg { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.dy-paper { background: var(--surface); color: var(--text); }
.dy-paper.is-warm { background: var(--diary-warm); }
.dy-paper.is-lined { background-image: repeating-linear-gradient(to bottom, transparent 0 31px, var(--diary-line) 31px 32px);
  background-attachment: local; }
.dy-paper.is-grid { background-image: linear-gradient(var(--diary-line) 1px, transparent 1px),
  linear-gradient(90deg, var(--diary-line) 1px, transparent 1px); background-size: 20px 20px; }
.dy-paper.font-serif, .dy-paper.font-serif :where(input, textarea) { font-family: var(--font-serif); }
.dy-paper.font-hand, .dy-paper.font-hand :where(input, textarea) { font-family: var(--font-hand); }
.dy-read { margin: var(--sp-2) var(--sp-4) var(--sp-4); padding: var(--sp-3) var(--sp-4) var(--sp-5);
  border-radius: var(--r-md); border: 1px solid var(--border); }
.dy-meta { font-size: var(--fs-12); color: var(--text-2); padding-bottom: var(--sp-2); }
.dy-title { font-size: var(--fs-17); font-weight: var(--fw-semi); padding-bottom: var(--sp-2); }
.dy-text { font-size: var(--fs-17); line-height: 32px; white-space: pre-wrap; overflow-wrap: anywhere; min-height: 96px; }
.dy-paper.font-hand .dy-text { font-size: var(--fs-20); }
.dy-del { text-decoration: line-through; color: var(--text-3); }
.dy-caret { display: inline-block; width: 1.5px; height: 1.1em; background: var(--text); vertical-align: -3px; margin-left: 1px;
  animation: dy-blink 1s steps(1) infinite; }
@keyframes dy-blink { 50% { opacity: 0; } }
.dy-prog { height: 2px; background: var(--border); border-radius: 2px; overflow: hidden; margin-top: var(--sp-3); }
.dy-prog i { display: block; height: 100%; width: var(--p, 0%); background: var(--text); }
.dy-photo { display: block; width: 100%; border-radius: var(--r-sm); margin-top: var(--sp-3); }
.dy-stat { font-size: var(--fs-11); color: var(--text-3); padding-top: var(--sp-3); }
.dy-play { display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-3); }
.dy-speed { flex: 1; min-width: 0; }
.dy-pbtn { border: 1px solid var(--border); border-radius: var(--r-full); padding: 4px 14px; font-size: var(--fs-12); color: var(--text); }

.dy-edit { min-height: 100%; padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.dy-edit input, .dy-edit textarea { background: transparent; border: 0; padding: var(--sp-2) 0; width: 100%; color: var(--text); }
.dy-edit input { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.dy-edit textarea { font-size: var(--fs-17); line-height: 32px; resize: none; min-height: 320px; }
.dy-moodpick { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding-bottom: var(--sp-2); }
.dy-moodpick-l { font-size: var(--fs-12); color: var(--text-2); }
.dy-moodpick-n { font-size: var(--fs-11); color: var(--text-3); }
.dy-thumbs { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.dy-thumb { position: relative; width: 88px; height: 88px; border-radius: var(--r-sm); overflow: hidden; background: var(--surface-2); }
.dy-thumb img { width: 100%; height: 100%; object-fit: cover; }
.dy-thumb-x { position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: var(--r-full); background: var(--scrim); color: var(--on-scrim); }
.dy-dock { position: sticky; bottom: 0; background: var(--surface); padding-bottom: var(--safe-bottom); }
.dy-sheet { border-top: 1px solid var(--border); padding: var(--sp-3) var(--sp-4); }
.dy-sheet-h { font-size: var(--fs-12); color: var(--text-2); padding-bottom: var(--sp-2); }
.dy-sheet-note { font-size: var(--fs-11); color: var(--text-3); padding-top: var(--sp-2); }
.dy-opts-row { display: flex; gap: var(--sp-2); }
.dy-opt-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--sp-2) 0; font-size: var(--fs-14); color: var(--text); }
.dy-opt-btn.is-on { border-color: var(--text); }
.dy-opt-btn.font-serif { font-family: var(--font-serif); }
.dy-opt-btn.font-hand { font-family: var(--font-hand); }
.dy-swatch { flex: 1; height: 48px; border: 1px solid var(--border); border-radius: var(--r-sm); display: grid; place-items: center;
  font-size: var(--fs-11); color: var(--text-2); }
.dy-swatch.is-on { outline: 2px solid var(--text); outline-offset: 2px; }
.dy-radio { display: flex; width: 100%; text-align: left; gap: var(--sp-3); padding: var(--sp-2); border-radius: var(--r-sm); color: var(--text); }
.dy-radio.is-on { background: var(--surface-2); }
.dy-rd { flex: none; width: 16px; height: 16px; margin-top: 2px; border-radius: var(--r-full); border: 1.5px solid var(--text-3); box-sizing: border-box; }
.dy-radio.is-on .dy-rd { border: 5px solid var(--text); }
.dy-rd.is-none { border-color: transparent; }
.dy-radio-t { display: block; font-size: var(--fs-14); }
.dy-radio-d { display: block; font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; }
.dy-tools { display: flex; border-top: 1px solid var(--border); background: var(--surface);
  padding: 6px var(--sp-2) calc(6px + var(--safe-bottom)); }
.dy-tool { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 4px 0; font-size: var(--fs-11);
  color: var(--text-2); border-radius: var(--r-sm); }
.dy-tool.is-on { color: var(--text); background: var(--surface-2); }
.dy-lock { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--sp-8) var(--sp-6) var(--sp-6); gap: var(--sp-2); }
.dy-lock-ic { width: 64px; height: 64px; border-radius: var(--r-full); background: var(--surface-2); display: grid; place-items: center; margin-bottom: var(--sp-2); }
.dy-lock-h { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.dy-lock-s { font-size: var(--fs-13); color: var(--text-2); margin-bottom: var(--sp-3); }
.dy-lock-n { font-size: var(--fs-12); color: var(--text-2); min-height: 18px; }
.dy-lock-foot { font-size: var(--fs-11); color: var(--text-3); line-height: 1.6; }
.dy-lock-link { font-size: var(--fs-13); color: var(--text-2); padding: var(--sp-2); }
.dy-lock-text { width: 100%; display: flex; flex-direction: column; gap: var(--sp-2); }
.dy-lock .button { width: 100%; }
.dy-pin { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.dy-pin span { width: 36px; height: 44px; border: 1px solid var(--border); border-radius: var(--r-sm); display: grid; place-items: center; font-size: var(--fs-20); }
.dy-pin span.is-on { border-color: var(--text); }
.dy-pin.is-bad span { border-color: var(--text-2); animation: dy-shake .3s; }
@keyframes dy-shake { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.dy-keys { display: grid; grid-template-columns: repeat(3, 64px); gap: var(--sp-2); margin-top: var(--sp-3); }
.dy-keys-foot { display: flex; justify-content: flex-end; width: calc(64px * 3 + var(--sp-2) * 2); margin-bottom: var(--sp-2); }
.dy-del { width: 64px; padding: var(--sp-2) 0; font-size: var(--fs-13); color: var(--text-2); }
.dy-del.is-hidden { visibility: hidden; }
.dy-key { height: 44px; border-radius: var(--r-sm); background: var(--surface-2); color: var(--text); font-size: var(--fs-17); display: grid; place-items: center; }
.dy-lockset { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) 0 0; }

/* ---- 角色眼中的你（contact/ImpressPage.js，4.346） ---- */
.im-top { margin: 0 var(--sp-4) var(--sp-4); padding: var(--sp-3) var(--sp-4) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.im-top-text { font-size: var(--fs-12); color: var(--text-2); line-height: 1.6; margin-bottom: var(--sp-3); }
.im-top-fine { font-size: var(--fs-11); color: var(--text-3); line-height: 1.55; margin-top: var(--sp-2); }
.im-group { padding: 0 var(--sp-4); }
.im-group-title { font-size: var(--fs-12); color: var(--text-3); margin: var(--sp-3) 2px var(--sp-2); }
.im-card {
  display: block; width: 100%; box-sizing: border-box; text-align: left; color: var(--text);
  padding: var(--sp-3); margin-bottom: var(--sp-2); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border);
}
.im-text { font-size: var(--fs-15); font-weight: var(--fw-medium); line-height: 1.55; }
.im-text.is-big { font-size: var(--fs-17); margin-top: var(--sp-2); }
.im-voice { font-size: var(--fs-13); color: var(--text-2); line-height: 1.55; margin-top: var(--sp-1); }
.im-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: var(--sp-2); font-size: var(--fs-11); color: var(--text-3); }
.im-pill { display: inline-flex; align-items: center; padding: 1px 8px; border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); font-size: var(--fs-11); }
.im-pill.is-sure { background: var(--accent); color: var(--on-accent); }
.im-pill.is-first { background: transparent; box-shadow: inset 0 0 0 1px var(--border-2); color: var(--text-3); }
.im-pill.is-against { background: var(--danger-weak); color: var(--danger); }
.im-new { display: inline-flex; align-items: center; margin-left: 6px; padding: 0 7px; border-radius: var(--r-full); background: var(--accent); color: var(--on-accent); font-size: var(--fs-11); font-weight: var(--fw-normal); vertical-align: 2px; }
.im-sec { font-size: var(--fs-13); font-weight: var(--fw-semi); margin: var(--sp-5) 0 var(--sp-2); }
.im-ev { border-left: 2px solid var(--border-2); padding: 2px 0 2px var(--sp-3); margin-bottom: var(--sp-3); }
.im-against .im-ev { border-left-color: var(--danger); }
.im-ev-at { font-size: var(--fs-11); color: var(--text-3); }
.im-ev-q { font-size: var(--fs-14); line-height: 1.55; margin-top: 2px; }
.im-ev-go { font-size: var(--fs-12); color: var(--text-2); margin-top: 2px; text-decoration: underline; text-underline-offset: 2px; }
.im-acts { margin-top: var(--sp-5); }
.im-pick { display: flex; gap: var(--sp-3); align-items: flex-start; }
.im-pick-body { flex: 1; min-width: 0; }
.im-check { flex: none; width: 18px; height: 18px; margin-top: 2px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center; box-shadow: inset 0 0 0 1.5px var(--border-2); }
.im-check.is-on { background: var(--accent); color: var(--on-accent); box-shadow: none; }
.im-quote { font-size: var(--fs-12); color: var(--text-2); line-height: 1.55; margin-top: var(--sp-2); }
.im-quote.is-against { color: var(--danger); }
/* 别人眼中的我（contact/SelfPages.js，4.347）：账号页那张卡、列表抬头、编辑页 */
.im-others { margin-top: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.im-others-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }
.im-others-head b { font-size: var(--fs-15); font-weight: var(--fw-semi); }
.im-others-head > span { font-size: var(--fs-12); color: var(--text-3); }
.im-stats { display: flex; margin: var(--sp-3) 0; border-radius: var(--r-md); background: var(--surface); }
.im-stats div { flex: 1; display: flex; flex-direction: column; align-items: center; padding: var(--sp-2) 0; }
.im-stats b { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.im-stats span { font-size: var(--fs-11); color: var(--text-3); }
.im-by { font-size: var(--fs-11); color: var(--text-3); margin-top: var(--sp-1); }
.im-others-empty { font-size: var(--fs-12); color: var(--text-2); line-height: 1.6; }
.im-others-more { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); text-align: center; font-size: var(--fs-13); }
.im-lt { display: flex; justify-content: space-between; gap: var(--sp-2); }
.im-sec-tabs { margin-top: 0; }
.im-count { font-size: var(--fs-11); color: var(--text-3); text-align: right; margin-top: var(--sp-1); }
.im-note { font-size: var(--fs-14); line-height: 1.55; }
.im-add { display: block; width: 100%; margin-bottom: var(--sp-3); padding: var(--sp-2) 0; border-radius: var(--r-md); box-shadow: inset 0 0 0 1px var(--border-2); color: var(--text-2); font-size: var(--fs-13); text-align: center; }
.im-sheet-t { font-size: var(--fs-12); color: var(--text-3); margin: var(--sp-4) 0 var(--sp-2); }
.im-by-row { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); margin-bottom: var(--sp-2); }
.im-avs { display: inline-flex; }
.im-avs > * + * { margin-left: -6px; }
.im-link { font-size: var(--fs-12); color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.im-merged { font-size: var(--fs-13); color: var(--text-2); text-align: center; padding: var(--sp-2) 0; }
.im-tabs { margin-bottom: var(--sp-3); }

/* ---- 收藏馆（apps/collect，4.349） ---- */
.cx-sum { display: flex; margin: 0 0 var(--sp-3); padding: var(--sp-3) var(--sp-1); border-radius: var(--r-lg); background: var(--surface-2); }
.cx-sum div { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; }
.cx-sum b { font-size: var(--fs-17); font-weight: var(--fw-semi); white-space: nowrap; }
.cx-sum span { font-size: var(--fs-11); color: var(--text-3); }
.cx-due { display: block; width: 100%; text-align: left; margin-bottom: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); color: var(--text); }
.cx-due-r { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); padding: 2px 0; font-size: var(--fs-12); }
.cx-due-r span { color: var(--text-3); }
.cx-due-r b { font-size: var(--fs-15); font-weight: var(--fw-semi); }
.cx-due-r em { font-style: normal; text-align: right; }
.cx-filters { display: flex; gap: 6px; overflow-x: auto; padding-top: var(--sp-3); padding-bottom: var(--sp-3); }
.cx-filters .chip { flex: none; }
.cx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); padding-bottom: 96px; }
.cx-card { display: block; min-width: 0; text-align: left; color: var(--text); padding: 6px 6px var(--sp-2); border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--surface); }
.cx-card-pic { position: relative; }
.cx-img { display: flex; align-items: center; justify-content: center; aspect-ratio: 1; border-radius: var(--r-md); background: var(--img, none) center / cover no-repeat, var(--surface-2); color: var(--text-3); }
.cx-qty { position: absolute; right: 6px; top: 6px; padding: 0 7px; border-radius: var(--r-full); background: var(--accent); color: var(--on-accent); font-size: var(--fs-11); }
.cx-tag { position: absolute; left: 6px; bottom: 6px; padding: 0 7px; border-radius: var(--r-full); background: var(--surface); color: var(--text-2); font-size: var(--fs-11); }
.cx-card-name { margin: 7px 3px 0; font-size: var(--fs-13); font-weight: var(--fw-semi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cx-card-sub { margin: 2px 3px 0; font-size: var(--fs-11); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cx-fab { position: absolute; right: var(--sp-4); bottom: calc(var(--safe-bottom) + var(--sp-5)); width: 52px; height: 52px; border-radius: var(--r-full); background: var(--accent); color: var(--on-accent); display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-2); }
.cx-group { display: flex; justify-content: space-between; font-size: var(--fs-12); color: var(--text-3); margin: var(--sp-4) 2px var(--sp-2); }
.cx-row { display: flex; gap: var(--sp-3); width: 100%; text-align: left; color: var(--text); padding: var(--sp-3); margin-bottom: var(--sp-2); border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--surface); }
.cx-row-pic { width: 52px; flex: none; }
.cx-row-pic .cx-img { border-radius: var(--r-sm); }
.cx-row-body { flex: 1; min-width: 0; }
.cx-row-name { font-size: var(--fs-14); font-weight: var(--fw-semi); }
.cx-row-sub { font-size: var(--fs-11); color: var(--text-3); margin-top: 2px; }
.cx-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-2); }
.cx-pill { display: inline-flex; align-items: center; padding: 1px 8px; border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); font-size: var(--fs-11); }
.cx-pill.is-k { background: var(--accent); color: var(--on-accent); }
.cx-pill.is-w { background: transparent; box-shadow: inset 0 0 0 1px var(--border-2); color: var(--text-3); }
.cx-sheet-t { display: flex; justify-content: space-between; font-size: var(--fs-12); color: var(--text-3); margin: var(--sp-3) 0 var(--sp-2); }
.cx-n { font-style: normal; margin-left: 4px; opacity: .55; }
.cx-hero { position: relative; aspect-ratio: 1; margin-top: var(--sp-2); border-radius: var(--r-xl); background: var(--img, none) center / cover no-repeat, var(--surface-2); }
.cx-hero.is-blank { display: flex; align-items: center; justify-content: center; }
.cx-hero-label { position: absolute; left: var(--sp-3); top: var(--sp-3); padding: 1px 9px; border-radius: var(--r-full); background: var(--surface); font-size: var(--fs-11); }
.cx-thumbs { display: flex; gap: 6px; margin: var(--sp-2) 0 var(--sp-3); overflow-x: auto; }
.cx-thumb { flex: none; width: 48px; height: 48px; border-radius: var(--r-sm); display: flex; align-items: flex-end; justify-content: center; padding-bottom: 3px; background: var(--img, none) center / cover no-repeat, var(--surface-2); }
.cx-thumb span { font-size: 9px; color: var(--text-2); background: var(--surface); border-radius: var(--r-full); padding: 0 4px; }
.cx-thumb span:empty { display: none; }
.cx-thumb.is-on { box-shadow: inset 0 0 0 2px var(--accent); }
.cx-thumb.is-add { align-items: center; padding: 0; background: transparent; box-shadow: inset 0 0 0 1px var(--border-2); color: var(--text-3); }
.cx-h1 { font-size: var(--fs-20); font-weight: var(--fw-semi); }
.cx-h2 { font-size: var(--fs-13); color: var(--text-2); margin-top: 3px; }
.cx-link { color: var(--text); text-decoration: underline; text-underline-offset: 2px; font-size: inherit; }
.cx-kv { display: grid; grid-template-columns: 64px 1fr; row-gap: 6px; margin-top: var(--sp-3); font-size: var(--fs-13); }
.cx-kv span { color: var(--text-3); }
.cx-kv b { font-weight: var(--fw-normal); }
.cx-box { margin-top: var(--sp-4); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.cx-box-r { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-13); padding: 4px 0; }
.cx-box-r span { color: var(--text-3); flex: none; }
.cx-box-r b { font-weight: var(--fw-normal); text-align: right; }
.cx-box .btn { margin-top: var(--sp-3); }
.cx-sec { display: flex; justify-content: space-between; align-items: baseline; font-size: var(--fs-13); font-weight: var(--fw-semi); margin: var(--sp-5) 0 var(--sp-2); }
.cx-sec .nav-text { font-size: var(--fs-12); font-weight: var(--fw-normal); }
.cx-line { display: flex; justify-content: space-between; gap: var(--sp-3); width: 100%; text-align: left; color: var(--text); font-size: var(--fs-13); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); }
.cx-line b { font-weight: var(--fw-medium); flex: 0 1 auto; min-width: 0; text-align: right; }
/* 左边的说明与右边的值都能收窄、换行，值再长也不顶出屏幕（4.c158-10） */
.cx-line > span { min-width: 0; }
.cx-line em { font-style: normal; color: var(--text-3); font-size: var(--fs-12); text-align: right; }
.cx-total { display: flex; justify-content: space-between; font-size: var(--fs-14); font-weight: var(--fw-semi); padding-top: var(--sp-2); }
.cx-note { font-size: var(--fs-13); color: var(--text-2); line-height: 1.6; white-space: pre-wrap; }
.cx-fine { font-size: var(--fs-12); color: var(--text-3); line-height: 1.55; margin: var(--sp-2) 0; }
.cx-batch { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.cx-batch input { min-width: 0; flex: 1; padding: 8px; border-radius: var(--r-sm); background: var(--surface-2); color: var(--text); border: 0; font-size: var(--fs-13); }
.cx-batch input[type=date] { flex: 1.6; }
.cx-batch input.is-qty { flex: .6; }
.cx-batch-x { flex: none; width: 28px; color: var(--text-3); font-size: var(--fs-17); }
.cx-add { display: block; width: 100%; padding: var(--sp-2) 0; border-radius: var(--r-md); box-shadow: inset 0 0 0 1px var(--border-2); color: var(--text-2); font-size: var(--fs-13); text-align: center; }
.cx-switch-row { display: flex; justify-content: space-between; align-items: center; margin: var(--sp-2) 0; font-size: var(--fs-14); }
.cx-list-block { margin-bottom: var(--sp-2); }
.cx-hero.is-blank { aspect-ratio: 16 / 9; }
/* 收藏馆的统计（apps/collect/StatsPage.js，4.350）。只有一组数据，柱与横条都用正文色；选中的月份实色，其余减淡 */
.cx-sum { width: 100%; color: var(--text); }
.cx-sum.is-flat { margin-bottom: var(--sp-2); }
.cx-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.cx-tiles div { padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); display: flex; flex-direction: column; }
.cx-tiles b { font-size: var(--fs-20); font-weight: var(--fw-semi); }
.cx-tiles span { font-size: var(--fs-11); color: var(--text-3); }
.cx-chart { position: relative; height: 150px; margin-top: var(--sp-5); display: flex; align-items: flex-end; gap: 6px; border-bottom: 1px solid var(--border-2); }
.cx-grid-line { position: absolute; left: 0; right: 0; bottom: var(--at); border-top: 1px dashed var(--border); pointer-events: none; }
.cx-grid-line span { position: absolute; left: 0; top: -15px; font-size: 10px; color: var(--text-3); }
.cx-col { flex: 1; height: 100%; display: flex; align-items: flex-end; position: relative; z-index: 1; }
.cx-col i { display: block; width: 100%; height: var(--h); border-radius: 4px 4px 0 0; background: var(--text); }
.cx-col.is-dim i { opacity: .3; }
.cx-xlabels { display: flex; gap: 6px; padding-top: 4px; }
.cx-xlabels span { flex: 1; text-align: center; font-size: 10px; color: var(--text-3); }
.cx-chart-read { margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); min-height: 18px; }
.cx-seg-sm .segmented { width: 120px; }
.cx-seg-sm .seg-item { height: 26px; font-size: var(--fs-12); }
.cx-hbar { margin-bottom: 10px; }
.cx-hbar-top { display: flex; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-13); margin-bottom: 4px; }
.cx-hbar-top em { font-style: normal; font-size: var(--fs-12); color: var(--text-2); flex: none; }
.cx-hbar-track { height: 8px; border-radius: 4px; background: var(--surface-2); }
.cx-hbar-track i { display: block; height: 100%; width: var(--w); border-radius: 4px; background: var(--text); }
.cx-hbar.is-rest .cx-hbar-track i { opacity: .3; }
.cx-more { display: block; width: 100%; padding: var(--sp-2) 0; font-size: var(--fs-12); color: var(--text-2); text-align: center; }
.cx-fact-k { color: var(--text-3); flex: none; }

/* ---- 收藏馆：角色一边（4.351） ---- */
.cx-gen { width: 100%; display: flex; align-items: center; gap: var(--sp-3); margin: var(--sp-3) 0 var(--sp-6); padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface-2); color: var(--text); text-align: left; }
.cx-gen i { flex: none; width: 32px; height: 32px; border-radius: var(--r-md); background: var(--surface); display: flex; align-items: center; justify-content: center; }
.cx-gen div { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cx-gen b { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.cx-gen em { font-style: normal; font-size: var(--fs-12); color: var(--text-3); }
.cx-gen > svg { color: var(--text-3); }
.cx-gen-form { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) var(--sp-3); }

/* ---- 收藏馆：按外观生图（4.352） ---- */
.cx-hero-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); padding: var(--sp-3); }
.cx-hero-btn { display: inline-flex; align-items: center; gap: var(--sp-1); padding: 7px 12px; border-radius: var(--r-full); background: var(--surface); color: var(--text); font-size: var(--fs-13); box-shadow: inset 0 0 0 1px var(--border); }
.cx-hero-btn.is-k { background: var(--accent); color: var(--on-accent); box-shadow: none; }
.cx-hero-btn:disabled, .cx-more:disabled { opacity: .45; }

/* ---- 入手确认卡（4.352） ---- */
.acq-card { width: 260px; max-width: 100%; padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); text-align: left; color: var(--text); }
.acq-tag { font-size: var(--fs-11); color: var(--text-3); }
.acq-name { font-size: var(--fs-15); font-weight: var(--fw-semi); margin: 2px 0; }
.acq-sub { font-size: var(--fs-12); color: var(--text-3); }
.acq-why { margin-top: var(--sp-2); padding: var(--sp-2); border-radius: var(--r-md); background: var(--surface-2); font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; }
.acq-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.acq-acts button { flex: 1; padding: 7px 0; border-radius: var(--r-md); background: var(--surface-2); color: var(--text); font-size: var(--fs-13); }
.acq-acts button.is-k { background: var(--accent); color: var(--on-accent); }
.acq-card:where(.is-done) { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-13); }
.acq-card:where(.is-done) b { font-weight: var(--fw-medium); min-width: 0; }
.acq-card:where(.is-done) span { flex: none; color: var(--text-3); }
.acq-card:where(.is-gone) { width: auto; padding: 0 var(--sp-1); background: none; box-shadow: none; font-size: var(--fs-12); color: var(--text-3); }

/* ---- 收藏馆：来源与共同拥有（4.353） ---- */
.cx-link-row { width: 100%; color: var(--text); text-align: left; }
.cx-link-row b { color: var(--text-2); }

/* ---- 一起听：收起后的小圆盘与播放列表（4.354） ---- */
.listen-mini {
  --size: 52px;
  position: absolute; z-index: 3; width: var(--size); height: var(--size); border-radius: var(--r-full);
  top: calc(var(--mini-y, .35) * (100% - var(--size) - 2 * var(--sp-3)) + var(--sp-3));
  padding: 3px; touch-action: none; cursor: grab;
  background: conic-gradient(var(--accent) calc(var(--p, 0) * 1turn), var(--border-2) 0);
  box-shadow: var(--shadow-2);
  transition: left var(--dur) var(--ease-out), right var(--dur) var(--ease-out), top var(--dur) var(--ease-out);
}
.listen-mini.is-right { right: var(--sp-3); }
.listen-mini.is-left { left: var(--sp-3); }
.listen-mini.is-drag { left: var(--mini-x); top: var(--mini-top); transition: none; cursor: grabbing; }
.listen-mini-disc {
  width: 100%; height: 100%; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center;
  background: var(--text); color: var(--bg);
}
.listen-mini.is-playing .listen-mini-disc { animation: listen-spin calc(var(--dur-slow) * 24) linear infinite; }
@keyframes listen-spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .listen-mini.is-playing .listen-mini-disc { animation: none; } }

.lsq-head { font-size: var(--fs-12); color: var(--text-3); padding: 0 var(--sp-1) var(--sp-2); }
.lsq { display: flex; flex-direction: column; }
.lsq-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-1); border-bottom: 1px solid var(--border); text-align: left; color: var(--text); }
.lsq-n { width: 22px; flex: none; text-align: center; font-size: var(--fs-12); color: var(--text-3); }
.lsq-t { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.lsq-t b { font-weight: var(--fw-normal); font-size: var(--fs-14); }
.lsq-t small { font-size: var(--fs-11); color: var(--text-3); }
.lsq-row.is-on .lsq-t b { font-weight: var(--fw-semi); }
.lsq-row.is-on .lsq-n { color: var(--text); }
.lsq-tag { flex: none; font-style: normal; font-size: var(--fs-11); padding: 1px 8px; border-radius: var(--r-full); background: var(--accent); color: var(--on-accent); }
.lsq-done { flex: none; font-style: normal; font-size: var(--fs-11); color: var(--text-3); }

/* 选歌页「上次一起听」（4.354） */
.ls-resume { margin: 0 var(--sp-4) var(--sp-2); padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface-2); }
.ls-resume-top { display: flex; gap: var(--sp-3); align-items: center; }
.ls-resume-cover { flex: none; width: 52px; height: 52px; border-radius: var(--r-md); background: var(--border-2); color: var(--surface); display: flex; align-items: center; justify-content: center; }
.ls-resume-body { min-width: 0; flex: 1; }
.ls-resume-k { font-size: var(--fs-11); color: var(--text-3); }
.ls-resume-n { font-size: var(--fs-15); font-weight: var(--fw-semi); margin: 1px 0; }
.ls-resume-a { font-size: var(--fs-12); color: var(--text-2); }
.ls-resume-bar { position: relative; height: 3px; margin: var(--sp-3) 0 var(--sp-1); border-radius: var(--r-full); background: var(--border-2); }
.ls-resume-bar i { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--p, 0) * 100%); border-radius: var(--r-full); background: var(--accent); }
.ls-resume-tm { display: flex; justify-content: space-between; font-size: var(--fs-11); color: var(--text-3); }
.ls-resume-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }
.ls-resume-acts > * { flex: 1; }

/* 设置 - 节日：自定义节日的月与日并排（4.380） */
.hd-date { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.hd-date > * { flex: 1; }

/* 联系 - 角色近况：日程与歌单一行一项（4.381） */
.cn-lines .li-sub { white-space: pre-line; }

/* 收藏馆单品大图角上的「查看大图」（4.382） */
.cx-hero-view {
  position: absolute; right: var(--sp-3); bottom: var(--sp-3);
  width: 34px; height: 34px; border-radius: var(--r-full); border: 0;
  background: var(--scrim); color: var(--on-scrim); display: grid; place-items: center;
}

/* 预设 - 正则「试一试」的结果，保留换行（4.383） */
.rx-result { white-space: pre-wrap; word-break: break-word; }

/* 设定集首页的卡片（ARCHITECTURE 4.386） */
.set-sec { padding: var(--sp-4) var(--sp-4) 0; }
.set-sec-title { font-size: var(--fs-13); color: var(--text-3); padding: 0 var(--sp-1) var(--sp-2); }
.set-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.set-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1);
  padding: var(--sp-4); border: 0; border-radius: var(--r-lg);
  background: var(--surface-2); color: var(--text); text-align: left; font: inherit;
}
.set-card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: var(--r-md);
  background: var(--surface); color: var(--text-2); margin-bottom: var(--sp-2);
}
.set-card-name { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.set-card-stat { font-size: var(--fs-12); color: var(--text-3); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 预设的条目顺序（4.387） */
.pe-list { margin: var(--sp-3) 0; background: var(--surface); }
.pe-row { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-1);
  border-bottom: 1px solid var(--border); min-height: 56px; }
.pe-row.is-off .pe-title, .pe-row.is-off .pe-sub { color: var(--text-3); }
.pe-row.is-history { background: var(--surface-2); }
.pe-row.is-fixed { color: var(--text-3); }
.pe-body { flex: 1; min-width: 0; }
.pe-title { font-size: var(--fs-15); display: flex; align-items: center; gap: var(--sp-2); }
.pe-sub { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pe-tag { font-size: var(--fs-11); color: var(--text-3); border: 1px solid var(--border); border-radius: var(--r-full); padding: 0 var(--sp-2); }
.pe-lock { font-size: var(--fs-12); color: var(--text-3); }
/* 两个数字框并排：320 宽时允许各自收窄，不把右边那个挤到屏幕边上（4.522） */
.num-pair { display: inline-flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.num-pair .num-row input { width: 64px; min-width: 2.5em; }
.num-pair .num-row { flex: 0 1 auto; min-width: 0; }
.tpl-view { white-space: pre-wrap; word-break: break-word; font-family: var(--font-mono); font-size: var(--fs-12);
  background: var(--surface-2); border-radius: var(--r-md); padding: var(--sp-3); margin: 0 0 var(--sp-3); color: var(--text-2); }
/* 预设里改说明句（4.701）：格式那几句灰着、改不了，与可改的输入框上下排 */
.tpl-view.tpl-lock { color: var(--text-3); margin: var(--sp-2) 0; }
.caps-count { flex: 1; font-size: var(--fs-13); color: var(--text-3); align-self: center; }

/* 会话菜单顶上四个常用操作（4.390） */
.menu-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); padding: var(--sp-3) var(--sp-4) var(--sp-1); }
.menu-tile { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); padding: var(--sp-3) 0;
  border: 0; border-radius: var(--r-md); background: var(--surface-2); color: var(--text); font: inherit; }
.menu-tile span { font-size: var(--fs-12); color: var(--text-2); }

/* 消息与正文里的 HTML（4.397）。盒子透明，跟着内容变高；color-scheme 与里面那一页一致，深色模式下才不会垫一层白底。
   外面那一层挂 ph-html，作者可以给它加底色、圆角、边框 */
.msg-html { width: 100%; max-width: 100%; min-width: 200px; }
.hf-box { width: 100%; }
.hf-box iframe { display: block; width: 100%; height: var(--hf-h, 24px); border: 0; background: transparent; color-scheme: normal; }
/* 框不接手指：按在框里时外面收不到触摸，长按菜单、左右滑引用都够不着。里面没有脚本，点了也没有反应 */
.msg-html iframe { pointer-events: none; }
.sg-segs > .msg-html { margin: var(--sp-2) 0; }

/* 状态栏（4.399）。线上挂在这一轮之前或之后，线下一段一个。样式走 --ph-status-* / --ph-status-offline-*，
   会话「状态栏」里设的写在包着它的 .sb-wrap 上 */
.sb-wrap { padding: var(--sp-1) 0; }
.sb { font-size: var(--fs-12); line-height: 1.5; padding: var(--sp-2) var(--sp-3); }
.ph-status-online {
  margin-left: calc(var(--ph-avatar-size, 36px) + var(--sp-2)); max-width: 300px;
  color: var(--ph-status-fg, var(--text-2)); background: var(--ph-status-bg, var(--group-fill));
  font-size: var(--ph-status-fs, var(--fs-12)); border-radius: var(--ph-status-r, var(--r-md));
  border: var(--ph-status-bw, 1px) solid var(--ph-status-bc, var(--border));
}
.ph-status-offline {
  color: var(--ph-status-offline-fg, var(--sg-dim, var(--text-2))); background: var(--ph-status-offline-bg, transparent);
  font-size: var(--ph-status-offline-fs, var(--fs-12)); border-radius: var(--ph-status-offline-r, var(--r-md));
  border: var(--ph-status-offline-bw, 1px) solid var(--ph-status-offline-bc, var(--border));
}
.sb-row { display: flex; gap: var(--sp-3); align-items: baseline; }
.sb-row + .sb-row { margin-top: 2px; }
.sb-key { flex: none; min-width: 3.5em; opacity: .7; white-space: nowrap; }
.sb-val { min-width: 0; overflow-wrap: anywhere; }
.sb-bar { display: inline-block; width: 96px; height: 6px; border-radius: 3px; background: color-mix(in srgb, currentColor 15%, transparent);
  overflow: hidden; vertical-align: middle; margin-right: var(--sp-2); }
.sb-bar i { display: block; height: 100%; width: var(--sb-p, 0%); background: var(--accent); border-radius: 3px; }
.sb-sample { margin: var(--sp-2) 0 var(--sp-3); }
.sb-sample :where(.ph-status-online) { margin-left: 0; }
.sb-head { margin-top: var(--sp-5); }
.sb-place { display: flex; flex-direction: column; gap: var(--sp-2); }
/* 美化的分类浏览（4.811、4.812，apps/skin/Gallery.js）。首页一排排文件夹，每个里面四格缩略；
   点开背景压暗，文件夹从原位放大成中间一块（.gf-panel 只动 transform）；点里面一样再放大看（.zoom-layer：clip-path 从那一格长到整屏） */
.gal-shot-empty { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: var(--text-3); }
.gal-shot-host { display: block; overflow: hidden; width: 100%; height: 100%; }
.gal-shot-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.gal-shot-code { margin: 0; width: 100%; height: 100%; padding: var(--sp-2) var(--sp-3); font-family: var(--font-mono); font-size: var(--fs-11);
  line-height: 1.5; white-space: pre-wrap; word-break: break-all; text-align: left; color: var(--text-2); overflow: hidden; }

.gf-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5) var(--sp-4); padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.gf-tile { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); padding: 0; border: 0; background: none; color: var(--text); min-width: 0; }
/* 一个文件夹：后片带一个标签，中间露出几张纸（里面的前几样），前面一片前盖 */
.gf-icon { --gf-back: color-mix(in srgb, var(--text) 13%, var(--surface)); --gf-front: color-mix(in srgb, var(--text) 7%, var(--surface));
  position: relative; display: block; width: 100%; aspect-ratio: 5 / 4; margin-top: var(--sp-2); perspective: 400px; }
.gf-back { position: absolute; left: 0; right: 0; top: 0; bottom: 0; border-radius: 0 var(--r-sm) var(--r-sm) var(--r-sm); background: var(--gf-back); }
.gf-back::before { content: ''; position: absolute; left: 0; bottom: 100%; width: 44%; height: var(--sp-2); border-radius: var(--r-xs) var(--r-xs) 0 0; background: var(--gf-back); }
.gf-papers { position: absolute; left: 8%; right: 8%; top: 7%; bottom: 12%; transition: transform var(--dur-fast) var(--ease); }
.gf-mini { position: absolute; inset: 0; overflow: hidden; border-radius: var(--r-xs); background: var(--surface); border: 1px solid var(--border); pointer-events: none; }
.gf-mini:where(.is-n2) { transform: translate(6%, -4%) rotate(4deg); }
.gf-mini:where(.is-n1) { transform: translate(-5%, -2%) rotate(-3deg); }
.gf-mini:where(.is-blank) { background: var(--surface-2); }
/* 空着的类只露一张空纸，不画一叠 */
.gf-mini:where(.is-none) { display: none; }
.gf-front { position: absolute; left: 0; right: 0; bottom: 0; height: 58%; border-radius: var(--r-xs) var(--r-xs) var(--r-sm) var(--r-sm);
  background: var(--gf-front); border-top: 1px solid var(--border); transform-origin: 50% 100%;
  display: flex; align-items: flex-end; padding: var(--sp-2) var(--sp-3); color: var(--text-3); transition: transform var(--dur-fast) var(--ease); }
/* 按下去：前盖往下翻一点 */
.gf-tile:active .gf-front { transform: rotateX(-16deg); }
.gf-tile-name { margin-top: var(--sp-1); max-width: 100%; font-size: var(--fs-15); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gf-tile-sub { font-size: var(--fs-12); color: var(--text-3); }
/* 复刻页在纸上铺满：去掉它在美化库里那一圈外边距、边框和固定高度 */
.gf-thumb-in > .skin-preview, .gal-big-shot > .skin-preview { margin: 0; border: 0; border-radius: 0; height: 100%; }
:where(:root[data-motion="off"]) .gf-front, :where(:root[data-motion="off"]) .gf-papers { transition: none; }

/* 缩略：按两倍、三倍的尺寸画，再整块缩小 */
.gf-thumb-in { position: absolute; left: 0; top: 0; display: block; transform-origin: 0 0; }
.gf-thumb-in:where(.is-x1) { width: 100%; height: 100%; }
.gf-thumb-in:where(.is-x2) { width: 200%; height: 200%; transform: scale(.5); }
.gf-thumb-in:where(.is-x3) { width: 300%; height: 300%; transform: scale(.3334); }
.gf-thumb-in > * { width: 100%; height: 100%; }

.gf-layer { position: absolute; inset: 0; z-index: var(--z-sheet); display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); padding: calc(var(--top-inset) + var(--navbar-h) + var(--sp-4)) var(--sp-5) var(--sp-8); }
.gf-scrim { position: absolute; inset: 0; background: color-mix(in srgb, var(--stage-bg) 82%, transparent); opacity: 0; transition: opacity var(--dur-nav) var(--ease-nav); }
.gf-note, .gf-acts { position: relative; opacity: 0; transition: opacity var(--dur-nav) var(--ease-nav); }
.gf-layer:where(.is-open) .gf-scrim, .gf-layer:where(.is-open) .gf-acts { opacity: 1; }
.gf-layer:where(.is-open) .gf-note { opacity: .7; }
/* 打开的大文件夹：和首页那个同一个样子，标签上写着类名。整块只动 transform，从首页那个位置长出来 */
.gf-folder { --gf-back: color-mix(in srgb, var(--text) 13%, var(--surface)); position: relative; display: flex; flex-direction: column; width: 100%; max-width: 420px; min-height: 0; flex: 0 1 auto;
  margin-top: 36px; transform-origin: 50% 50%;
  transition: transform var(--dur-nav) var(--ease-nav), opacity var(--dur-fast) linear; }
/* 收起：缩回首页那一个上，最后一段淡出，露出底下那一个（4.815） */
.gf-folder:where(.is-leaving) { transition: transform var(--dur-nav) var(--ease-nav), opacity var(--dur-fast) linear calc(var(--dur-nav) - var(--dur-fast)); }
.gf-tab { position: absolute; left: 0; bottom: 100%; max-width: 70%; height: 36px; padding: 0 var(--sp-5); display: flex; align-items: center;
  border-radius: var(--r-md) var(--r-md) 0 0; background: var(--gf-back); color: var(--text); font-size: var(--fs-17); font-weight: var(--fw-semi);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gf-panel { min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: var(--sp-4) var(--sp-4) var(--sp-5);
  border-radius: 0 var(--r-xl) var(--r-xl) var(--r-xl); background: var(--gf-back); }
.gf-count { padding: 0 var(--sp-1) var(--sp-3); font-size: var(--fs-12); color: var(--text-2); }
.gf-items { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4) var(--sp-4); }
.gf-item { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; padding: 0; border: 0; background: none; color: var(--text); }
/* 里面的每一样是一张纸 */
.gf-thumb { position: relative; width: 100%; aspect-ratio: 430 / 620; overflow: hidden; border-radius: var(--r-sm); background: var(--surface);
  border: 1px solid var(--border); }
.gf-thumb:where(.is-on) { border-color: var(--text); }
/* 正放大着的那一张：原位空出来，像是被拿起来了 */
.gf-thumb:where(.is-src) { visibility: hidden; }
.gf-item-name { margin-top: var(--sp-1); max-width: 100%; font-size: var(--fs-14); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gf-item-sub { font-size: var(--fs-12); color: var(--text-3); }
.gf-empty { padding: var(--sp-6) var(--sp-2); text-align: center; font-size: var(--fs-13); color: var(--text-2); }
.gf-note { max-width: 420px; text-align: center; font-size: var(--fs-12); line-height: 1.6; color: var(--on-scrim); }
/* 只认应用自己的动效开关（4.813）：系统的「减弱动态效果」不关这里的转场，这一页的转场是用户点名要的 */
:where(:root[data-motion="off"]) .gf-folder, :where(:root[data-motion="off"]) .gf-scrim { transition: none; }

/* 放大看（4.814）：大图本身从那张纸的位置长出来（useFlip 只动 transform），背景另外变暗；没有裁切框，也没有先出来的一块黑底 */
.lb-layer { position: absolute; inset: 0; z-index: var(--z-sheet); container-type: size; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); padding: calc(var(--top-inset) + var(--navbar-h)) var(--sp-4) var(--sp-8); }
.lb-scrim { position: absolute; inset: 0; background: color-mix(in srgb, var(--stage-bg) 90%, transparent); opacity: 0; transition: opacity var(--dur-nav) var(--ease-nav); }
.lb-layer .gal-big-name, .lb-layer .gal-big-acts { position: relative; opacity: 0; transition: opacity var(--dur-nav) var(--ease-nav); }
.lb-layer:where(.is-open) .lb-scrim, .lb-layer:where(.is-open) .gal-big-name, .lb-layer:where(.is-open) .gal-big-acts { opacity: 1; }
/* 和纸一样是复刻页的 430:620，等比放大不变形，复刻页按宽度正好铺满 */
.gal-big-shot { position: relative; width: min(100%, 400px, calc((100cqh - 220px) * 430 / 620)); aspect-ratio: 430 / 620; flex: none; border-radius: var(--r-lg); overflow: hidden; background: var(--surface);
  transition: transform var(--dur-nav) var(--ease-nav); will-change: transform; }
.gal-big-shot > * { width: 100%; height: 100%; }
/* 状态栏样例只有几行：按内容的高度，不撑成一大块空白 */
.gal-big-shot:where(.is-fit) { aspect-ratio: auto; }
:where(:root[data-motion="off"]) .gal-big-shot, :where(:root[data-motion="off"]) .lb-scrim { transition: none; }
.gal-big-name { color: var(--on-scrim); font-size: var(--fs-15); text-align: center; }
.gal-big-acts { display: flex; justify-content: center; gap: var(--sp-2); }
.gal-big-btn { min-width: 88px; height: 36px; padding: 0 var(--sp-4); border-radius: var(--r-full); border: 1px solid color-mix(in srgb, var(--on-scrim) 50%, transparent); background: none; color: var(--on-scrim); font-size: var(--fs-14); }
/* 世界书列表的分组与拖动排序（4.809） */
.lb-group-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
/* 状态栏折叠与最大高度（4.802）。折着时只剩一行（折叠时显示的内容），右上角一个箭头；
   最大高度走 --ph-status-mh / --ph-status-offline-mh，超出的在框里滚动，不带着整页一起滚 */
.sb { position: relative; }
/* 箭头只占标题那一行（4.903，用户：「开启折叠后再展开状态栏，状态栏里展现的内容左右不对称」）：
   从前整块右边多留 20px，展开后下面每一行都偏左。现在只给标题那一行让出箭头的位置，整块左右一样宽 */
:where(.sb.is-foldable) .sb-brief { padding-right: 20px; }
.sb-toggle { position: absolute; top: var(--sp-1); right: var(--sp-1); width: 24px; height: 24px; display: flex; align-items: center;
  justify-content: center; border: 0; background: none; color: inherit; opacity: .6; padding: 0; transition: transform var(--dur-fast) var(--ease); }
:where(.sb.is-folded) .sb-toggle { transform: rotate(-90deg); }
.sb-css-box { margin-top: var(--sp-5); }
.sb-brief { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.sb-body { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
/* 框里的滚动条不画（4.903，用户要的）：照样能滑，超出的那几行在框底下截断，看得出还有 */
.sb-body::-webkit-scrollbar { display: none; }
:where(.ph-status-online) .sb-body { max-height: var(--ph-status-mh, none); }
:where(.ph-status-offline) .sb-body { max-height: var(--ph-status-offline-mh, none); }

/* 锁脸照片多张（4.402）：失败的图上「改为只传一张」，角色卡上的一排照片 */
.face-pick { margin-top: var(--sp-2); }
.face-pick-go, .face-pick-cancel {
  border: 1px solid var(--border); background: transparent; color: inherit;
  border-radius: var(--r-full); padding: var(--sp-1) var(--sp-3); font-size: var(--fs-12);
}
.face-pick-tip { font-size: var(--fs-12); color: var(--text-3); margin-bottom: var(--sp-2); }
.face-pick-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.face-pick-item {
  position: relative; width: 56px; height: 56px; padding: 0; border: 2px solid transparent;
  border-radius: var(--r-md); overflow: hidden; background: var(--surface-2);
}
.face-pick-item.is-on { border-color: var(--accent); }
.face-pick-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.face-pick-item span {
  position: absolute; left: 2px; bottom: 2px; font-size: var(--fs-11); line-height: 1.4;
  padding: 0 4px; border-radius: var(--r-sm); background: var(--scrim-fill); color: var(--on-scrim-fill);
}
.face-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); margin-top: var(--sp-3); }
.face-cell { position: relative; aspect-ratio: 1; border-radius: var(--r-md); overflow: hidden; background: var(--surface-2); padding: 0; border: 0; }
.face-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.face-cell .face-n, .face-cell .face-one {
  position: absolute; bottom: 4px; font-size: var(--fs-11); line-height: 1.4; padding: 0 5px;
  border-radius: var(--r-sm); background: var(--scrim-fill); color: var(--on-scrim-fill);
}
.face-cell .face-n { left: 4px; }
.face-cell .face-one { right: 4px; }
.face-add {
  aspect-ratio: 1; border-radius: var(--r-md); border: 1.5px dashed var(--border); background: transparent;
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}

/* ---- 商城（4.403） ---- */
.ml-sub { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }
.ml-price { color: var(--danger); font-weight: var(--fw-semi); font-size: var(--fs-15); }
.ml-price.is-big { font-size: var(--fs-24); }
.ml-thumb {
  background: var(--surface-2); color: var(--text-3); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.ml-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.ml-bar { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.ml-search {
  flex: 1; min-width: 0; height: 36px; border-radius: var(--r-full); border: 0;
  background: var(--surface-2); color: var(--text); padding: 0 var(--sp-4); font-size: var(--fs-14);
}
.ml-ib { width: 36px; height: 36px; border-radius: var(--r-full); flex: none; }
.ml-ib:where(.is-dark) { background: var(--text); color: var(--bg); }
.ml-ib:where(.is-on) { color: var(--danger); }

.ml-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); padding: 0 var(--sp-4) var(--sp-4); }
.ml-card {
  display: flex; flex-direction: column; text-align: left; padding: 0; border: 0; color: inherit;
  background: var(--surface); border-radius: var(--r-lg); overflow: hidden;
}
.ml-card-img { width: 100%; aspect-ratio: 1; }
.ml-card-title {
  padding: var(--sp-2) var(--sp-3) 0; font-size: var(--fs-14); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ml-card-price { padding: var(--sp-1) var(--sp-3) 0; color: var(--danger); font-weight: var(--fw-semi); }
.ml-card-meta {
  display: flex; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3) var(--sp-3); font-size: var(--fs-11); color: var(--text-3);
}
.ml-tag {
  display: inline-block; margin-left: var(--sp-1); padding: 0 5px; border-radius: var(--r-sm);
  font-size: var(--fs-11); vertical-align: 1px; background: var(--surface-3); color: var(--text-2);
}
.ml-tag:where(.is-auction) { background: var(--danger-weak); color: var(--danger); }

.ml-me {
  display: flex; align-items: center; gap: var(--sp-3); width: calc(100% - 2 * var(--sp-4));
  margin: var(--sp-4); padding: var(--sp-4); border: 0; border-radius: var(--r-lg);
  background: var(--surface-2); color: inherit; text-align: left;
}
.ml-me-body { flex: 1; min-width: 0; }
.ml-me-nick { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.ml-me-face { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-4); }

.ml-gallery { display: flex; gap: 2px; overflow-x: auto; scroll-snap-type: x mandatory; }
.ml-gallery-cell { flex: none; width: 100%; padding: 0; border: 0; scroll-snap-align: start; }
.ml-gallery-img { width: 100%; aspect-ratio: 1; }
.ml-price-line { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-2); }
.ml-title { font-size: var(--fs-17); font-weight: var(--fw-semi); margin: var(--sp-2) 0; }
.ml-desc { font-size: var(--fs-14); line-height: 1.7; white-space: pre-wrap; margin-bottom: var(--sp-2); }
.ml-seller {
  display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4);
  padding-top: var(--sp-4); border-top: 1px solid var(--border);
}
.ml-seller-body { flex: 1; min-width: 0; }
.ml-foot {
  position: sticky; bottom: 0; display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + var(--safe-bottom)); background: var(--bg);
  border-top: 1px solid var(--border);
}
.ml-foot > .ml-ib { margin-right: auto; }
.ml-buy-row { display: flex; gap: var(--sp-3); align-items: center; margin-bottom: var(--sp-3); }
.ml-buy-img { width: 56px; height: 56px; border-radius: var(--r-md); flex: none; }

.ml-form .field { margin-bottom: var(--sp-3); }
.ml-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.ml-save {
  border: 0; border-radius: var(--r-full); padding: var(--sp-1) var(--sp-4);
  background: var(--text); color: var(--bg); font-size: var(--fs-14); margin-right: var(--sp-2);
}
.ml-save:disabled { opacity: .5; }
.ml-source {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; padding: var(--sp-3) var(--sp-4);
  border: 0; border-radius: var(--r-lg); background: var(--surface-2); color: inherit; margin-bottom: var(--sp-3);
}
.ml-source-k { color: var(--text-2); font-size: var(--fs-14); }
.ml-source-v { flex: 1; text-align: right; font-size: var(--fs-14); }
.ml-switch-row {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg); background: var(--surface-2); margin-bottom: var(--sp-3); font-size: var(--fs-14);
}
.ml-switch-row > div { flex: 1; min-width: 0; }
.ml-photos { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-4); }
.ml-photo { position: relative; aspect-ratio: 1; border-radius: var(--r-md); overflow: hidden; }
.ml-photo-img { width: 100%; height: 100%; }
.ml-photo-x {
  position: absolute; top: 4px; right: 4px; width: 20px; height: 20px; padding: 0; border: 0;
  border-radius: var(--r-full); background: var(--scrim-fill); color: var(--on-scrim-fill);
  display: flex; align-items: center; justify-content: center;
}
.ml-photo-add {
  border: 1.5px dashed var(--border); color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}

.ml-chat { display: flex; flex-direction: column; height: 100%; }
.ml-goods {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; padding: var(--sp-3) var(--sp-4);
  border: 0; background: var(--surface); color: inherit; text-align: left;
}
.ml-chat > .ml-goods { border-bottom: 1px solid var(--border); }
.pad > .ml-goods { border-radius: var(--r-lg); margin: var(--sp-3) 0; background: var(--surface-2); }
.ml-goods-img { width: 48px; height: 48px; border-radius: var(--r-md); flex: none; }
.ml-goods-body { flex: 1; min-width: 0; font-size: var(--fs-14); }
.ml-goods-act {
  flex: none; padding: var(--sp-1) var(--sp-4); border-radius: var(--r-full);
  background: var(--text); color: var(--bg); font-size: var(--fs-13);
}
.ml-chat-state {
  padding: var(--sp-2) var(--sp-4); font-size: var(--fs-12); color: var(--text-2);
  background: var(--surface-2); text-align: center;
}
.ml-chat-body { flex: 1; min-height: 0; padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.ml-sys { align-self: center; font-size: var(--fs-12); color: var(--text-3); text-align: center; }
.ml-msg { display: flex; align-items: flex-end; gap: var(--sp-2); max-width: 85%; }
.ml-msg:where(.is-mine) { align-self: flex-end; flex-direction: row-reverse; }
.ml-bubble {
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-lg); background: var(--surface-2);
  font-size: var(--fs-15); line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}
.ml-msg:where(.is-mine) .ml-bubble { background: var(--text); color: var(--bg); }
.ml-offer {
  min-width: 180px; padding: var(--sp-3); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border);
}
.ml-offer:where(.is-closed) { opacity: .7; }
.ml-offer-k { font-size: var(--fs-12); color: var(--text-3); }
.ml-offer-v { font-size: var(--fs-20); font-weight: var(--fw-semi); color: var(--danger); margin: var(--sp-1) 0; }
.ml-offer-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.ml-offer-btn {
  flex: 1; padding: var(--sp-1) 0; border-radius: var(--r-full); border: 1px solid var(--border);
  background: transparent; color: inherit; font-size: var(--fs-13);
}
.ml-offer-btn:where(.is-primary) { background: var(--text); color: var(--bg); border-color: var(--text); }
.ml-composer {
  padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + var(--safe-bottom));
  border-top: 1px solid var(--border); background: var(--bg);
}
.ml-chips { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.ml-chips:empty { display: none; }
.ml-chip {
  padding: 2px var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border);
  background: transparent; color: var(--text-2); font-size: var(--fs-12);
}
.ml-input-row { display: flex; align-items: center; gap: var(--sp-2); }
.ml-input {
  flex: 1; min-width: 0; height: 36px; border-radius: var(--r-full); border: 0;
  background: var(--surface-2); color: var(--text); padding: 0 var(--sp-4); font-size: var(--fs-15);
}

.ml-phase { font-size: var(--fs-20); font-weight: var(--fw-semi); margin-bottom: var(--sp-3); }
.ml-steps { display: flex; justify-content: space-between; gap: 2px; }
.ml-steps span {
  flex: 1; text-align: center; font-size: var(--fs-11); color: var(--text-3);
  padding-top: var(--sp-2); border-top: 3px solid var(--surface-3);
}
.ml-steps span.is-done { color: var(--text); border-top-color: var(--text); }
.ml-kv { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-2) 0; font-size: var(--fs-14); }
.ml-kv > span:first-child { color: var(--text-3); }
.ml-track { margin: var(--sp-3) 0; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.ml-track-row { display: flex; gap: var(--sp-3); padding: var(--sp-2) 0; font-size: var(--fs-14); color: var(--text-2); }
.ml-track-row.is-now { color: var(--text); }
.ml-track-dot { flex: none; width: 8px; height: 8px; margin-top: 6px; border-radius: var(--r-full); background: var(--surface-3); }
.ml-track-row.is-now .ml-track-dot { background: var(--text); }
.ml-card-box { margin: var(--sp-3) 0; padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.ml-box-title { font-weight: var(--fw-semi); margin-bottom: var(--sp-3); }
.ml-stars { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-3); }
.ml-star { padding: 0; border: 0; background: transparent; color: var(--surface-3); }
.ml-star.is-on { color: var(--text); }
.ml-review { padding: var(--sp-3) 0; border-top: 1px solid var(--border); font-size: var(--fs-14); }
.ml-acts { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.ml-row-img { width: 44px; height: 44px; border-radius: var(--r-md); }
.ml-row-img.is-sm { width: 36px; height: 36px; }
.ml-dot {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-full);
  background: var(--danger); color: var(--on-accent); font-size: var(--fs-11);
  display: inline-flex; align-items: center; justify-content: center;
}
.ml-photo-gen { flex-direction: column; gap: var(--sp-1); background: transparent; font-size: var(--fs-12); }
.ml-photo-gen:disabled { opacity: .45; }
.ml-blank {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-3);
  aspect-ratio: 4 / 3; background: var(--surface-2); color: var(--text-3); padding: var(--sp-4); text-align: center;
}
.ml-blank-btn {
  display: inline-flex; align-items: center; gap: var(--sp-1); padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--bg); color: var(--text); font-size: var(--fs-13);
}
.ml-blank-btn:disabled { opacity: .5; }
.ml-nick-row { display: flex; gap: var(--sp-2); align-items: center; }
.ml-nick-row > input { flex: 1; min-width: 0; }

/* 聊天里的商城卡片（4.405） */
.mall-card {
  display: flex; gap: var(--sp-3); width: 240px; max-width: 100%; padding: var(--sp-2);
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.mall-card-img {
  flex: none; width: 72px; height: 72px; border-radius: var(--r-md); background: var(--surface-2) center / cover no-repeat;
  background-image: var(--img, none); display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.mall-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mall-card-title { font-size: var(--fs-14); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mall-card-price { font-weight: var(--fw-semi); }
.mall-card-meta { margin-top: auto; display: flex; align-items: center; gap: 3px; font-size: var(--fs-11); color: var(--text-3); }
/* 聊天里的梦境卡片（4.444） */
.dream-card {
  display: flex; flex-direction: column; gap: var(--sp-2); width: 260px; max-width: 100%; padding: var(--sp-3);
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.dream-card-head { display: flex; align-items: center; gap: 4px; font-size: var(--fs-12); color: var(--text-3); }
.dream-card-level { margin-left: auto; }
.dream-card-said { font-size: var(--fs-14); line-height: 1.5; }
.dream-card-text {
  font-size: var(--fs-13); line-height: 1.7; color: var(--text-2); white-space: pre-wrap;
  max-height: 240px; overflow-y: auto; overscroll-behavior: contain;
}
.dream-card-frags { display: flex; flex-direction: column; gap: var(--sp-2); }
.dream-card-frag { font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); padding-left: var(--sp-2); border-left: 2px solid var(--border); }
.dream-card-mood { font-size: var(--fs-13); color: var(--text-2); }
.mall-shot {
  width: 250px; max-width: 100%; border-radius: var(--r-lg); overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
}
.mall-shot-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); background: var(--surface); }
.mall-shot-img {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-sm); background: var(--surface-2) center / cover no-repeat;
  background-image: var(--img, none); display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.mall-shot-what { flex: 1; min-width: 0; font-size: var(--fs-13); }
.mall-shot-sub { font-size: var(--fs-11); color: var(--text-3); }
.mall-shot-price { flex: none; font-size: var(--fs-13); font-weight: var(--fw-semi); }
.mall-shot-lines { display: flex; flex-direction: column; gap: 6px; padding: var(--sp-3); }
.mall-shot-line { display: flex; }
.mall-shot-line > span {
  max-width: 85%; padding: 4px 10px; border-radius: var(--r-md); background: var(--surface);
  font-size: var(--fs-12); line-height: 1.5; word-break: break-word;
}
.mall-shot-line:where(.is-own) { justify-content: flex-end; }
.mall-shot-line:where(.is-own) > span { background: var(--text); color: var(--bg); }
/* 密语的纸条卡片（4.413）。挂着契约钩子 .ph-slip-card：状态一律包进 :where() */
.slip-card {
  width: 240px; max-width: 100%; padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.slip-card-head { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-3); }
.slip-card-text { margin: var(--sp-3) 0; font-family: var(--font-serif); font-size: var(--fs-15); line-height: 1.8; white-space: pre-wrap; word-break: break-word; }
.slip-card-meta { font-size: var(--fs-11); color: var(--text-3); }
.slip-card:where(.is-folded) {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); width: 160px;
  background: var(--surface-2); border-style: dashed;
}
.slip-card-fold { position: relative; display: block; width: 56px; height: 40px; border-radius: var(--r-xs); background: var(--surface); border: 1px solid var(--border-2); }
.slip-card-fold span { position: absolute; left: 0; right: 0; top: 50%; border-top: 1px dashed var(--border-2); }
.slip-draw, .slip-reveal {
  width: 260px; max-width: 100%; padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.slip-draw-who { margin-top: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }
.slip-draw-roles { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px dashed var(--border-2); }
.slip-draw-role { display: flex; gap: var(--sp-2); font-size: var(--fs-13); }
.slip-draw-k { flex: none; min-width: 2.5em; font-size: var(--fs-11); color: var(--text-3); line-height: 1.8; }
.slip-draw-again {
  display: block; width: 100%; margin-top: var(--sp-3); padding: var(--sp-2); border: 1px solid var(--border-2);
  border-radius: var(--r-md); background: transparent; color: var(--text-2); font-size: var(--fs-13);
}
.slip-reveal-q { margin: var(--sp-2) 0 var(--sp-3); font-family: var(--font-serif); font-size: var(--fs-15); line-height: 1.7; }
.slip-reveal-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.slip-reveal-a {
  display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); font-size: var(--fs-13); line-height: 1.6; word-break: break-word;
}
.mall-shot-sys { align-self: center; font-size: var(--fs-11); color: var(--text-3); }
.ml-note {
  margin: var(--sp-2) 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); font-size: var(--fs-13); line-height: 1.5;
}
.ml-ib:where(.is-busy) { opacity: .4; pointer-events: none; }
.ml-ib:where(.is-busy) svg { animation: ml-spin var(--dur-slow) linear infinite; }
@keyframes ml-spin { to { transform: rotate(360deg); } }
.ml-typing { align-self: flex-start; font-size: var(--fs-12); color: var(--text-3); }
.ml-nick-row > .num-row { flex: 1; min-width: 0; }
.ml-auction { padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); margin-bottom: var(--sp-3); }
.ml-auction-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.ml-bids { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-1); }
.ml-bid { display: grid; grid-template-columns: 1fr auto auto; gap: var(--sp-3); align-items: baseline; font-size: var(--fs-13); color: var(--text-2); }
.ml-bid:where(.is-top) { color: var(--text); font-weight: var(--fw-semi); }
.tp-mall-me { display: flex; flex-direction: column; gap: 2px; margin: var(--sp-4); padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.tp-mall-me b { font-size: var(--fs-17); }
.tp-mall-img {
  width: 40px; height: 40px; border-radius: var(--r-md); background: var(--surface-2) center / cover no-repeat;
  background-image: var(--img, none); display: flex; align-items: center; justify-content: center; color: var(--text-3);
}

/* ---- 密语（4.411，界面 4.412）---- */
.mz-home { padding: var(--sp-2) var(--sp-4) var(--sp-8); }
.mz-sec { margin: var(--sp-6) 0 var(--sp-3); font-size: var(--fs-13); color: var(--text-3); letter-spacing: .04em; }
.mz-label { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.mz-hint { margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); line-height: 1.6; }
.mz-hint:where(.is-center) { text-align: center; }
.mz-link { display: block; margin: var(--sp-6) auto 0; padding: var(--sp-2) var(--sp-4); border: 0; background: transparent; color: var(--text-3); font-size: var(--fs-13); }

/* 顶上那一块：张数 + 圆形的抽一张 */
.mz-hero {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5);
  border-radius: var(--r-xl); background: var(--surface-2);
}
.mz-hero-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.mz-hero-k { font-size: var(--fs-13); color: var(--text-2); }
.mz-hero-n { font-family: var(--font-serif); font-size: var(--fs-40); line-height: 1.1; color: var(--text); }
.mz-hero-n span { margin-left: var(--sp-1); font-family: var(--font); font-size: var(--fs-14); color: var(--text-3); }
.mz-hero-sub { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }
.mz-draw {
  flex: none; width: 76px; height: 76px; border: 0; border-radius: var(--r-full);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: var(--text); color: var(--bg); font-size: var(--fs-11);
}
.mz-draw:disabled { opacity: .25; }

/* 角色：头像、名字、两枚小签 */
.mz-people { display: flex; flex-direction: column; gap: var(--sp-1); }
.mz-person { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; }
.mz-person-name { flex: 1; min-width: 0; font-size: var(--fs-15); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mz-person-sub { display: block; font-size: var(--fs-11); color: var(--text-3); }
.mz-pill {
  display: inline-flex; align-items: center; gap: 4px; padding: 6px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); background: transparent; color: var(--text); font-size: var(--fs-12);
}
.mz-pill:where(.is-locked) { color: var(--text-3); }

/* 两列：纸条盒卡片与纸条 */
.mz-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.mz-box {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); min-height: 112px;
  padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); color: inherit; text-align: left;
}
.mz-box:where(.is-new) { border-style: dashed; color: var(--text-3); justify-content: center; }
.mz-box-name { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.mz-box-n { font-size: var(--fs-11); color: var(--text-3); }
.mz-faces { display: inline-flex; }
.mz-faces-one { display: inline-flex; border-radius: var(--r-full); box-shadow: 0 0 0 2px var(--surface); }
.mz-faces-one + .mz-faces-one { margin-left: -8px; }

.mz-tile {
  position: relative; display: flex; flex-direction: column; gap: var(--sp-2); min-height: 132px; text-align: left;
  padding: var(--sp-4) var(--sp-3) var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
}
.mz-tile:where(.is-capsule) { border-style: double; border-width: 3px; }
.mz-tile-cat { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-3); }
.mz-tile-text {
  flex: 1; font-family: var(--font-serif); font-size: var(--fs-14); line-height: 1.7; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.mz-tile-foot { font-size: var(--fs-11); color: var(--text-3); }
.mz-tile:where(.is-folded) { align-items: center; justify-content: center; text-align: center; background: var(--surface-2); border-color: transparent; }
.mz-tile:where(.is-folded) .mz-tile-cat { font-size: var(--fs-13); color: var(--text-2); }

/* 折起来的纸条：一个小方块，中间一道折痕 */
.mz-fold {
  position: relative; display: block; width: 34px; height: 24px; border-radius: var(--r-xs);
  background: var(--surface); border: 1px solid var(--border-2);
}
.mz-fold-line { position: absolute; left: 0; right: 0; top: 50%; border-top: 1px dashed var(--border-2); }
.mz-fold:where(.is-big) { width: 120px; height: 84px; border-radius: var(--r-sm); }
.mz-folded {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); width: 100%;
  padding: var(--sp-8) var(--sp-4); border: 0; border-radius: var(--r-xl); background: var(--surface-2); color: var(--text-2);
}
.mz-folded-cat { font-size: var(--fs-15); color: var(--text); }
.mz-folded-hint { font-size: var(--fs-12); color: var(--text-3); }

/* 展开的纸条 */
.mz-paper {
  padding: var(--sp-5) var(--sp-5) var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.mz-paper:where(.is-capsule) { border-style: double; border-width: 3px; }
.mz-paper-head { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.mz-paper-to { margin-left: auto; color: var(--text-3); }
.mz-paper-text {
  margin: var(--sp-5) 0; font-family: var(--font-serif); font-size: var(--fs-17); line-height: 1.9;
  white-space: pre-wrap; word-break: break-word;
}
.mz-paper:where(.is-big) .mz-paper-text { font-size: var(--fs-20); min-height: 96px; }
.mz-paper-foot { font-size: var(--fs-11); color: var(--text-3); letter-spacing: .03em; }

/* 抽到一张：整屏 */
.mz-stage { background: var(--bg); color: var(--text); display: flex; flex-direction: column; }
.mz-stage-close {
  position: absolute; right: var(--sp-2); top: calc(var(--top-inset) + var(--sp-2));
  width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--text-2);
}
.mz-stage-body { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: var(--sp-4); padding: var(--sp-6) var(--sp-5); }
.mz-stage-kicker { text-align: center; font-size: var(--fs-12); color: var(--text-3); }
.mz-stage-acts {
  display: flex; justify-content: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5) calc(var(--safe-bottom) + var(--sp-5));
}
.mz-act {
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-full); border: 1px solid var(--border);
  background: transparent; color: var(--text); font-size: var(--fs-14);
}
.mz-act:where(.is-strong) { background: var(--text); color: var(--bg); border-color: var(--text); }
.mz-unfold { animation: mz-unfold var(--dur-slow) var(--ease-out); transform-origin: top center; }
@keyframes mz-unfold { from { opacity: 0; transform: scaleY(.5); } to { opacity: 1; transform: none; } }

/* 详情 */
.mz-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); font-size: var(--fs-12); color: var(--text-3); }
.mz-meta-box { padding: 0; border: 0; background: transparent; color: var(--text-2); font-size: var(--fs-12); text-decoration: underline; text-underline-offset: 3px; }
.mz-toggles { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.mz-toggle {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); background: transparent; color: var(--text-2); font-size: var(--fs-13);
}
.mz-toggle:where(.is-on) { background: var(--text); border-color: var(--text); color: var(--bg); }
.mz-why { margin-top: var(--sp-4); padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.mz-why-k { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-13); color: var(--text-2); margin-bottom: var(--sp-2); }
.mz-why-k span { font-size: var(--fs-11); color: var(--text-3); }
.mz-why-v { font-size: var(--fs-14); line-height: 1.7; white-space: pre-wrap; }
.mz-why-in {
  width: 100%; border: 0; background: transparent; color: var(--text); font: inherit; font-size: var(--fs-14);
  line-height: 1.7; resize: none; outline: none; padding: 0;
}
.mz-write {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2); width: 100%; margin-top: var(--sp-4);
  padding: var(--sp-3); border: 1px dashed var(--border-2); border-radius: var(--r-lg); background: transparent; color: var(--text-2); font-size: var(--fs-14);
}
.mz-thread { display: flex; flex-direction: column; }
.mz-thread-row {
  display: flex; gap: var(--sp-3); padding: var(--sp-2) 0 var(--sp-2) calc(var(--mz-depth, 0) * var(--sp-4));
  border: 0; background: transparent; color: inherit; text-align: left;
}
.mz-thread-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mz-thread-k { font-size: var(--fs-11); color: var(--text-3); }
.mz-thread-v { font-family: var(--font-serif); font-size: var(--fs-14); line-height: 1.6; }
.mz-thread-v:where(.is-folded) { font-family: var(--font); color: var(--text-3); }
.mz-thread-row:where(.is-here) .mz-thread-v { font-weight: var(--fw-semi); }
.mz-line { position: relative; padding-left: var(--sp-4); }
.mz-line::before { content: ''; position: absolute; left: 4px; top: 8px; bottom: 8px; border-left: 1px solid var(--border); }
.mz-line-row { position: relative; display: flex; padding: var(--sp-2) 0; }
.mz-line-dot { position: absolute; left: calc(-1 * var(--sp-4) + 1px); top: 14px; width: 7px; height: 7px; border-radius: var(--r-full); background: var(--text-3); }
.mz-line-body { display: flex; flex-direction: column; gap: 2px; }
.mz-line-v { font-size: var(--fs-13); color: var(--text); }
.mz-line-t { font-size: var(--fs-11); color: var(--text-3); }

/* 纸条盒页 */
.mz-scroll { display: flex; gap: var(--sp-2); overflow-x: auto; scrollbar-width: none; margin-top: var(--sp-4); padding-bottom: 2px; }
.mz-scroll::-webkit-scrollbar { display: none; }
.mz-wrap { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.mz-tab {
  flex: none; display: inline-flex; align-items: center; gap: 6px; padding: 6px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); background: transparent; color: var(--text-2); font-size: var(--fs-13); white-space: nowrap;
  /* 名字长过一整行时在框里换行，不顶出去（4.c158-10） */
  max-width: 100%;
}
.mz-tab:where(.is-face) { white-space: normal; text-align: left; }
.mz-tab:where(.is-face) { padding-left: 4px; }
.mz-tab:where(.is-on) { background: var(--text); border-color: var(--text); color: var(--bg); }
.mz-home > .mz-grid { margin-top: var(--sp-4); }
.mz-empty { padding: var(--sp-8) 0; text-align: center; font-size: var(--fs-13); color: var(--text-3); }
.mz-locked { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); padding: var(--sp-8) var(--sp-6); text-align: center; }
.mz-locked-mark {
  width: 64px; height: 64px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); color: var(--text-2);
}
.mz-locked-t { font-size: var(--fs-15); }
.mz-locked-d { font-size: var(--fs-13); color: var(--text-3); line-height: 1.7; }
.mz-fl + .mz-fl { margin-top: var(--sp-4); }
.mz-fl-k { font-size: var(--fs-12); color: var(--text-3); }

/* 历史 */
.mz-log { display: flex; flex-direction: column; padding: var(--sp-2) var(--sp-4) var(--sp-8); }
.mz-log-row {
  display: flex; gap: var(--sp-3); padding: var(--sp-3) 0; border: 0; border-bottom: 1px solid var(--border);
  background: transparent; color: inherit; text-align: left;
}
.mz-log-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.mz-log-k { font-size: var(--fs-12); color: var(--text-2); }
.mz-log-v { font-family: var(--font-serif); font-size: var(--fs-15); line-height: 1.6; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mz-log-v:where(.is-folded) { font-family: var(--font); font-size: var(--fs-13); color: var(--text-3); }
.mz-log-t { font-size: var(--fs-11); color: var(--text-3); }

/* 写纸条 */
.mz-save {
  border: 0; border-radius: var(--r-full); padding: var(--sp-1) var(--sp-4);
  background: var(--text); color: var(--bg); font-size: var(--fs-14); margin-right: var(--sp-2);
}
.mz-from { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.mz-from-one {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px var(--sp-3) 4px 4px; border-radius: var(--r-full);
  border: 0; background: var(--surface-2); color: var(--text); font-size: var(--fs-13);
}
.mz-editor { margin-top: var(--sp-4); padding: var(--sp-5); border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); }
.mz-editor-text {
  width: 100%; min-height: 150px; border: 0; background: transparent; color: var(--text); resize: none; outline: none; padding: 0;
  font-family: var(--font-serif); font-size: var(--fs-17); line-height: 1.9;
}
.mz-mood-in {
  flex: none; width: 88px; padding: 6px var(--sp-3); border-radius: var(--r-full); border: 1px dashed var(--border-2);
  background: transparent; color: var(--text); font-size: var(--fs-13); outline: none;
}
.mz-quote { padding: var(--sp-3) var(--sp-4); border-left: 2px solid var(--text); margin-bottom: var(--sp-4); }
.mz-quote-k { font-size: var(--fs-11); color: var(--text-3); margin-bottom: 2px; }
.mz-quote-v { font-family: var(--font-serif); font-size: var(--fs-14); line-height: 1.7; white-space: pre-wrap; }

/* 密语第三步（4.414）：今日抽选的提示、每日抽选开关、惊喜纸条 */
.mz-turn {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; margin-bottom: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border: 0; border-radius: var(--r-lg); background: var(--text); color: var(--bg); text-align: left;
}
.mz-turn-k { font-size: var(--fs-11); opacity: .7; }
.mz-turn-v { flex: 1; font-size: var(--fs-14); }
.mz-daily {
  display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg); border: 1px solid var(--border); font-size: var(--fs-14);
}
.mz-daily-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mz-stage-kicker:where(.is-strong) { color: var(--text); font-size: var(--fs-13); letter-spacing: .2em; }
.mz-write:where(.is-solid) { border-style: solid; color: var(--text); }
.mz-log-row:where(.is-daily) { cursor: default; }
.mz-sub { font-size: var(--fs-12); color: var(--text-3); line-height: 1.6; }
/* 同时揭晓（4.415） */
.mz-reveal { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.mz-reveal-a {
  display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); font-size: var(--fs-14); line-height: 1.6; word-break: break-word;
}
.mz-reveal-a:where(.is-sealed) { color: var(--text-3); border: 1px dashed var(--border-2); background: transparent; }
.mz-reveal-k { font-size: var(--fs-11); color: var(--text-3); }
/* 纸条页：看过的人、待完成、随机事件（4.416） */
.mz-facts { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-3); }
.mz-fact { display: flex; gap: var(--sp-3); font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); }
.mz-fact-k { flex: none; min-width: 4.5em; color: var(--text-3); }
.slip-draw-event { margin-top: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }

/* ---- 专注（4.417）---- */
.fc-home { padding: var(--sp-2) var(--sp-4) var(--sp-8); }
.fc-label { margin: var(--sp-6) 0 var(--sp-2); font-size: var(--fs-13); color: var(--text-3); }
.fc-hint { margin-top: var(--sp-2); font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); }
.fc-hint:where(.is-center) { text-align: center; }
.fc-dial { display: flex; flex-direction: column; align-items: center; padding: var(--sp-6) 0 var(--sp-4); }
.fc-dial-n { font-family: var(--font-serif); font-size: var(--fs-56); line-height: 1; color: var(--text); }
.fc-dial-n span { margin-left: var(--sp-1); font-family: var(--font); font-size: var(--fs-15); color: var(--text-3); }
.fc-dial-sub { margin-top: var(--sp-3); font-size: var(--fs-13); color: var(--text-3); text-align: center; }
.fc-chips, .fc-scroll { display: flex; gap: var(--sp-2); align-items: center; }
.fc-chips { flex-wrap: wrap; justify-content: center; }
.fc-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
.fc-chip {
  flex: none; display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border-2); border-radius: var(--r-full); background: transparent; color: var(--text-2); font-size: var(--fs-14);
}
.fc-chip:where(.is-face) { padding-left: var(--sp-2); }
.fc-chip:where(.is-on) { background: var(--text); border-color: var(--text); color: var(--bg); }
.fc-chip-in { width: 120px; }
.fc-task { display: flex; gap: var(--sp-2); }
.fc-task-in {
  flex: 1; min-width: 0; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text); font-size: var(--fs-15);
}
.fc-task-pick {
  flex: none; display: inline-flex; align-items: center; gap: var(--sp-1); padding: 0 var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); color: var(--text-2); font-size: var(--fs-13);
}
.fc-start {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2); width: 100%; margin-top: var(--sp-8);
  padding: var(--sp-4); border: 0; border-radius: var(--r-full); background: var(--text); color: var(--bg); font-size: var(--fs-17);
}

/* 正在专注：整页倒计时 */
.fc-run { display: flex; flex-direction: column; align-items: center; min-height: 100%; padding: var(--sp-8) var(--sp-4); text-align: center; }
.fc-run-k { font-size: var(--fs-13); letter-spacing: .08em; color: var(--text-3); }
.fc-run-clock { margin: var(--sp-6) 0 var(--sp-3); font-family: var(--font-serif); font-size: var(--fs-56); line-height: 1; font-variant-numeric: tabular-nums; color: var(--text); }
.fc-run:where(.is-rest) .fc-run-clock { color: var(--text-3); }
.fc-run-task { margin: var(--sp-2) 0; font-size: var(--fs-17); line-height: 1.6; color: var(--text); text-align: center; }
.fc-run-meta { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-3); font-size: var(--fs-13); color: var(--text-3); }
.fc-run-with { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); margin-top: var(--sp-6); font-size: var(--fs-14); color: var(--text-2); }
.fc-run-foot { width: 100%; margin-top: auto; padding-top: var(--sp-8); }

/* 长按提前结束：按住时一条底色从左到右走满 */
.fc-hold {
  position: relative; overflow: hidden; width: 100%; padding: var(--sp-4); border: 1px solid var(--border-2); border-radius: var(--r-full);
  background: transparent; color: var(--text-2); font-size: var(--fs-15); touch-action: none;
}
.fc-hold-bar { position: absolute; inset: 0; width: 0; background: var(--surface-2); transition: width 120ms linear; }
.fc-hold:where(.is-holding) .fc-hold-bar { width: 100%; transition: width var(--fc-hold, 3000ms) linear; }
.fc-hold-label { position: relative; }

/* 记录 */
.fc-sum { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); margin-top: var(--sp-4); text-align: center; }
.fc-sum-n { font-family: var(--font-serif); font-size: var(--fs-28); color: var(--text); }
.fc-sum-k { margin-top: var(--sp-1); font-size: var(--fs-11); color: var(--text-3); }
.fc-bars { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-2); height: 120px; margin-top: var(--sp-6); align-items: end; }
.fc-bar { display: flex; flex-direction: column; justify-content: flex-end; height: 100%; gap: var(--sp-1); }
.fc-bar-v { height: var(--fc-h, 0%); min-height: 2px; border-radius: var(--r-xs); background: var(--text-3); }
.fc-bar-k { font-size: var(--fs-11); color: var(--text-3); text-align: center; }
.fc-rows { display: flex; flex-direction: column; }
.fc-row {
  display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-3) 0; border: 0;
  border-bottom: 1px solid var(--border); background: transparent; color: var(--text); font-size: var(--fs-14); text-align: left;
}
.fc-row-v { flex: none; color: var(--text-3); font-size: var(--fs-13); }
.fc-done { margin-top: var(--sp-4); }
/* 陪伴角色（4.418） */
.fc-say {
  max-width: 320px; margin: var(--sp-3) auto 0; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface-2); color: var(--text); font-size: var(--fs-15); line-height: 1.7; text-align: left;
}
.fc-lines {
  width: 100%; padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text); font-size: var(--fs-14); line-height: 1.7; resize: vertical;
}
.fc-save { padding: var(--sp-1) var(--sp-3); border: 0; border-radius: var(--r-full); background: var(--text); color: var(--bg); font-size: var(--fs-14); }
.fc-go { width: 100%; justify-content: center; margin-top: var(--sp-4); padding: var(--sp-3); }
/* 锁 app（4.419） */
.fc-lock { margin-top: var(--sp-2); }
.fc-lock .fc-row { align-items: center; }
/* 屏幕使用时间的提醒线（4.848） */
.st-line { align-items: center; }
.st-line > span:first-child { flex: 1; }
.fc-perm { flex: none; padding: var(--sp-1) var(--sp-3); border: 0; border-radius: var(--r-full); background: var(--text); color: var(--bg); font-size: var(--fs-13); }
.fc-search { display: block; width: 100%; margin: var(--sp-4) 0 var(--sp-2); }
.fc-app {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; padding: var(--sp-3) 0; border: 0;
  border-bottom: 1px solid var(--border); background: transparent; color: var(--text); font-size: var(--fs-15); text-align: left;
}
.fc-app:disabled { opacity: .55; }
.fc-app-ic { flex: none; width: 36px; height: 36px; border-radius: var(--r-md); background: var(--surface-2); object-fit: cover; }
.fc-app-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fc-tick {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px;
  border: 1px solid var(--border-2); border-radius: var(--r-full); color: var(--bg);
}
.fc-tick:where(.is-on) { border-color: var(--text); background: var(--text); }
/* 苹果快捷指令（4.420） */
.fc-again { margin: var(--sp-3) auto 0; padding: var(--sp-2) var(--sp-4); }
.fc-steps { margin: 0; padding-left: var(--sp-5); color: var(--text); font-size: var(--fs-14); line-height: 1.8; }
.fc-steps li + li { margin-top: var(--sp-1); }
.fc-code { padding: 0 var(--sp-1); border-radius: var(--r-xs); background: var(--surface-2); font-family: var(--font-mono); font-size: var(--fs-13); }
.fc-name { width: 50%; padding: var(--sp-1) var(--sp-2); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); color: var(--text); font-size: var(--fs-14); text-align: right; }
.fc-guide-btns { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }
.fc-guide-btns > * { flex: 1; justify-content: center; padding: var(--sp-3); }

/* ---- 花园（4.423，原型） ---- */
.hb-home { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) var(--sp-6); }
.hb-search {
  width: 100%; padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text); font-size: var(--fs-14);
}
.hb-chips { display: flex; gap: var(--sp-2); overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.hb-chips::-webkit-scrollbar { display: none; }
.hb-chip {
  flex: none; padding: 5px var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--surface); color: var(--text-2); font-size: var(--fs-13); white-space: nowrap;
}
.hb-chip:where(.is-on) { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.hb-sub { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.hb-sub-k { flex: none; font-size: var(--fs-12); color: var(--text-3); }
.hb-sub > .hb-chips { flex: 1; min-width: 0; }

.hb-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
.hb-card {
  display: flex; flex-direction: column; min-width: 0; padding: 0; border: 1px solid var(--border); text-align: left;
  background: var(--surface); color: inherit; border-radius: var(--r-lg); overflow: hidden;
}
.hb-card-body { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) var(--sp-3) var(--sp-3); min-width: 0; }
.hb-card-title { font-size: var(--fs-14); font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-card-sum {
  font-size: var(--fs-12); line-height: 1.45; color: var(--text-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.hb-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-2); margin-top: 2px; font-size: var(--fs-11); color: var(--text-3); }

.hb-cover { display: grid; place-items: center; aspect-ratio: 4 / 3; color: var(--text-3); background: var(--surface-2); }
.hb-cover:where(.is-t2) { background: var(--surface-3); }
.hb-cover:where(.is-t3) { background: var(--accent-weak); }
.hb-cover:where(.is-t4) { background: var(--group-fill); }
.hb-cover:where(.has-img) { background: var(--surface-2); overflow: hidden; }
.hb-cover-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.hb-cover:where(.is-big) { aspect-ratio: 16 / 9; border-radius: var(--r-lg); }

.hb-badge {
  display: inline-block; padding: 0 6px; border: 1px solid var(--border-2); border-radius: var(--r-xs);
  font-size: var(--fs-11); line-height: 18px; color: var(--text-2); white-space: nowrap;
}
.hb-badge:where(.is-adult) { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.hb-badge:where(.is-soft) { border-color: transparent; background: var(--surface-2); }

.hb-note { padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); font-size: var(--fs-12); line-height: 1.6; color: var(--text-2); }
.hb-label { margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.hb-rows { display: flex; flex-direction: column; border-radius: var(--r-md); background: var(--surface-2); overflow: hidden; }
.hb-row {
  display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3); border: 0; text-align: left;
  background: none; color: var(--text); font-size: var(--fs-14); line-height: 1.5;
}
.hb-row + .hb-row { border-top: 1px solid var(--border); }
.hb-row:where(.is-on) { font-weight: var(--fw-semi); background: var(--accent-weak); }
.hb-row:where(.is-muted) { color: var(--text-3); }
.hb-row-t { flex: 1; min-width: 0; }
.hb-row:where(.hb-row-col) { flex-direction: column; align-items: stretch; gap: 2px; }
.hb-row-k { font-size: var(--fs-12); color: var(--text-3); }
.hb-row-v { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 16em; overflow: auto; }
.hb-row-d { margin-top: 2px; font-size: var(--fs-12); color: var(--text-3); }

.hb-up {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2); width: 100%; padding: var(--sp-3);
  border: 0; border-radius: var(--r-md); background: var(--accent); color: var(--on-accent); font-size: var(--fs-15);
}
.hb-up:disabled { opacity: .35; }
.hb-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.hb-btn {
  flex: 1; padding: var(--sp-3); border: 1px solid var(--border-2); border-radius: var(--r-md);
  background: var(--surface); color: var(--text); font-size: var(--fs-15);
}
.hb-btn:where(.is-primary) { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.hb-d-title { font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1.35; }
.hb-d-meta { font-size: var(--fs-12); color: var(--text-3); }
.hb-d-badges { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.hb-d-sum { font-size: var(--fs-14); line-height: 1.7; color: var(--text-2); }

.hb-steps { display: flex; gap: var(--sp-1); }
.hb-step {
  flex: 1; min-width: 0; padding-top: var(--sp-2); border-top: 2px solid var(--border);
  font-size: var(--fs-11); color: var(--text-3); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hb-step:where(.is-done) { border-top-color: var(--text-3); }
.hb-step:where(.is-on) { border-top-color: var(--accent); color: var(--text); font-weight: var(--fw-medium); }
.hb-shot {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
  aspect-ratio: 16 / 9; border: 1px dashed var(--border-2); border-radius: var(--r-lg); color: var(--text-3); font-size: var(--fs-13);
}
.hb-shot-img { display: block; max-width: 60%; max-height: 320px; margin: 0 auto var(--sp-3); border-radius: var(--r-md); box-shadow: var(--shadow-1); }
/* 第四批导入确认页的预览（4.434）：卡片、组件、网页工具各在不给脚本的盒子里，宽高经变量传进来 */
.hb-frame-wrap { display: flex; justify-content: center; padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); overflow: auto; }
.hb-frame { display: block; width: var(--hb-fw, 100%); max-width: 100%; height: var(--hb-fh, 240px); border: 0; border-radius: var(--r-md); background: var(--surface); }
.hb-css { margin: 0; padding: var(--sp-3); max-height: 240px; overflow: auto; border-radius: var(--r-md); background: var(--surface-2);
  font-family: var(--font-mono); font-size: var(--fs-11); line-height: 1.5; white-space: pre-wrap; word-break: break-all; color: var(--text-2); }
.hb-rules { margin: 0; padding-left: var(--sp-5); font-size: var(--fs-14); line-height: 1.8; color: var(--text-2); }
.hb-rules li + li { margin-top: var(--sp-2); }

/* 花园「我的」：推特个人主页的版式 */
.hb-tw { position: relative; }
/* 头图：推特在手机上是顶到屏幕最上沿的，看着比 3:1 高。这里没有导航栏，头图铺到顶，
   内容区按 5:2，再加上顶部安全区（content-box，padding 不算进比例里） */
.hb-tw-banner {
  display: block; width: 100%; aspect-ratio: 5 / 2; border: 0; padding: 0; box-sizing: content-box;
  background: var(--surface-3) var(--hb-banner, none) center / cover no-repeat;
}
.page:where(.is-bare) .hb-tw-banner { padding-top: var(--top-inset, 0px); }
.hb-tw-banner:where(.is-edit) { display: grid; place-items: center; color: var(--on-scrim); }
.hb-tw-banner:where(.is-edit) > * { padding: var(--sp-2); border-radius: var(--r-full); background: var(--scrim); box-sizing: content-box; }
.hb-tw-top { display: flex; align-items: flex-start; justify-content: space-between; padding: 0 var(--sp-4); margin-top: -44px; }
/* 头像压在头图上 44px；按钮从头图下沿往下 12px 开始，和推特一样 */
.hb-tw-top > .hb-tw-edit { margin-top: calc(44px + var(--sp-3)); }
.hb-tw-face { position: relative; padding: 0; border: 4px solid var(--bg); border-radius: var(--r-full); background: var(--bg); line-height: 0; }
.hb-tw-face-cam {
  position: absolute; inset: 0; display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--scrim); color: var(--on-scrim);
}
.hb-tw-edit {
  padding: 7px var(--sp-4); border: 1px solid var(--border-2); border-radius: var(--r-full);
  background: var(--bg); color: var(--text); font-size: var(--fs-14); font-weight: var(--fw-semi);
}
.hb-tw-save {
  padding: 5px var(--sp-4); border: 0; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent); font-size: var(--fs-14); font-weight: var(--fw-semi);
}
.hb-tw-info { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4) 0; }
.hb-tw-name { font-size: var(--fs-24); font-weight: var(--fw-bold); line-height: 1.2; }
.hb-tw-handle { margin-top: -10px; font-size: var(--fs-15); color: var(--text-2); }
.hb-tw-bio { font-size: var(--fs-15); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.hb-tw-meta { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font-size: var(--fs-15); color: var(--text-2); }
.hb-tw-meta > * { display: inline-flex; align-items: center; gap: var(--sp-1); }
.hb-tw-link { padding: 0; border: 0; background: none; color: var(--accent); font-size: inherit; }
.hb-tw-counts { display: flex; gap: var(--sp-4); }
.hb-tw-counts > button { padding: 0; border: 0; background: none; color: var(--text-2); font-size: var(--fs-14); }
.hb-tw-counts b { color: var(--text); font-weight: var(--fw-bold); }

.hb-tw-tabs { display: flex; margin-top: var(--sp-3); border-bottom: 1px solid var(--border); }
.hb-tw-tab {
  flex: 1; display: flex; justify-content: center; padding: 0; border: 0; background: none;
  color: var(--text-2); font-size: var(--fs-15); font-weight: var(--fw-medium);
}
.hb-tw-tab > span { padding: var(--sp-3) 0; border-bottom: 4px solid transparent; }
.hb-tw-tab:where(.is-on) { color: var(--text); font-weight: var(--fw-bold); }
.hb-tw-tab:where(.is-on) > span { border-bottom-color: var(--accent); }

.hb-tw-post {
  display: flex; gap: var(--sp-3); width: 100%; padding: var(--sp-3) var(--sp-4); border: 0;
  border-bottom: 1px solid var(--border); background: none; color: inherit; text-align: left;
}
.hb-tw-post-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hb-tw-post-head { display: flex; gap: var(--sp-1); min-width: 0; font-size: var(--fs-15); white-space: nowrap; }
.hb-tw-post-head > b { font-weight: var(--fw-bold); overflow: hidden; text-overflow: ellipsis; flex: none; max-width: 50%; }
.hb-tw-post-head > span { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; }
.hb-tw-post-text { font-size: var(--fs-15); line-height: 1.45; }
.hb-tw-post-sum { font-size: var(--fs-15); line-height: 1.45; color: var(--text-2); }
.hb-tw-post-card { margin-top: var(--sp-2); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.hb-tw-post-card .hb-cover { aspect-ratio: 16 / 9; }
.hb-tw-post-card-k { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-13); color: var(--text-2); border-top: 1px solid var(--border); }
.hb-tw-post-acts { display: flex; gap: var(--sp-6); margin-top: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }
.hb-tw-post-acts > span { display: inline-flex; align-items: center; gap: var(--sp-1); }

.hb-tw-foot { padding: var(--sp-4); font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); }
.hb-tw-rules { padding: 0; border: 0; background: none; color: var(--text-2); font-size: inherit; text-decoration: underline; }
.hb-tw-fab {
  position: sticky; bottom: var(--sp-4); display: flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; margin: 0 var(--sp-4) var(--sp-4) auto; border: 0; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent); box-shadow: var(--shadow-2);
}

/* 浮在头图上的那一层：返回、更多两个圆钮一直在；滚过名字后底色与名字淡入 */
.hb-tw-sticky { position: sticky; top: 0; z-index: 3; height: 0; }
.hb-tw-bar {
  position: absolute; top: 0; left: 0; right: 0; display: flex; align-items: center; gap: var(--sp-3);
  padding: calc(var(--top-inset, 0px) + var(--sp-2)) var(--sp-3) var(--sp-2);
}
.hb-tw-bar::before {
  content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity var(--dur) var(--ease);
  background: linear-gradient(var(--scrim-strong), var(--scrim-strong)), var(--surface-3) var(--hb-banner, none) center / cover no-repeat;
}
.hb-tw-bar-t {
  flex: 1; min-width: 0; display: flex; flex-direction: column; color: var(--on-scrim); opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.hb-tw-bar-t > b { font-size: var(--fs-17); font-weight: var(--fw-bold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-tw-bar-t > span { font-size: var(--fs-13); opacity: .8; }
.hb-tw-bar:where(.is-shown)::before, .hb-tw-bar:where(.is-shown) .hb-tw-bar-t { opacity: 1; }
/* 没有头图时（4.774，用户：「往下滑动的时候顶栏会突然变成灰色」）：从前垫的是灰底再盖一层深色遮罩，滑过名字就冒出一条深灰。
   现在用页面本身的底色、正常颜色的字，底下一道细线，和别的页的顶栏一样；两个圆钮在收起后也换成透明底。有头图时照旧显示头图 */
.hb-tw-bar:where(.is-plain)::before { background: var(--bg); box-shadow: 0 1px 0 var(--border); }
.hb-tw-bar:where(.is-plain) .hb-tw-bar-t { color: var(--text); }
.hb-tw-bar:where(.is-plain.is-shown) .hb-tw-round { background: transparent; color: var(--text); }
.hb-tw-bar:where(.is-plain) .hb-tw-round { transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.hb-tw-round {
  flex: none; display: grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 0;
  border-radius: var(--r-full); background: var(--scrim); color: var(--on-scrim);
}
/* 开了悬浮返回键（data-nav="back"）：外壳的悬浮键正好压在头图左上角这一个的位置上，
   同一个位置不放两个返回，自己这个让位。用 visibility 不用 display，栏里的标题位置不变 */
:root[data-nav="back"] .hb-tw-back { visibility: hidden; }

/* 花园举报队列（设置 - 登录账号 - 花园举报队列，4.430） */
.hq-reports { display: flex; flex-direction: column; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-3); }
.hq-rep { background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-3); }
.hq-rep-head { display: flex; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.hq-rep-who { color: var(--text-2); font-weight: var(--fw-medium); }
.hq-rep-reason { font-size: var(--fs-14); color: var(--text); margin-top: var(--sp-1); }
.hq-rep-note { font-size: var(--fs-13); color: var(--text-2); line-height: 1.6; margin-top: var(--sp-1); white-space: pre-wrap; word-break: break-word; }
.hq-rep-act { margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--danger); background: none; border: 0; padding: 0; }
.hq-rep-act:disabled { opacity: .5; }

/* 花园第五批（4.435）：点赞收藏一排、评论区、广场的帖子 */
.hb-acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.hb-act { display: inline-flex; align-items: center; gap: var(--sp-1); padding: 6px var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border);
  background: var(--surface); font-size: var(--fs-13); color: var(--text-2); }
.hb-act:where(.is-on) { color: var(--accent); border-color: var(--accent); }
.hb-note:where(.is-warn) { color: var(--text); background: var(--accent-weak); }
.hb-cms { display: flex; flex-direction: column; border-radius: var(--r-md); background: var(--surface-2); overflow: hidden; }
.hb-cm { display: flex; gap: var(--sp-2); padding: var(--sp-3); text-align: left; background: none; border: 0; color: inherit; }
.hb-cm + .hb-cm { border-top: 1px solid var(--border); }
.hb-cm:where(.is-hidden) { opacity: .6; }
.hb-cm-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hb-cm-head { display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-13); }
.hb-cm-head > span:last-child { margin-left: auto; color: var(--text-3); font-size: var(--fs-12); }
.hb-cm-text { font-size: var(--fs-14); line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
.hb-cm-to { color: var(--text-3); }
.hb-cm-tip { font-size: var(--fs-12); color: var(--text-3); }
.hb-cm-box { display: flex; flex-direction: column; gap: var(--sp-2); }
.hb-cm-box > .hb-btn { align-self: flex-end; min-width: 88px; }
.hb-cm-replying { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-12); color: var(--text-2); }
.hb-cm-replying > button { background: none; border: 0; color: var(--accent); font-size: var(--fs-12); }
.hb-pz-list { display: flex; flex-direction: column; }
.hb-pz { display: flex; gap: var(--sp-3); padding: var(--sp-3) 0; text-align: left; background: none; border: 0; color: inherit; }
.hb-pz + .hb-pz { border-top: 1px solid var(--border); }
.hb-pz-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.hb-pz-text { font-size: var(--fs-15); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
.hb-pz-head { display: flex; align-items: center; gap: var(--sp-2); }
.hb-pz-who { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: var(--fs-13); }
.hb-pz-who > span { color: var(--text-3); font-size: var(--fs-12); }
.hb-pz-full { font-size: var(--fs-15); line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.hb-state { padding: 1px var(--sp-2); border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); font-size: var(--fs-12); }
.hb-state:where(.is-done) { background: var(--accent-weak); color: var(--accent); }
.hb-imgs { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px; border-radius: var(--r-md); overflow: hidden; }
.hb-imgs:where(.is-1) { grid-template-columns: 1fr; }
.hb-imgs > img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; background: var(--surface-2); }
.hb-imgs:where(.is-full) { grid-template-columns: 1fr; }
.hb-imgs:where(.is-full) > img { aspect-ratio: auto; }
.hb-imgs:where(.is-edit) { grid-template-columns: repeat(4, 1fr); overflow: visible; }
.hb-img-cell { position: relative; }
.hb-img-cell > img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--r-sm); display: block; }
.hb-img-x { position: absolute; top: 2px; right: 2px; width: 22px; height: 22px; border-radius: 50%; border: 0; display: grid; place-items: center;
  background: var(--surface); color: var(--text); }
.hb-img-add { aspect-ratio: 1; border-radius: var(--r-sm); border: 1px dashed var(--border); display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; font-size: var(--fs-11); color: var(--text-3); text-align: center; }

/* 消息列表里的「花园通知」与它的那一页（4.435）：服务通知的样子，一张张卡片 */
.hub-inbox-face { width: 46px; height: 46px; border-radius: 50%; flex: none; display: grid; place-items: center;
  background: var(--ph-tile-plate, var(--tile-bg)); color: var(--text); box-shadow: 0 0 0 1px var(--border); }
.hub-inbox { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-4) var(--sp-4) var(--sp-6); }
.hub-inbox-item { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.hub-inbox-time { font-size: var(--fs-12); color: var(--text-3); text-align: center; }
.hub-inbox-card { width: 100%; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4) 0;
  border-radius: var(--r-lg); border: 0; background: var(--surface-2); color: var(--text); text-align: left; }
.hub-inbox-head { font-size: var(--fs-15); font-weight: var(--fw-bold); }
.hub-inbox-body { font-size: var(--fs-14); line-height: 1.6; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; }
.hub-inbox-gone { font-size: var(--fs-12); color: var(--text-3); }
.hub-inbox-foot { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-2) 0 var(--sp-3);
  border-top: 1px solid var(--border); font-size: var(--fs-13); color: var(--text-2); }

/* ---- 梦境（4.442）---- */
.dm-head { padding: var(--sp-4) var(--sp-4) var(--sp-2); }
.dm-title { font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1.4; }
.dm-meta { margin-top: var(--sp-1); font-size: var(--fs-13); color: var(--text-3); }
.dm-body { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.dm-scene + .dm-scene { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--border); }
.dm-text { font-size: var(--fs-17); line-height: 1.9; color: var(--text); white-space: pre-wrap; word-break: break-word; }
.dm-trans { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px dashed var(--border); font-size: var(--fs-14); line-height: 1.8; color: var(--text-2); white-space: pre-wrap; word-break: break-word; }

/* ---- 论坛（ARCHITECTURE 4.445） ---- */
.fr-sub { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }
.fr-center { text-align: center; }
.fr-link { border: 0; background: none; color: var(--accent); font-size: var(--fs-13); padding: 0; }
.fr-tag {
  display: inline-block; margin-left: var(--sp-1); padding: 0 var(--sp-1); border-radius: var(--r-xs);
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-11); line-height: 1.6; vertical-align: middle;
}
.fr-tag:where(.is-admin) { background: var(--accent-weak); color: var(--accent); }
.fr-tag:where(.is-ban) { background: var(--danger-weak); color: var(--danger); }
.fr-sec { margin: var(--sp-3) var(--sp-4); background: var(--surface); border-radius: var(--r-lg); overflow: hidden; }
.fr-sec-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: var(--sp-3) var(--sp-4) var(--sp-1); font-size: var(--fs-13); color: var(--text-2); font-weight: var(--fw-semi);
}
.fr-row {
  display: flex; gap: var(--sp-3); width: 100%; text-align: left; border: 0; background: none; color: inherit;
  padding: var(--sp-3) var(--sp-4);
}
:where(.fr-row) + .fr-row { border-top: 1px solid var(--border); }
.fr-rank { flex: none; width: 20px; font-weight: var(--fw-semi); color: var(--text-3); font-size: var(--fs-15); line-height: 1.4; }
.fr-rank:where(.is-top) { color: var(--danger); }
.fr-row-body { flex: 1; min-width: 0; }
.fr-row-title { font-size: var(--fs-15); font-weight: var(--fw-semi); line-height: 1.4; word-break: break-word; }
.fr-row-text {
  margin-top: var(--sp-1); font-size: var(--fs-13); color: var(--text-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fr-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-1); font-size: var(--fs-11); color: var(--text-3);
}
.fr-meta .ellipsis { max-width: 40%; }
.fr-meta-n { display: inline-flex; align-items: center; gap: 2px; }
.is-gone { color: var(--text-3); font-style: italic; font-weight: normal; }
.fr-me {
  display: flex; align-items: center; gap: var(--sp-3); width: calc(100% - var(--sp-4) * 2);
  margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-4); border: 0; border-radius: var(--r-lg);
  background: var(--surface); color: inherit; text-align: left;
}
.fr-me-body { flex: 1; min-width: 0; }
.fr-me-nick { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.fr-face-pick { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.fr-post { padding: var(--sp-4); background: var(--surface); }
.fr-post-title { font-size: var(--fs-17); font-weight: var(--fw-semi); line-height: 1.4; margin-bottom: var(--sp-3); word-break: break-word; }
.fr-post-body { margin-top: var(--sp-3); font-size: var(--fs-15); line-height: 1.8; white-space: pre-wrap; word-break: break-word; }
.fr-floor-head { display: flex; align-items: center; gap: var(--sp-2); }
.fr-floor-who { flex: 1; min-width: 0; }
.fr-name { display: flex; align-items: center; font-size: var(--fs-14); font-weight: var(--fw-semi); min-width: 0; }
.fr-floors-head { padding: var(--sp-4) var(--sp-4) var(--sp-2); font-size: var(--fs-13); color: var(--text-2); font-weight: var(--fw-semi); }
.fr-floor { padding: var(--sp-3) var(--sp-4); background: var(--surface); border-top: 1px solid var(--border); }
.fr-floor-text { margin: var(--sp-2) 0 0 38px; font-size: var(--fs-15); line-height: 1.7; white-space: pre-wrap; word-break: break-word; }
.fr-quote {
  margin: var(--sp-2) 0 0 38px; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-13); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fr-acts { display: flex; gap: var(--sp-4); margin: var(--sp-2) 0 0 38px; }
.fr-post .fr-acts { margin-left: 0; }
.fr-act { display: inline-flex; align-items: center; gap: var(--sp-1); border: 0; background: none; padding: 0; color: var(--text-3); font-size: var(--fs-12); }
.fr-act:where(.is-on) { color: var(--danger); }
/* 帖子页整页是一列，至少撑满滚动区：帖子短的时候，输入框也落在最底下（margin-top: auto），长了就贴底（sticky） */
.fr-thread { display: flex; flex-direction: column; min-height: 100%; }
.fr-board-bar { display: flex; align-items: center; gap: var(--sp-2); }
.fr-board-bar .segmented { flex: 1; }
.fr-composer {
  margin-top: auto; position: sticky; bottom: 0; padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + env(safe-area-inset-bottom));
  background: var(--bg); border-top: 1px solid var(--border);
}
.fr-replying { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.fr-composer-row { display: flex; align-items: center; gap: var(--sp-2); }
.fr-anon {
  flex: none; border: 1px solid var(--border); background: var(--surface); color: var(--text-2);
  border-radius: var(--r-full); padding: var(--sp-1) var(--sp-3); font-size: var(--fs-12);
}
.fr-anon:where(.is-on) { background: var(--text); color: var(--bg); border-color: var(--text); }
.fr-input {
  flex: 1; min-width: 0; border: 0; border-radius: var(--r-full); background: var(--surface-2); color: var(--text);
  padding: var(--sp-2) var(--sp-3); font-size: var(--fs-15);
}
.fr-send { flex: none; }
.fr-report { padding: var(--sp-3) var(--sp-4); }
.fr-report + .fr-report { border-top: 1px solid var(--border); }
.fr-report-target { display: block; width: 100%; text-align: left; border: 0; background: none; color: inherit; padding: 0; }
.fr-report-text {
  margin-top: var(--sp-1); font-size: var(--fs-14); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.fr-report-reason { margin: var(--sp-2) 0 var(--sp-1); font-size: var(--fs-14); line-height: 1.5; }
.fr-report-reason .fr-tag { margin: 0 var(--sp-2) 0 0; }
.fr-report .btn-row { margin-top: var(--sp-2); }
.fr-report-done { margin-top: var(--sp-1); }
.fr-tag:where(.is-yes) { background: var(--danger-weak); color: var(--danger); }
.fr-tag:where(.is-no) { background: var(--accent-weak); color: var(--accent); }
.fr-court {
  margin-top: var(--sp-4); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.fr-court-line { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-14); }
.fr-jurors { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.fr-juror {
  padding: 2px var(--sp-2); border-radius: var(--r-full); background: var(--surface); color: var(--text-2);
  font-size: var(--fs-12); line-height: 1.6;
}
.fr-juror:where(.is-yes) { background: var(--danger-weak); color: var(--danger); }
.fr-juror:where(.is-no) { background: var(--accent-weak); color: var(--accent); }
.fr-verdict { font-size: var(--fs-15); font-weight: var(--fw-semi); line-height: 1.6; }

/* 论坛帖子的转发卡片（4.445 第二版 B） */
.forum-card {
  display: flex; flex-direction: column; gap: var(--sp-1); width: 240px; max-width: 100%; padding: var(--sp-3);
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.forum-card-title { font-size: var(--fs-14); font-weight: var(--fw-semi); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.forum-card-body { font-size: var(--fs-12); color: var(--text-2); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.forum-card-meta { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-3); }
.forum-card-meta .ellipsis { flex: 1; min-width: 0; }
/* 作者名写得长时同样收进这一行（4.716） */
.forum-card-meta > span:last-child:not(.ellipsis) { flex: 0 1 auto; min-width: 0; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forum-card-title, .forum-card-body { overflow-wrap: anywhere; }
.forum-card-gone { font-size: var(--fs-11); color: var(--text-3); }
/* 论坛私信（4.445 第二版 D） */
.fr-unread {
  display: inline-block; min-width: 18px; padding: 0 5px; border-radius: var(--r-full);
  background: var(--danger); color: var(--on-accent); font-size: var(--fs-11); line-height: 18px; text-align: center;
}
.fr-dm-list { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.fr-dm { display: flex; }
.fr-dm:where(.is-mine) { justify-content: flex-end; }
.fr-dm-bubble {
  max-width: 78%; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-lg); background: var(--surface);
  font-size: var(--fs-15); line-height: 1.6; white-space: pre-wrap; word-break: break-word;
}
:where(.fr-dm.is-mine) .fr-dm-bubble { background: var(--text); color: var(--bg); }
.fr-dm-ask { display: flex; justify-content: center; margin-bottom: var(--sp-2); }
.fr-juror:where(.is-char) { border: 1px solid var(--border); }

/* 好友与联机群（4.459）：列表小标、添加好友页、好友资料、会话页 */
.link-mark { flex: none; margin-left: var(--sp-1); padding: 0 var(--sp-1); font-size: var(--fs-11); line-height: 16px; border-radius: var(--r-sm);
  color: var(--text-3); border: 1px solid var(--border); }
.link-friend-plus { width: 44px; height: 44px; border-radius: 50%; flex: none; display: grid; place-items: center; background: var(--surface-2); color: var(--text-2); }
.link-invite { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); padding: var(--sp-4); text-align: center; }
.link-qr { width: 180px; height: 180px; border-radius: var(--r-md); background: #fff; }
.link-code { font-size: var(--fs-20); font-weight: var(--fw-semi); letter-spacing: .12em; font-variant-numeric: tabular-nums; user-select: all; }
.link-invite-btns { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); }
.link-wait { padding: var(--sp-4); display: flex; justify-content: center; }
.link-use { display: flex; gap: var(--sp-2); padding-top: var(--sp-2); }
.link-use input { flex: 1; min-width: 0; }
.link-scan-btns { justify-content: flex-start; }
/* 扫码（4.573）：方形取景，画面铺满；中间一个细框指明对准的位置。黑底不跟主题走，和视频的信箱底色同一个 */
.qr-scan { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); padding: var(--sp-4); }
.qr-scan-view { position: relative; width: 100%; max-width: 360px; aspect-ratio: 1; border-radius: var(--r-md); overflow: hidden; background: var(--stage-bg); }
.qr-scan-video { width: 100%; height: 100%; object-fit: cover; display: block; }
.qr-scan-frame { position: absolute; inset: 18%; border: 2px solid var(--on-scrim); border-radius: var(--r-sm); opacity: .85; pointer-events: none; }
.qr-scan-err { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: var(--sp-5); text-align: center; color: var(--on-scrim); font-size: var(--fs-13); line-height: 1.6; }
.qr-scan-tip { text-align: center; max-width: 360px; }
/* 这一轮的思考（4.580）：原样显示模型写在 <thinking> 里的那一段 */
.think-view { white-space: pre-wrap; word-break: break-word; font-size: var(--fs-14); line-height: 1.7; color: var(--text-2); }
.link-err { padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); color: var(--danger); font-size: var(--fs-13); margin-top: var(--sp-3); }
.link-head { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5) var(--sp-4) var(--sp-3); }
.link-head-info { min-width: 0; }
.link-head-name { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.link-head-sub { font-size: var(--fs-13); color: var(--text-3); margin-top: 2px; word-break: break-all; }
.safety-code { font-size: var(--fs-15); font-variant-numeric: tabular-nums; letter-spacing: .04em; line-height: 1.8; word-spacing: .4em;
  padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); text-align: center; user-select: all; margin-bottom: var(--sp-2); }
.link-lock { align-self: center; display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-3);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-full); background: var(--surface-2); margin-bottom: var(--sp-2); }
.link-tip { font-size: var(--fs-12); color: var(--text-3); text-align: center; padding: var(--sp-1) var(--sp-4); }
/* 牌桌邀请（4.915）：一张小卡片，写谁开了一桌，下面一个「加入」 */
.link-game { display: flex; flex-direction: column; gap: var(--sp-2); width: 210px; padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text); }
.link-game-head { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-14); font-weight: var(--fw-semi); }
.link-game-go { align-self: stretch; height: 34px; border-radius: var(--r-full); border: 1px solid var(--text); background: none; color: var(--text); font-size: var(--fs-13); }
.link-game-go:disabled { opacity: .4; }
.link-friend-plus:where(.is-sm) { width: 36px; height: 36px; }
.link-chars { display: flex; gap: var(--sp-2); overflow-x: auto; padding: var(--sp-1) var(--sp-3); scrollbar-width: none; }
.link-chip { flex: none; font-size: var(--fs-12); color: var(--text-2); padding: 2px var(--sp-3); border-radius: var(--r-full); background: var(--surface-2); }
.stk-edit-swap { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-3); text-align: center; }

/* ---- 自律（4.479）：预算环、三个数、记餐条目、记录页的图。单色 ---- */
.fit-head { display: flex; flex-direction: column; align-items: center; padding: var(--sp-4) var(--sp-5) var(--sp-2); }
/* 起居（4.479）「一日之弧」：一道从晨到夜的弧，记录按时刻落在弧上。数字用衬线体，其余退成小字；线条一律发丝粗 */
.fit-sky { padding: var(--sp-4) var(--sp-5) 0; text-align: center; }
.fit-arc { display: block; width: 100%; max-width: 320px; margin: 0 auto; overflow: visible; }
.fit-arc-track { fill: none; stroke: var(--border-2); stroke-width: 1; }
.fit-arc-ink { fill: none; stroke: var(--text); stroke-width: 2; stroke-linecap: round; transition: stroke-dasharray var(--dur-slow) var(--ease); }
.fit-arc-dot { fill: var(--bg); stroke: var(--text); stroke-width: 1.2; }
.fit-arc-dot:where(.is-workout) { fill: var(--text); }
.fit-arc-now { fill: var(--bg); stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 2 2; }
.fit-arc-end { font-family: var(--font-serif); font-size: 11px; fill: var(--text-3); letter-spacing: .1em; }
.fit-hero { margin-top: calc(-1 * var(--sp-8)); }
.fit-hero-num { font-family: var(--font-serif); font-size: var(--fs-56); line-height: 1; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.fit-hero-cap { font-size: var(--fs-12); color: var(--text-3); letter-spacing: .12em; margin-top: var(--sp-2); }
.fit-stats { display: flex; justify-content: center; gap: var(--sp-8); margin-top: var(--sp-5); }
.fit-stat { display: flex; flex-direction: column; align-items: center; }
.fit-stat b { font-family: var(--font-serif); font-size: var(--fs-20); font-weight: var(--fw-normal); font-variant-numeric: tabular-nums; }
.fit-stat span { font-size: var(--fs-11); color: var(--text-3); margin-top: 2px; letter-spacing: .06em; }
.fit-why { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-3); min-height: 1.4em; }
.fit-why .link { background: none; border: 0; padding: 0; color: var(--text); font-size: inherit; text-decoration: underline; }
.fit-acts { display: flex; justify-content: center; gap: var(--sp-2); padding: var(--sp-4) var(--sp-5) 0; }
.fit-act { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); border: 1px solid var(--border-2); border-radius: var(--r-full); background: none; color: var(--text); font: inherit; font-size: var(--fs-13); }
.fit-foot-note { text-align: center; font-size: var(--fs-11); color: var(--text-3); padding-top: var(--sp-2); }
/* 时间线：左侧一条发丝线，每一条记录一个点 */
.fit-line { position: relative; margin: var(--sp-5) var(--sp-5) var(--sp-4); padding-left: 0; }
.fit-line::before { content: ''; position: absolute; left: 56px; top: 10px; bottom: 10px; width: 1px; background: var(--border-2); }
.fit-ev { position: relative; display: grid; grid-template-columns: 44px 24px minmax(0, 1fr) auto; align-items: center; gap: 0; width: 100%; padding: var(--sp-3) 0; background: none; border: 0; color: var(--text); font: inherit; text-align: left; }
.fit-ev-t { font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; font-variant-numeric: tabular-nums; }
.fit-ev-dot { justify-self: center; width: 7px; height: 7px; border-radius: 50%; background: var(--bg); border: 1px solid var(--text); box-sizing: border-box; }
.fit-ev:where(.is-workout) .fit-ev-dot { background: var(--text); }
.fit-ev:where(.is-empty) .fit-ev-dot { border-color: var(--border-2); }
.fit-ev:where(.is-empty) .fit-ev-main b { color: var(--text-3); font-weight: var(--fw-normal); }
.fit-ev:where(.is-note) .fit-ev-dot { border: 0; width: 3px; height: 3px; background: var(--text-3); }
.fit-ev-main { display: flex; flex-direction: column; min-width: 0; padding-left: var(--sp-2); }
.fit-ev-main b { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.fit-ev-main span { font-size: var(--fs-12); color: var(--text-3); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fit-ev-k { font-family: var(--font-serif); font-size: var(--fs-15); font-variant-numeric: tabular-nums; padding-left: var(--sp-3); }
/* 记录页 */
.fit-weight { padding: var(--sp-5) var(--sp-5) 0; }
.fit-weight-num { font-family: var(--font-serif); font-size: var(--fs-40); line-height: 1; font-variant-numeric: tabular-nums; }
.fit-weight-num span { font-size: var(--fs-14); color: var(--text-3); margin-left: var(--sp-2); letter-spacing: .08em; }
.fit-weight-cap { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-2); }
/* 目标 */
.fit-goal { padding: var(--sp-5) var(--sp-5) var(--sp-3); }
.fit-goal-num { font-family: var(--font-serif); font-size: var(--fs-20); }
.fit-goal-num b { font-size: var(--fs-40); font-weight: var(--fw-normal); line-height: 1; font-variant-numeric: tabular-nums; margin: 0 var(--sp-1); }
.fit-goal-cap { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-2); }
.fit-goal-rule { position: relative; height: 1px; background: var(--border-2); margin: var(--sp-5) 0 var(--sp-2); }
.fit-goal-rule::before { content: ''; position: absolute; left: 0; top: 0; width: var(--p, 0%); height: 1px; background: var(--text); }
.fit-goal-mark { position: absolute; left: var(--p, 0%); top: -4px; width: 9px; height: 9px; margin-left: -5px; border-radius: 50%; background: var(--bg); border: 1px solid var(--text); box-sizing: border-box; }
.fit-goal-ends { display: flex; justify-content: space-between; font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; }
.fit-goal-acts { display: flex; gap: var(--sp-4); margin-top: var(--sp-3); }
/* 周计划：七天一条 */
.fit-wk { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; padding: var(--sp-2) var(--sp-4) var(--sp-3); }
.fit-wk-day { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); padding: var(--sp-2) 0; background: none; border: 0; border-top: 1px solid var(--border-2); color: var(--text); font: inherit; min-width: 0; }
.fit-wk-wd { font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; }
.fit-wk-dot { width: 8px; height: 8px; border-radius: 50%; border: 1px solid var(--border-2); box-sizing: border-box; margin: 2px 0; }
.fit-wk-day:where(.is-on) .fit-wk-dot { background: var(--text); border-color: var(--text); }
.fit-wk-day:where(.is-skipped) .fit-wk-dot { border-color: var(--text); background: var(--bg); }
.fit-wk-lab { font-size: var(--fs-11); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fit-wk-day:where(.is-skipped) .fit-wk-lab { text-decoration: line-through; color: var(--text-3); }
.fit-wk-min { font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); min-height: 1.2em; }
.fit-item { display: grid; grid-template-columns: minmax(0, 1fr) 72px 60px auto auto; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--border); }
.fit-item input { min-width: 0; height: 32px; padding: 0 var(--sp-2); border: 0; border-radius: var(--r-sm); background: var(--surface-2); color: var(--text); font: inherit; font-size: var(--fs-14); }
.fit-item-kcal { text-align: right; font-variant-numeric: tabular-nums; }
.fit-item-unit { font-size: var(--fs-12); color: var(--text-3); }
.fit-item-del { background: none; border: 0; padding: var(--sp-1); color: var(--text-3); }
.fit-row2 { display: flex; gap: var(--sp-2); align-items: center; }
.fit-row2 > input, .fit-row2 > .segmented { flex: 1; min-width: 0; }
.fit-chart { padding: var(--sp-5) var(--sp-5) 0; }
.fit-chart-title { font-size: var(--fs-11); color: var(--text-3); letter-spacing: .1em; margin-bottom: var(--sp-3); }
.fit-svg { display: block; width: 100%; height: 90px; }
.fit-svg .fit-line { fill: none; stroke: var(--text); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.fit-line-faint { fill: none; stroke: var(--border-2); stroke-width: 1; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.fit-bar { fill: var(--surface-3); }
.fit-svg { border-bottom: 1px solid var(--border-2); }
.fit-bar:where(.is-over) { fill: var(--text-2); }
.fit-plan-box { padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md); margin: var(--sp-2) 0 var(--sp-3); }
.fit-plan-row { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-14); line-height: 1.8; }
.fit-plan-row b { font-weight: var(--fw-medium); text-align: right; }
.fit-photo { display: block; width: 100%; max-height: 220px; object-fit: cover; border-radius: var(--r-md); margin-bottom: var(--sp-3); }
.fit-cycle { fill: var(--surface-3); }
.fit-star { background: none; border: 0; padding: var(--sp-1); color: var(--text-3); }
.fit-week .li-sub, .fit-day-sheet .li-sub, .fit-sched .li-sub { white-space: pre-line; }
.fit-stage { display: flex; flex-direction: column; }
.fit-player { position: relative; width: 100%; aspect-ratio: 16 / 9; background: var(--surface-2); }
.fit-player:where(.is-blank) { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--sp-5); box-sizing: border-box; aspect-ratio: auto; min-height: 120px; text-align: center; }
.fit-player-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* 竖屏视频（抖音默认，4.496）：框也竖着，不然播放器只露出中间一截 */
.fit-player:where(.is-tall) { aspect-ratio: 9 / 16; width: 78%; max-width: 420px; margin: 0 auto; }
.fit-clock { padding: var(--sp-6) var(--sp-5) var(--sp-4); text-align: center; }
.fit-clock-num { font-family: var(--font-serif); font-size: var(--fs-56); line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.fit-clock-cap { font-size: var(--fs-12); color: var(--text-3); margin-top: var(--sp-3); letter-spacing: .04em; }
.fit-clock-acts { display: flex; justify-content: center; gap: var(--sp-6); margin-top: var(--sp-5); }
.fit-clock-btn { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); background: none; border: 0; color: var(--text-2); font: inherit; font-size: var(--fs-11); text-decoration: none; }
.fit-clock-btn:where(.is-primary) { color: var(--text); }
.fit-clock-btn:disabled { opacity: .35; }
/* 全屏：视频铺满整屏，计时缩成右上角一小条（4.877，用户：「站内播放没办法真全屏」）。黑底白字，看片子的那一层，不随主题变。
   左上角留给播放器自己的按钮，这一条放右上角 */
.fit-stage:where(.is-on) { position: fixed; inset: 0; z-index: var(--z-modal); background: rgba(0, 0, 0, 1); color: rgba(255, 255, 255, .92); }
.fit-stage:where(.is-on) .fit-player { position: absolute; inset: 0; background: rgba(0, 0, 0, 1); width: 100%; max-width: none; height: 100%; margin: 0; aspect-ratio: auto; }
.fit-stage:where(.is-on) .fit-clock { display: none; }
.fit-stage:where(.is-on) .field-desc { color: rgba(255, 255, 255, .6); }
/* 转过来：播放器按屏幕的高当宽、宽当高，转 90 度，横着的视频在竖着的手机上铺满。宽高由页面量好了给（--turn-w / --turn-h）：
   从前用容器查询单位，iPhone 上给这一层挂 container-type 之后整层只铺了左上一块（用户录屏） */
.fit-stage:where(.is-on) .fit-player:where(.is-turned) { inset: auto; left: 50%; top: 50%; width: var(--turn-w, 100%); height: var(--turn-h, 100%); transform: translate(-50%, -50%) rotate(90deg); }
.fit-stage-bar { position: absolute; right: calc(var(--sp-3) + env(safe-area-inset-right, 0px)); top: calc(var(--sp-3) + var(--safe-top)); z-index: 1; display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3); border-radius: var(--r-full); background: rgba(0, 0, 0, .45); }
.fit-stage-time { font-variant-numeric: tabular-nums; font-size: var(--fs-13); color: rgba(255, 255, 255, .92); margin-right: var(--sp-1); }
.fit-stage-btn { width: 32px; height: 32px; border-radius: 50%; border: 0; background: rgba(255, 255, 255, .14); color: rgba(255, 255, 255, .92); display: flex; align-items: center; justify-content: center; }
/* 游玩时间与白名单（4.480）：顶上三个数，下面三组折叠，每组 20 个一页 */
.pt-head { display: flex; justify-content: space-around; padding: var(--sp-5) var(--sp-5) var(--sp-2); }
.pt-stat { display: flex; flex-direction: column; align-items: center; min-width: 64px; }
.pt-stat b { font-family: var(--font-serif); font-size: var(--fs-28); font-weight: var(--fw-normal); line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--text-2); }
.pt-stat:where(.is-key) b { color: var(--text); font-size: var(--fs-40); }
.pt-stat span { font-size: var(--fs-11); color: var(--text-3); letter-spacing: .1em; margin-top: var(--sp-1); }
.pt-month { text-align: center; font-family: var(--font-serif); font-size: var(--fs-11); color: var(--text-3); letter-spacing: .08em; padding-bottom: var(--sp-4); }
.pt-tools { padding: 0 var(--sp-4) var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.pt-search { display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-3); height: 36px; border-radius: var(--r-full); background: var(--surface-2); color: var(--text-3); }
.pt-search-input { flex: 1; min-width: 0; border: 0; background: none; color: var(--text); font: inherit; font-size: var(--fs-14); outline: none; }
.pt-limit { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.pt-limit .pt-limit-input { width: 56px; height: 28px; min-height: 0; padding: 0; margin: 0; text-align: center; border: 0; border-bottom: 1px solid var(--border-2); border-radius: 0; background: none; box-shadow: none; color: var(--text); font-family: var(--font-serif); font-size: var(--fs-17); outline: none; -moz-appearance: textfield; appearance: textfield; }
.pt-limit .pt-limit-input::-webkit-outer-spin-button, .pt-limit .pt-limit-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pt-group { margin: 0 var(--sp-4); border-top: 1px solid var(--border); }
.pt-group:last-of-type { border-bottom: 1px solid var(--border); }
.pt-group-head { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: baseline; gap: var(--sp-2); width: 100%; padding: var(--sp-4) var(--sp-1); background: none; border: 0; color: var(--text); font: inherit; text-align: left; }
.pt-group-title { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.pt-group-n { font-family: var(--font-serif); font-size: var(--fs-15); color: var(--text-2); font-variant-numeric: tabular-nums; }
.pt-group-desc { font-size: var(--fs-11); color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-group-head svg { align-self: center; color: var(--text-3); }
.pt-rows { padding-bottom: var(--sp-3); }
.pt-row { display: flex; align-items: center; gap: var(--sp-3); width: 100%; padding: var(--sp-3) var(--sp-1); background: none; border: 0; border-top: 1px solid var(--border); color: var(--text); font: inherit; text-align: left; }
.pt-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pt-row-main b { font-size: var(--fs-15); font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-row-main span { font-size: var(--fs-11); color: var(--text-3); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-row-time { flex: none; display: flex; align-items: baseline; gap: 3px; }
.pt-row-time b { font-family: var(--font-serif); font-size: var(--fs-20); font-weight: var(--fw-normal); font-variant-numeric: tabular-nums; }
.pt-row-time span { font-size: var(--fs-11); color: var(--text-3); }
.pt-empty { padding: var(--sp-3) var(--sp-1); font-size: var(--fs-12); color: var(--text-3); border-top: 1px solid var(--border); }
.pt-more { display: block; width: 100%; padding: var(--sp-3); margin-top: var(--sp-1); background: none; border: 0; border-top: 1px dashed var(--border-2); color: var(--text-2); font: inherit; font-size: var(--fs-12); }
.pt-add { padding: var(--sp-5) var(--sp-4) var(--sp-6); }
.pt-add-row { display: flex; gap: var(--sp-2); align-items: center; }
.pt-add-row > input { flex: 1; min-width: 0; }
.pt-foot { font-size: var(--fs-11); color: var(--text-3); line-height: 1.7; margin-top: var(--sp-3); }
/* 第三台设备登录时：选一台退出（4.481） */
.login-devices { display: flex; flex-direction: column; gap: var(--sp-2); width: 100%; margin: var(--sp-4) 0 var(--sp-2); }
.login-device { display: flex; align-items: center; gap: var(--sp-3); width: 100%; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border-2); border-radius: var(--r-md); background: var(--surface); color: var(--text); font: inherit; text-align: left; }
.login-device-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.login-device-main b { font-size: var(--fs-15); font-weight: var(--fw-medium); }
.login-device-main span { font-size: var(--fs-12); color: var(--text-3); margin-top: 2px; }
.login-device-act { flex: none; font-size: var(--fs-13); color: var(--text-2); }
.pt-unlock { padding: 0 var(--sp-4) var(--sp-4); }
.pt-ban { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); width: 100%; margin: 0 0 var(--sp-2); padding: var(--sp-3); border: 1px solid var(--danger); border-radius: var(--r-md); background: none; color: var(--danger); font: inherit; font-size: var(--fs-14); }
.pt-ban-hint { padding: var(--sp-2) var(--sp-1) var(--sp-3); font-size: var(--fs-12); color: var(--text-3); }

/* ---- 音声（ARCHITECTURE 4.488） ---- */
.vd-tags + .vd-tags { margin-top: var(--sp-3); }
.vd-tags-head { font-size: var(--fs-13); color: var(--text-3); }
.vd-view { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.vd-lines { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.vd-line { display: flex; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.vd-line-body { flex: 1; min-width: 0; }
.vd-line-edit { flex: none; color: var(--text-3); }
.vd-lines:where(.is-playing) .vd-line-main { color: var(--text-3); }
.vd-lines:where(.is-playing) .vd-line:where(.is-now) .vd-line-main { color: var(--text); font-weight: var(--fw-semi); }
.vd-line:where(.is-mute) .vd-line-main { color: var(--text-2); }
.vd-player { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--border); background: var(--bg); }
.vd-play { flex: none; }
.vd-time { flex: none; font-size: var(--fs-13); color: var(--text-3); font-variant-numeric: tabular-nums; min-width: 34px; text-align: center; }
.vd-seek { flex: 1; min-width: 0; accent-color: var(--accent); }
.vd-subs { display: inline-flex; gap: var(--sp-3); }
.vd-line:last-child { border-bottom: 0; }
.vd-line-main { font-size: var(--fs-17); line-height: 1.8; color: var(--text); white-space: pre-wrap; word-break: break-word; }
.vd-line-sub { margin-top: var(--sp-1); font-size: var(--fs-14); line-height: 1.7; color: var(--text-2); white-space: pre-wrap; word-break: break-word; }
.vd-act { margin: var(--sp-2) 0 var(--sp-4); }
.vd-line-at { font-size: var(--fs-12); color: var(--text-3); font-variant-numeric: tabular-nums; }
.vd-line:where(.is-note) .vd-line-main { font-size: var(--fs-13); color: var(--text-3); }
.vd-line:where(.is-next) { background: var(--accent-weak); }
.vd-tapbar { position: sticky; bottom: 0; z-index: 2; padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + var(--safe-bottom)); background: var(--bg); border-top: 1px solid var(--border); }
.vd-tap-next { font-size: var(--fs-14); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vd-tap-acts { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-2); }

/* ---- 音声播放页（4.491、4.492）：暗的舞台，不跟主题走 ---- */
.vp { position: relative; height: 100%; display: flex; flex-direction: column; overflow: hidden;
  background: var(--vstage-bg); color: var(--vstage-fg); padding-top: var(--top-inset); }
.vp-bg { position: absolute; inset: 0; pointer-events: none; }
.vp-bg:where(.has-img) { background-image: var(--vp-img); background-size: cover; background-position: center; opacity: .38; }
.vp-bg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to bottom, var(--vstage-shade), var(--vstage-bg) 78%); }
.vp > :not(.vp-bg) { position: relative; }
.vp-top { flex: none; display: grid; grid-template-columns: 88px 1fr 88px; align-items: center; padding: var(--sp-2) var(--sp-3); }
.vp-top-side { display: flex; }
.vp-top-side:where(.is-end) { justify-content: flex-end; }
.vp-top-mid { flex: 1; min-width: 0; text-align: center; }
.vp-top-work { font-size: var(--fs-14); font-weight: var(--fw-semi); }
.vp-top-n { margin-top: 2px; font-size: var(--fs-12); color: var(--vstage-fg-3); }
.vp-btn { flex: none; width: 44px; height: 44px; border: 0; border-radius: var(--r-full); background: transparent;
  color: var(--vstage-fg); display: flex; align-items: center; justify-content: center; }
.vp-btn:disabled { color: var(--vstage-fg-3); }
.vp-stage { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 0 var(--sp-6); }
.vp-art { width: min(68%, 300px); aspect-ratio: 1; border-radius: var(--r-xl); overflow: hidden; flex: none;
  display: flex; align-items: center; justify-content: center; background: var(--vstage-line); color: var(--vstage-fg-2); }
.vp-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vp-title { max-width: 100%; margin-top: var(--sp-5); font-size: var(--fs-17); font-weight: var(--fw-semi); text-align: center; }
.vp-subs { width: 100%; margin-top: var(--sp-5); text-align: center; min-height: 150px; display: flex; flex-direction: column; justify-content: center; gap: var(--sp-2); }
.vp-cap-dim { min-height: 20px; font-size: var(--fs-13); color: var(--vstage-fg-3); }
.vp-cap { font-size: var(--fs-20); line-height: 1.55; font-weight: var(--fw-semi); white-space: pre-wrap; word-break: break-word; }
.vp-cap-none { font-size: var(--fs-14); font-weight: normal; color: var(--vstage-fg-3); }
.vp-cap-sub { min-height: 22px; font-size: var(--fs-15); line-height: 1.6; color: var(--vstage-fg-2); white-space: pre-wrap; word-break: break-word; }
.vp-lyrics { flex: 1; min-height: 0; overflow-y: auto; padding: 0 var(--sp-6); }
.vp-gap { height: 38%; min-height: 140px; }
.vp-line { padding: var(--sp-3) 0; cursor: pointer; }
.vp-main { font-size: var(--fs-17); line-height: 1.6; color: var(--vstage-fg-3); font-weight: var(--fw-semi); white-space: pre-wrap; word-break: break-word; transition: color var(--dur); }
.vp-sub { margin-top: 2px; font-size: var(--fs-13); line-height: 1.6; color: var(--vstage-fg-3); white-space: pre-wrap; word-break: break-word; }
.vp-line:where(.is-now) .vp-main { color: var(--vstage-fg); font-size: var(--fs-20); }
.vp-line:where(.is-now) .vp-sub { color: var(--vstage-fg-2); font-size: var(--fs-15); }
.vp-line:where(.is-note) .vp-main { font-size: var(--fs-13); font-weight: normal; font-style: italic; }
/* Home 横条那一条由舞台自己铺：页面那层的底部留白去掉，不然那里露出页面底色（iOS 主屏幕版底下一条白，4.498） */
.vp-page > .page-body:last-child { padding-bottom: 0; }
.vp-bottom { flex: none; padding: var(--sp-2) var(--sp-6) calc(var(--sp-5) + var(--safe-bottom)); }
.vp-seek { -webkit-appearance: none; appearance: none; width: 100%; height: 18px; margin: 0; background: transparent; }
.vp-seek::-webkit-slider-runnable-track { height: 3px; border-radius: var(--r-full);
  background: linear-gradient(to right, var(--vstage-fg) var(--vp-fill, 0%), var(--vstage-line) var(--vp-fill, 0%)); }
.vp-seek::-moz-range-track { height: 3px; border-radius: var(--r-full); background: var(--vstage-line); }
.vp-seek::-moz-range-progress { height: 3px; border-radius: var(--r-full); background: var(--vstage-fg); }
.vp-seek::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; margin-top: -4.5px; border-radius: var(--r-full); background: var(--vstage-fg); border: 0; }
.vp-seek::-moz-range-thumb { width: 12px; height: 12px; border-radius: var(--r-full); background: var(--vstage-fg); border: 0; }
.vp-times { display: flex; justify-content: space-between; margin-top: 2px; font-size: var(--fs-12); color: var(--vstage-fg-3); font-variant-numeric: tabular-nums; }
.vp-ctrl { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-3); }
.vp-btn:where(.vp-play) { width: 68px; height: 68px; background: var(--vstage-fg); color: var(--vstage-bg); }
.vp-btn:where(.vp-play):disabled { background: var(--vstage-line); color: var(--vstage-fg-3); }
.vp-opts { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-4); }
.vp-opt { display: inline-flex; align-items: center; gap: 6px; border: 0; background: transparent; color: var(--vstage-fg-2); font-size: var(--fs-13); padding: var(--sp-1) 0; }
.vp-opt:where(.is-on) { color: var(--vstage-fg); }
.vp-hint { margin-top: var(--sp-3); text-align: center; font-size: var(--fs-12); color: var(--vstage-fg-3); }
:root:has(.vp-page) .statusbar { background: var(--vstage-bg); }
/* 白天：舞台那几个变量在 .vp 这一层换成白天的值，其余规则不用动 */
.vp:where(.is-day) { --vstage-bg: var(--vstage-day-bg); --vstage-fg: var(--vstage-day-fg); --vstage-fg-2: var(--vstage-day-fg-2);
  --vstage-fg-3: var(--vstage-day-fg-3); --vstage-line: var(--vstage-day-line); --vstage-shade: var(--vstage-day-shade); }
:root:has(.vp:where(.is-day)) .statusbar { background: var(--vstage-day-bg); }
.vd-cover-thumb { width: 36px; height: 36px; border-radius: var(--r-xs); object-fit: cover; display: block; }

/* ---- 配色（4.494）。色块的颜色是用户挑的数据，经变量传进来 ---- */
.pal-row { display: flex; gap: var(--sp-3); overflow-x: auto; padding: var(--sp-2) var(--sp-4) var(--sp-3); scrollbar-width: none; }
.pal-row::-webkit-scrollbar { display: none; }
.pal-sw { flex: none; display: flex; flex-direction: column; align-items: center; gap: 6px; border: 0; background: transparent; padding: 0; color: var(--text-2); }
.pal-chip { position: relative; width: 52px; height: 52px; border-radius: var(--r-md); background: var(--sw-bg, var(--bg));
  box-shadow: inset 0 0 0 1px var(--border-2); display: flex; align-items: center; justify-content: center; overflow: hidden; color: var(--text-2); }
.pal-dot { position: absolute; left: 10px; top: 10px; width: 16px; height: 16px; border-radius: var(--r-full); background: var(--sw-ac, var(--accent)); }
.pal-line { position: absolute; left: 10px; right: 10px; bottom: 12px; height: 4px; border-radius: var(--r-full); background: var(--sw-tx, var(--text)); opacity: .7; }
.pal-chip:where(.is-custom) .pal-dot, .pal-chip:where(.is-custom) .pal-line { display: none; }
.pal-sw:where(.is-on) .pal-chip { box-shadow: inset 0 0 0 2px var(--accent); }
.pal-sw:where(.is-on) .pal-name { color: var(--text); font-weight: var(--fw-semi); }
.pal-name { font-size: var(--fs-12); }
.pal-mode { padding-bottom: var(--sp-2); }
.pal-pick { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.pal-pick input { width: 30px; height: 30px; padding: 0; border: 0; border-radius: var(--r-full); background: transparent; }
/* User 生成器（4.502）：每组一张卡，头上是组名、项数与开关，点开逐项填写；结果按组排 */
.ug-label { font-size: var(--fs-13); color: var(--text-3); margin: var(--sp-4) 0 var(--sp-2); }
.ug-label:first-child { margin-top: 0; }
.ug-modes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); }
.ug-mode { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); min-width: 0; padding: var(--sp-3);
  border-radius: var(--r-md); border: 1px solid var(--border); background: var(--surface); color: var(--text-2); font: inherit; text-align: left; }
.ug-mode:where(.is-on) { border-color: var(--accent); color: var(--text); background: var(--accent-weak); }
.ug-mode-name { font-size: var(--fs-14); font-weight: var(--fw-semi); color: var(--text); }
.ug-mode-desc { font-size: var(--fs-12); color: var(--text-3); line-height: 1.4; }
.ug-refs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin-bottom: var(--sp-4); }
.ug-ref { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); min-width: 0; padding: var(--sp-3);
  border-radius: var(--r-md); border: 1px dashed var(--border-2); background: var(--surface); color: var(--text); font: inherit; text-align: left; }
.ug-ref:where(.is-set) { border-style: solid; border-color: var(--border); background: var(--surface-2); }
.ug-ref-head { display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-12); color: var(--text-3); }
.ug-ref-val { font-size: var(--fs-14); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ug-group { margin-top: var(--sp-3); }
.ug-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); }
.ug-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); background: none; border: 0; padding: 0; color: var(--text); font: inherit; text-align: left; }
.ug-name { font-weight: var(--fw-semi); }
.ug-count { flex: 1; font-size: var(--fs-12); color: var(--text-3); }
.ug-group:where(.is-off) .ug-name { color: var(--text-3); }
.ug-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin-top: var(--sp-2); }
.ug-card { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--surface); }
.ug-card:where(.is-wide) { grid-column: 1 / -1; }
.ug-card:where(.is-filled) { border-color: var(--border-2); background: var(--surface-2); }
.ug-card:focus-within { border-color: var(--accent); }
.ug-card-label { font-size: var(--fs-12); color: var(--text-3); }
.ug-card-hint { font-size: var(--fs-11); color: var(--text-3); line-height: 1.4; }
.ug-card textarea { min-height: 0; resize: none; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none;
  font-size: var(--fs-14); line-height: 1.5; color: var(--text); }
.ug-result { margin-top: var(--sp-2); }
.ug-result-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.ug-result-head .ug-label { margin: var(--sp-4) 0 var(--sp-2); }
.ug-result-head .segmented { flex: 0 0 150px; }
.ug-sec { margin-top: var(--sp-4); }
.ug-sec-title { font-family: var(--font-serif); font-size: var(--fs-15); }
.ug-from { margin-top: var(--sp-3); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); }
.ug-from-head { font-size: var(--fs-12); color: var(--text-3); margin-bottom: var(--sp-2); }
.ug-from-row { font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); }
.ug-from-row + .ug-from-row { margin-top: var(--sp-1); }
.ug-yaml { margin: var(--sp-3) 0 0; padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); font-family: var(--font-mono);
  font-size: var(--fs-12); line-height: 1.7; white-space: pre-wrap; word-break: break-word; color: var(--text); }

/* ---- 监控（4.509）：黑底小屏、REC、镜头名，此刻在画面里的那一格描边 ---- */
.mon-hint { margin-top: var(--sp-3); }
.mon-now { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); line-height: 1.5; }
.mon-now-dot { flex: none; width: 8px; height: 8px; border-radius: var(--r-full); background: var(--danger); }
.mon-wall { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: var(--sp-3); }
.mon-tile { position: relative; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; min-width: 0;
  aspect-ratio: 16 / 10; padding: var(--sp-2); border-radius: var(--r-sm); overflow: hidden; text-align: left;
  background: var(--film); color: var(--on-film); outline: 1px solid var(--film-edge); outline-offset: -1px; }
.mon-tile:where(.is-live) { outline: 2px solid var(--on-film); outline-offset: -5px; }
.mon-tile:where(.is-on) { outline: 2px dashed var(--on-film-2); outline-offset: -5px; }
.mon-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .72; }
.mon-rec { position: absolute; top: var(--sp-2); left: var(--sp-3); display: flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: var(--fs-11); color: var(--on-film-2); }
.mon-rec i { width: 6px; height: 6px; border-radius: var(--r-full); background: currentColor; }
.mon-tile:where(.is-live) .mon-rec { color: var(--on-film); }
.mon-cam, .mon-body { position: relative; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-cam { font-size: var(--fs-13); font-weight: var(--fw-semi); }
.mon-body { font-size: var(--fs-11); color: var(--on-film-2); }
.mon-sec-title { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-13); font-weight: var(--fw-semi); color: var(--text-2); }
.mon-log { margin-top: var(--sp-3); }
.mon-log-head { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-12); color: var(--text-3); }
.mon-entry { margin-top: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); }
.mon-entry-head { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.mon-time { font-family: var(--font-mono); color: var(--text-2); }
.mon-text { margin-top: var(--sp-1); font-size: var(--fs-14); line-height: 1.6; color: var(--text); }
.mon-shot { display: block; width: 100%; margin-top: var(--sp-2); border-radius: var(--r-sm); }
.mon-wait { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.mon-draw { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); margin-top: var(--sp-2); }
.mon-err { font-size: var(--fs-12); color: var(--danger); }

/* ---- 游戏：测试问卷（apps/play，ARCHITECTURE 4.519）----
   问卷页的外框 .quiz 上挂版式（qz-t-*）与字体（qz-f-*）；用户挑的颜色以 --ph-quiz-* 传进来，压在版式自带的颜色上。
   挂了契约钩子的元素上，版式与状态一律包进 :where()，单个 .ph-quiz-* 写的美化压得住（第 18 条） */
.qz-group { padding-top: var(--sp-2); }
.qz-group-title { padding: var(--sp-3) var(--sp-4) 0; font-size: var(--fs-13); color: var(--text-3); }
.qz-grid { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); }
/* 首页的卡片一律跟随应用主题（4.520），问卷自己的版式只在打开之后用 */
.qz-tile {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; text-align: left;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.qz-tile > svg { flex: none; color: var(--text-3); }
.qz-tile-icon {
  flex: none; width: 38px; height: 38px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text-2);
}
.qz-tile-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.qz-tile-title { font-size: var(--fs-15); font-weight: var(--fw-semi); line-height: 1.35; }
.qz-tile-desc {
  font-size: var(--fs-13); color: var(--text-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.qz-tile-meta { font-size: var(--fs-11); color: var(--text-3); }

/* 外框：颜色先取版式自带的（--qz-d-*），用户挑了的压上去。theme 版式全部取应用本身的令牌 */
.quiz {
  --qz-d-paper: var(--bg); --qz-d-ink: var(--text); --qz-d-accent: var(--accent);
  --qz-d-chip: var(--surface); --qz-d-line: var(--border); --qz-r: var(--r-lg); --qz-d-track: var(--surface-3);
  --qz-paper: var(--ph-quiz-paper, var(--qz-d-paper)); --qz-ink: var(--ph-quiz-ink, var(--qz-d-ink));
  --qz-accent: var(--ph-quiz-accent, var(--qz-d-accent));
  min-height: 100%; padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3);
  background: var(--qz-paper); color: var(--qz-ink);
}
.quiz-cover {
  position: relative; overflow: hidden; padding: var(--sp-5) var(--sp-4); border-radius: var(--qz-r);
  background: var(--qz-d-chip); border: 1px solid var(--qz-d-line);
}
.quiz-cover:where(.is-small) { padding: var(--sp-3) var(--sp-4); }
:where(.quiz.has-cover) .quiz-cover { background: var(--ph-quiz-cover) center / cover no-repeat; min-height: 180px; display: flex; flex-direction: column; justify-content: flex-end; }
:where(.quiz.has-cover) .quiz-cover::before { content: ""; position: absolute; inset: 0; background: linear-gradient(transparent 20%, color-mix(in srgb, var(--qz-paper) 92%, transparent)); }
.quiz-cover > * { position: relative; }
.quiz-kind { font-size: var(--fs-12); color: var(--text-3); margin-bottom: var(--sp-1); }
.quiz-title { font-size: var(--fs-24); font-weight: var(--fw-bold); line-height: 1.3; }
:where(.quiz-cover.is-small) .quiz-title { font-size: var(--fs-17); }
.quiz-desc { margin-top: var(--sp-2); font-size: var(--fs-14); line-height: 1.75; color: var(--text-2); white-space: pre-wrap; }
.quiz-actions { display: flex; flex-direction: column; gap: var(--sp-2); }
.quiz-note { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; text-align: center; }
.quiz-progress { height: 4px; border-radius: var(--r-full); background: var(--qz-d-track); overflow: hidden; }
.quiz-progress > i, .qz-bar > i { display: block; height: 100%; width: var(--qz-progress, 0%); background: var(--qz-accent); border-radius: inherit; transition: width .25s; }
.quiz-step { font-size: var(--fs-12); color: var(--text-3); margin-top: calc(-1 * var(--sp-1)); }
.quiz-question { font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1.5; padding: var(--sp-3) 0 var(--sp-2); }
.quiz-options { display: flex; flex-direction: column; gap: var(--sp-2); }
.quiz-option {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; text-align: left;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--qz-r); font-size: var(--fs-15); line-height: 1.5;
  background: var(--qz-d-chip); color: var(--qz-ink); border: 1px solid var(--qz-d-line);
}
.quiz-option:where(.is-on) { border-color: var(--qz-accent); box-shadow: inset 0 0 0 1px var(--qz-accent); }
.quiz-letter {
  flex: none; width: 26px; height: 26px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); background: var(--surface-2);
}
:where(.quiz-option.is-on) .quiz-letter { background: var(--qz-accent); color: var(--on-accent); }
.quiz-option-text { flex: 1; min-width: 0; }
.quiz-nav { display: flex; justify-content: space-between; align-items: center; margin-top: auto; padding-top: var(--sp-4); }

/* 量表题：一排圆点，越往右越符合 */
.qz-likert { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4) var(--sp-3); border-radius: var(--qz-r); background: var(--qz-d-chip); border: 1px solid var(--qz-d-line); }
.qz-likert-row { display: flex; justify-content: space-between; align-items: center; }
.qz-dot {
  width: 44px; height: 44px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--border-2); background: var(--qz-d-chip);
}
.qz-dot > i { width: 14px; height: 14px; border-radius: var(--r-full); background: transparent; transition: background .15s; }
.qz-dot:where(.is-on) { border-color: var(--qz-accent); }
:where(.qz-dot.is-on) > i { background: var(--qz-accent); }
.qz-likert-ends { display: flex; justify-content: space-between; font-size: var(--fs-12); color: var(--text-3); }
.qz-likert-now { text-align: center; font-size: var(--fs-14); font-weight: var(--fw-medium); min-height: 1.5em; }

/* 结果页：一节一张卡片 */
.qz-sec {
  padding: var(--sp-4); border-radius: var(--qz-r); background: var(--qz-d-chip); border: 1px solid var(--qz-d-line);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.qz-row { flex-direction: row; align-items: center; justify-content: space-between; font-size: var(--fs-14); }
.qz-sec-label { font-size: var(--fs-12); color: var(--text-3); }
.qz-big { font-size: var(--fs-24); font-weight: var(--fw-bold); line-height: 1.3; }
.qz-sub { font-size: var(--fs-17); font-weight: var(--fw-semi); }
.qz-when { font-size: var(--fs-12); color: var(--text-3); margin-top: calc(-1 * var(--sp-1)); }
.qz-para { margin: 0; font-size: var(--fs-14); line-height: 1.75; }
.qz-para:where(.is-muted) { color: var(--text-2); font-size: var(--fs-13); }
.qz-para:where(.is-error) { color: var(--danger); font-size: var(--fs-13); }
.qz-rich { display: flex; flex-direction: column; gap: var(--sp-3); }
.qz-rich-sec { display: flex; flex-direction: column; gap: var(--sp-1); }
.qz-h { font-size: var(--fs-15); font-weight: var(--fw-semi); margin-top: var(--sp-1); }
.qz-ul { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-14); line-height: 1.7; }
.qz-bar { height: 6px; border-radius: var(--r-full); background: var(--qz-d-track); overflow: hidden; flex: 1; }
.qz-bar:where(.is-other) > i { opacity: .4; }
.qz-dim { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3) 0; border-top: 1px solid var(--qz-d-line); }
.qz-dim-head { display: flex; align-items: center; gap: var(--sp-2); width: 100%; text-align: left; color: inherit; }
.qz-dim-head > svg { flex: none; color: var(--text-3); }
.qz-dim-name { font-size: var(--fs-15); font-weight: var(--fw-semi); }
.qz-dim-band { flex: 1; min-width: 0; font-size: var(--fs-13); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qz-dim-pct { font-size: var(--fs-15); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.qz-dim-pair { display: grid; grid-template-columns: auto 1fr 2.2em; align-items: center; column-gap: var(--sp-2); row-gap: var(--sp-1); font-size: var(--fs-12); color: var(--text-2); }
.qz-dim-pair > b { font-weight: var(--fw-semi); text-align: right; color: var(--text); font-variant-numeric: tabular-nums; }
.qz-dim-more { display: flex; flex-direction: column; gap: var(--sp-3); padding-top: var(--sp-1); }
.qz-ev { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); }
.qz-ev-row { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-13); line-height: 1.6; }
.qz-ev-row > span { color: var(--text-2); }
.qz-ev-row > b { font-weight: var(--fw-semi); }
.qz-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.qz-chip { padding: 4px 10px; border-radius: var(--r-full); background: var(--surface-2); font-size: var(--fs-13); color: var(--text-2); }
.qz-basis { display: flex; gap: var(--sp-2); align-items: flex-start; padding: 0 var(--sp-1); font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); }
.qz-basis > svg { flex: none; margin-top: 2px; }
.qz-wait { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-14); color: var(--text-2); }
.qz-react { font-size: var(--fs-15); line-height: 1.75; white-space: pre-wrap; padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); }
.quiz-result, .quiz-compare { min-width: 0; }
.quiz-toggle { align-self: flex-start; font-size: var(--fs-13); color: var(--text-2); padding: var(--sp-2) 0; }
.quiz-picks { display: flex; flex-direction: column; gap: var(--sp-2); }
.quiz-pick { padding: var(--sp-3); border-radius: var(--r-md); background: var(--qz-d-chip); border: 1px solid var(--qz-d-line); }
.quiz-pick:where(.is-same) { box-shadow: inset 3px 0 0 var(--qz-accent); }
.quiz-pick-q { font-size: var(--fs-14); font-weight: var(--fw-medium); line-height: 1.5; }
.quiz-pick-a { font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); }
.quiz-pick-a > b { font-weight: var(--fw-semi); margin-right: var(--sp-2); color: var(--text); }
.quiz-pick-a:where(.is-key) { color: var(--qz-accent); }
.quiz-pick-why { font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); margin-top: 2px; white-space: pre-wrap; }

/* 版式：信纸 */
.quiz:where(.qz-t-paper) {
  --qz-d-paper: var(--qz-paper-warm); --qz-d-ink: var(--qz-ink-warm); --qz-d-chip: transparent; --qz-d-line: var(--qz-line-warm);
  --qz-r: 0px; font-family: var(--font-serif);
}
:where(.quiz.qz-t-paper) .quiz-option { border-width: 0 0 1px; padding-left: 0; padding-right: 0; }
:where(.quiz.qz-t-paper) .quiz-letter { border-radius: 2px; }
:where(.quiz.qz-t-paper) .quiz-cover { border-bottom: 1px solid var(--qz-line-warm); background: none; padding-left: 0; padding-right: 0; }
/* 版式：杂志 */
.quiz:where(.qz-t-magazine) { --qz-r: var(--r-xs); }
:where(.quiz.qz-t-magazine) .quiz-cover { background: var(--qz-mag-ink); color: var(--qz-on-mag); padding: var(--sp-6) var(--sp-4); }
:where(.quiz.qz-t-magazine) .quiz-title { font-size: var(--fs-28); letter-spacing: -.01em; }
:where(.quiz.qz-t-magazine .quiz-cover) .quiz-kind { color: var(--qz-on-mag); opacity: .7; }
:where(.quiz.qz-t-magazine) .quiz-option { border-width: 1px 0 0; border-radius: 0; background: none; padding-left: 0; padding-right: 0; }
:where(.quiz.qz-t-magazine) .quiz-option:where(.is-on) { box-shadow: none; font-weight: var(--fw-semi); }
:where(.quiz.qz-t-magazine) .quiz-letter { border: none; font-size: var(--fs-17); font-weight: var(--fw-bold); }
/* 版式：像素 */
.quiz:where(.qz-t-pixel) { --qz-r: 2px; --qz-d-line: var(--border-2); font-family: var(--font-mono); }
:where(.quiz.qz-t-pixel) .quiz-option, :where(.quiz.qz-t-pixel) .qz-sec, :where(.quiz.qz-t-pixel) .quiz-cover {
  box-shadow: 2px 2px 0 var(--border-2);
}
:where(.quiz.qz-t-pixel) .quiz-letter { border-radius: 0; }
:where(.quiz.qz-t-pixel) .quiz-progress, :where(.quiz.qz-t-pixel) .qz-bar { border-radius: 0; }
/* 版式：柔和 */
.quiz:where(.qz-t-soft) { --qz-d-paper: var(--qz-soft-bg); --qz-d-chip: var(--qz-soft-chip); --qz-d-line: transparent; --qz-r: var(--r-xl); }
:where(.quiz.qz-t-soft) .quiz-option:where(.is-on) { background: var(--qz-accent); color: var(--on-accent); }
:where(.quiz.qz-t-soft) .quiz-option:where(.is-on) .quiz-letter { background: var(--on-accent); color: var(--qz-accent); }
/* 字体 */
.quiz:where(.qz-f-serif) { font-family: var(--font-serif); }
.quiz:where(.qz-f-hand) { font-family: var(--font-hand); }
.quiz:where(.qz-f-mono) { font-family: var(--font-mono); }

/* 编辑与上传 */
.qz-src { font-family: var(--font-mono); font-size: var(--fs-13); line-height: 1.6; }
.qz-help { white-space: pre-wrap; font-family: var(--font-mono); font-size: var(--fs-12); line-height: 1.6; color: var(--text-2);
  background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-3); margin: 0 0 var(--sp-2); }
.qz-tpl-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); padding-top: var(--sp-3); padding-bottom: var(--sp-3); }
.qz-tpl {
  --qz-paper: var(--qz-d-paper); --qz-ink: var(--qz-d-ink);
  --qz-d-paper: var(--surface-2); --qz-d-ink: var(--text);
  display: flex; flex-direction: column; gap: 2px; text-align: left; padding: var(--sp-3);
  border-radius: var(--r-md); border: 1px solid var(--border); background: var(--qz-paper); color: var(--qz-ink);
}
.qz-tpl:where(.qz-t-paper) { font-family: var(--font-serif); }
.qz-tpl:where(.qz-t-pixel) { font-family: var(--font-mono); border-radius: 2px; }
.qz-tpl:where(.qz-t-magazine) { --qz-d-paper: var(--qz-mag-ink); --qz-d-ink: var(--qz-on-mag); border-radius: 0; }
.qz-tpl:where(.is-on) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.qz-tpl-name { font-size: var(--fs-14); font-weight: var(--fw-semi); }
.qz-tpl-desc { font-size: var(--fs-11); opacity: .6; }
.qz-cover-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.qz-cover-thumb { width: 64px; height: 40px; border-radius: var(--r-xs); background: var(--img) center / cover no-repeat; }
.qz-preview { border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--border); }
:where(.qz-preview) .quiz { min-height: 0; }

/* 聊天里的问卷卡片（4.519）：结果卡与角色发来的问卷。版式跟着问卷走，颜色取 --ph-quiz-* */
.quiz-card {
  --qz-d-paper: var(--surface); --qz-d-ink: var(--text); --qz-d-accent: var(--accent); --qz-d-line: var(--border);
  --qz-paper: var(--ph-quiz-paper, var(--qz-d-paper)); --qz-ink: var(--ph-quiz-ink, var(--qz-d-ink));
  --qz-accent: var(--ph-quiz-accent, var(--qz-d-accent));
  display: flex; flex-direction: column; gap: var(--sp-1); width: 250px; max-width: 100%; padding: var(--sp-3);
  border-radius: var(--r-lg); background: var(--qz-paper); color: var(--qz-ink); border: 1px solid var(--qz-d-line);
}
.quiz-card:where(.qz-t-paper) { --qz-d-paper: var(--qz-paper-warm); --qz-d-ink: var(--qz-ink-warm); --qz-d-line: var(--qz-line-warm); border-radius: 0; font-family: var(--font-serif); }
.quiz-card:where(.qz-t-magazine) { --qz-d-paper: var(--qz-mag-ink); --qz-d-ink: var(--qz-on-mag); --qz-d-accent: var(--qz-on-mag); --qz-d-line: var(--qz-mag-ink); border-radius: 0; }
.quiz-card:where(.qz-t-pixel) { --qz-d-line: var(--border-2); border-radius: 2px; box-shadow: 2px 2px 0 var(--border-2); font-family: var(--font-mono); }
.quiz-card:where(.qz-t-soft) { --qz-d-paper: var(--qz-soft-bg); --qz-d-line: transparent; border-radius: var(--r-xl); }
.quiz-card-head { display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); opacity: .65; }
.quiz-card-title { font-size: var(--fs-16); font-weight: var(--fw-bold); line-height: 1.35; margin-bottom: var(--sp-1); }
.quiz-card-meta { font-size: var(--fs-12); opacity: .65; }
.quiz-card-row { display: flex; gap: var(--sp-2); font-size: var(--fs-13); line-height: 1.5; }
.quiz-card-row > span { flex: none; min-width: 3em; opacity: .65; }
.quiz-card-row > b { font-weight: var(--fw-semi); min-width: 0; overflow-wrap: anywhere; }
.quiz-card-row:where(.is-vs) > b { color: var(--qz-accent); }
.quiz-card-go { margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--qz-d-line); font-size: var(--fs-13); color: var(--qz-accent); }

/* ---- 游戏：桌游（apps/play/Games.js，ARCHITECTURE 4.547）----
   颜色一律取 --gm-* 令牌。牌桌上的元素不挂契约钩子 */
.gm-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); margin-top: var(--sp-2); }
.gm-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px; text-align: left;
  padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.gm-tile-icon {
  width: 38px; height: 38px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text-2); margin-bottom: var(--sp-1);
}
.gm-tile-name { font-size: var(--fs-15); font-weight: var(--fw-semi); }
.gm-tile-lead { font-size: var(--fs-12); color: var(--text-3); line-height: 1.5; }
.gm-resume {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%; margin-top: var(--sp-2); text-align: left;
  padding: var(--sp-3); border-radius: var(--r-md); background: var(--accent-weak); color: var(--text); font-size: var(--fs-13);
}
.gm-resume > span { flex: 1; }
.gm-rules { padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); }
.gm-rules > p { margin: 0; font-size: var(--fs-13); line-height: 1.7; color: var(--text-2); }
.gm-rules > p + p { margin-top: var(--sp-1); }
.gm-seat-no {
  width: 24px; height: 24px; border-radius: var(--r-full); border: 1.5px solid var(--border-2);
  display: flex; align-items: center; justify-content: center; font-size: var(--fs-12); color: var(--on-accent);
}
.gm-seat-no:where(.is-on) { background: var(--accent); border-color: var(--accent); }
.gm-start { padding: var(--sp-4) 0 var(--sp-8); }
.gm-empty { color: var(--text-3); text-align: center; }

.gm-table { display: flex; flex-direction: column; gap: var(--sp-3); width: 100%; box-sizing: border-box; padding: var(--sp-3) var(--sp-4) var(--sp-8); }

/* 桌面（4.598）：一块椭圆的绒面，座位按 --sx/--sy 围一圈，中间是牌堆与弃牌堆 */
.gm-felt {
  position: relative; width: 100%; aspect-ratio: 1 / .94; border-radius: 50% / 46%;
  background: repeating-radial-gradient(circle at 30% 20%, var(--gm-felt-weave) 0 1px, transparent 1px 3px),
    radial-gradient(ellipse at 50% 42%, var(--gm-felt-light), var(--gm-felt) 70%);
  box-shadow: inset 0 0 0 6px var(--gm-felt-edge), inset 0 0 0 7px var(--gm-felt-rim), inset 0 18px 40px rgba(0, 0, 0, .28), var(--shadow-2);
  color: var(--gm-on);
}
.gm-felt:where(.is-spy) { aspect-ratio: 1 / .78; }
.gm-seat-face:has(> .gm-mini) { margin-bottom: 12px; }
.gm-spy-round { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: var(--fs-13); opacity: .8; }
.gm-seat {
  position: absolute; left: var(--sx); top: var(--sy); transform: translate(-50%, -50%); z-index: 2;
  width: 84px; display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center;
}
.gm-seat-face { position: relative; }
.gm-seat-face > .avatar { box-shadow: 0 0 0 2px var(--gm-felt-rim); transition: box-shadow .2s; }
.gm-seat:where(.is-turn) .gm-seat-face > .avatar { box-shadow: 0 0 0 3px var(--gm-on), 0 0 14px var(--gm-on); }
.gm-seat:where(.is-out) { opacity: .4; }
.gm-seat:where(.is-me) { width: 110px; }
.gm-seat-name { font-size: var(--fs-12); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 2px rgba(0, 0, 0, .35); }
.gm-seat-extra { font-size: var(--fs-11); opacity: .8; line-height: 1.3; }
/* 角色手里的牌：几张小牌背扇着，右下角写张数 */
.gm-mini { position: absolute; left: 50%; bottom: -10px; transform: translateX(-50%); width: 40px; height: 22px; }
.gm-mini-card {
  position: absolute; left: 50%; bottom: 0; width: 13px; height: 19px; border-radius: 2.5px; background: var(--gm-wild); border: 1px solid var(--gm-on);
  transform: translateX(calc(-50% + (var(--i) - 2.5) * 5px)) rotate(calc((var(--i) - 2.5) * 7deg)); transform-origin: 50% 100%;
}
.gm-mini-n {
  position: absolute; right: -12px; bottom: -4px; min-width: 18px; height: 18px; padding: 0 4px; border-radius: var(--r-full);
  background: var(--gm-on); color: var(--gm-wild); font-size: var(--fs-11); font-weight: var(--fw-semi); line-height: 18px; text-align: center;
}
/* 台词：带尾巴的气泡，座位下方（「我」的在上方）；靠左的座位气泡向右展开、靠右的向左展开，相邻的不压在一起。
   弹出来停一会儿再淡掉，记录里还在 */
.gm-say {
  --bx: -50%;
  position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(var(--bx)); z-index: 3;
  width: 124px; padding: 6px 8px; border-radius: var(--r-md); background: var(--gm-bubble); color: var(--text);
  font-size: var(--fs-12); line-height: 1.45; text-align: left; box-shadow: var(--shadow-2); text-shadow: none;
  animation: gm-bubble 14s var(--ease) both;
}
.gm-say::before {
  content: ''; position: absolute; left: 50%; top: -5px; width: 10px; height: 10px; background: var(--gm-bubble);
  transform: translateX(-50%) rotate(45deg); border-radius: 2px;
}
.gm-say:where(.is-left) { --bx: calc(-100% + 22px); }
.gm-say:where(.is-left)::before { left: auto; right: 17px; }
.gm-say:where(.is-right) { --bx: -22px; }
.gm-say:where(.is-right)::before { left: 22px; }
.gm-say:where(.is-up) { top: auto; bottom: calc(100% + 8px); }
.gm-say:where(.is-up)::before { top: auto; bottom: -5px; }
.gm-say-text { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.gm-trans { margin-top: 2px; font-size: var(--fs-11); color: var(--text-3); line-height: 1.4; }
@keyframes gm-bubble {
  0% { opacity: 0; transform: translateX(var(--bx)) translateY(4px) scale(.9); }
  4%, 80% { opacity: 1; transform: translateX(var(--bx)); }
  100% { opacity: 0; transform: translateX(var(--bx)); pointer-events: none; }
}
.gm-hint { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: 20px; font-size: var(--fs-13); color: var(--text-2); text-align: center; }
.gm-err { font-size: var(--fs-12); color: var(--danger); text-align: center; }
.gm-acts { display: flex; justify-content: center; gap: var(--sp-2); flex-wrap: wrap; }
.gm-chip {
  padding: 6px var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border-2); background: var(--surface);
  font-size: var(--fs-13); color: var(--text);
}
.gm-chip:disabled { opacity: .5; }
/* 对同桌说一句 */
.gm-say-bar { display: flex; align-items: center; gap: var(--sp-2); }
.gm-say-input {
  flex: 1; min-width: 0; height: 38px; padding: 0 var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border-2);
  background: var(--surface); color: var(--text); font-size: var(--fs-14); font-family: inherit; outline: none;
}
.gm-say-input:focus { border-color: var(--accent); }
.gm-say-send { width: 38px; height: 38px; border-radius: var(--r-full); display: flex; align-items: center; justify-content: center; background: var(--accent); color: var(--on-accent); }
.gm-say-send:disabled { opacity: .4; }

.gm-log { border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--border); padding: var(--sp-2) var(--sp-3); }
.gm-log-head { display: flex; align-items: center; justify-content: space-between; width: 100%; font-size: var(--fs-12); color: var(--text-3); padding-bottom: 4px; }
.gm-log-row { display: flex; flex-direction: column; gap: 0; font-size: var(--fs-12); line-height: 1.6; color: var(--text-2); }
.gm-log-row > div { display: flex; align-items: center; gap: 6px; }
.gm-log-row b { font-weight: var(--fw-semi); color: var(--text); margin-right: 4px; }
.gm-log-row:where(.is-say) { color: var(--text); }
.gm-log-row:where(.is-sys) { color: var(--text-3); }
.gm-log-row:where(.is-err) { color: var(--danger); }

.gm-result { padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); text-align: center; }
.gm-result:where(.is-win) { border-color: var(--accent); }
.gm-result-head { font-size: var(--fs-20); font-weight: var(--fw-bold); }
.gm-result-line { margin-top: var(--sp-1); font-size: var(--fs-13); line-height: 1.6; color: var(--text-2); }
.gm-result-acts { display: flex; justify-content: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.gm-result-sub { margin-top: var(--sp-3); font-size: var(--fs-12); color: var(--text-3); }
.gm-result-chats { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); margin-top: var(--sp-2); }

/* UNO（4.913，用户选了效果图第二版）：只用黑白灰。四色换成四种花色，各有一种底纹与一个记号：
   圆点（red）、斜纹（yellow）、格纹（green）、素面（blue）。牌面是纸，中间一枚白色圆章写数字，左上右下各一个角标（数字加花色记号），
   像扑克牌。万能牌与牌背是黑底。花色记号是画出来的形状（.gm-suit），不用字形 */
.gm-card {
  position: relative; flex: none; width: 58px; height: 86px; border-radius: 7px; padding: 0; overflow: hidden;
  background: linear-gradient(170deg, var(--gm-paper), var(--gm-paper-2)); color: var(--gm-ink); border: 0;
  box-shadow: 0 1px 0 var(--gm-edge), 0 5px 12px rgba(0, 0, 0, .28), inset 0 0 0 1px var(--gm-edge);
  display: flex; align-items: center; justify-content: center; transition: transform .25s var(--ease), filter .2s, opacity .2s;
}
.gm-card:disabled { opacity: 1; }
.gm-field { position: absolute; inset: 5px; border-radius: 4px; border: 1px solid var(--gm-edge); background: var(--gm-pattern, none); }
.gm-card:where(.gm-c-red)    { --gm-pattern: radial-gradient(circle, var(--gm-pat) 1.1px, transparent 1.3px) 0 0 / 6px 6px; }
.gm-card:where(.gm-c-yellow) { --gm-pattern: repeating-linear-gradient(45deg, var(--gm-pat) 0 1px, transparent 1px 5px); }
.gm-card:where(.gm-c-green)  { --gm-pattern: repeating-linear-gradient(0deg, var(--gm-pat) 0 1px, transparent 1px 6px), repeating-linear-gradient(90deg, var(--gm-pat) 0 1px, transparent 1px 6px); }
.gm-card:where(.gm-c-blue)   { --gm-pattern: linear-gradient(var(--gm-solid), var(--gm-solid)); }
.gm-card-face {
  position: relative; width: 64%; aspect-ratio: 1; border-radius: 50%; background: var(--gm-paper);
  box-shadow: 0 0 0 1px var(--gm-edge), 0 2px 5px rgba(0, 0, 0, .14);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1;
}
.gm-ix {
  position: absolute; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-family: var(--font-serif); font-size: var(--fs-11); font-weight: var(--fw-semi); line-height: 1;
}
.gm-ix:where(.is-tl) { left: 5px; top: 5px; }
/* 6 与 9 倒过来分不清：和真牌一样在下面划一道 */
.gm-ix:where(.is-69), .gm-card-face:where(.is-69) { text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 2px; }
.gm-ix:where(.is-br) { right: 5px; bottom: 5px; transform: rotate(180deg); }
/* 花色记号：圆、三角、方、菱，一律用 currentColor 画 */
.gm-suit { display: block; width: 7px; height: 7px; background: currentColor; }
.gm-suit:where(.gm-s-red) { border-radius: 50%; }
.gm-suit:where(.gm-s-yellow) { clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.gm-suit:where(.gm-s-green) { border-radius: 1px; }
.gm-suit:where(.gm-s-blue) { transform: rotate(45deg) scale(.82); border-radius: 1px; }
.gm-suit:where(.gm-s-wild) { clip-path: polygon(50% 0, 61% 35%, 100% 38%, 69% 60%, 80% 100%, 50% 76%, 20% 100%, 31% 60%, 0 38%, 39% 35%); }
/* 万能牌与牌背：黑底，字与线用 --gm-on */
.gm-card:where(.gm-c-wild), .gm-back { background: linear-gradient(170deg, var(--gm-wild), var(--gm-wild-2)); color: var(--gm-on); box-shadow: 0 1px 0 var(--gm-edge), 0 5px 12px rgba(0, 0, 0, .32), inset 0 0 0 1px var(--gm-on-edge); }
.gm-card:where(.gm-c-wild) .gm-field { border-color: var(--gm-on-edge);
  background: conic-gradient(from 45deg, var(--gm-on-pat) 0 25%, transparent 0 50%, var(--gm-on-pat) 0 75%, transparent 0); }
.gm-card:where(.gm-c-wild) .gm-card-face { background: var(--gm-wild-2); color: var(--gm-on); box-shadow: 0 0 0 1px var(--gm-on-edge); }
.gm-back .gm-field { border-color: var(--gm-on-edge); background: repeating-linear-gradient(45deg, var(--gm-on-pat) 0 2px, transparent 2px 6px); }
.gm-back::after {
  content: "UNO"; position: relative; z-index: 1; width: 56%; aspect-ratio: 1; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--gm-on-edge);
  display: flex; align-items: center; justify-content: center; background: var(--gm-wild-2);
  font-family: var(--font-serif); font-size: var(--fs-11); letter-spacing: .08em;
}
/* 万能牌中间那一枚：四格灰度的扇面，四种花色合在一起 */
.gm-wheel {
  display: block; width: 24px; height: 24px; border-radius: 50%; box-shadow: 0 0 0 1px var(--gm-on-edge);
  background: conic-gradient(var(--gm-paper) 0 25%, var(--gm-solid) 0 50%, var(--gm-felt-rim) 0 75%, var(--gm-wild) 0);
}
/* 桌面中间：牌堆（两张叠着，右下角张数）与弃牌堆（最上面一张压着两张歪的） */
.gm-center { position: absolute; left: 50%; top: 60%; transform: translate(-50%, -50%); z-index: 1; display: flex; align-items: center; gap: var(--sp-4); }
.gm-pile { position: relative; width: 58px; height: 86px; }
.gm-pile > .gm-card { position: absolute; left: 0; top: 0; }
.gm-pile > .gm-card:where(.is-under) { transform: translate(3px, -3px); }
.gm-pile-n {
  position: absolute; right: -8px; bottom: -8px; z-index: 2; min-width: 22px; padding: 0 5px; border-radius: var(--r-full);
  background: var(--gm-on); color: var(--gm-wild); font-size: var(--fs-11); font-weight: var(--fw-semi); line-height: 20px; text-align: center;
}
.gm-discard { position: relative; width: 58px; height: 86px; }
.gm-discard > .gm-card { position: absolute; left: 0; top: 0; transform: rotate(var(--tilt, 0deg)); }
.gm-discard > .gm-card:where(.is-under) { filter: brightness(.82); }
.gm-discard > .gm-card:where(.is-top) { z-index: 2; }
/* 出牌：从那个座位飞到弃牌堆上；摸牌：一张牌背从牌堆飞到那个座位 */
.gm-discard > .gm-card:where(.is-flown) { animation: gm-fly-in .4s var(--ease-out) both; }
@keyframes gm-fly-in {
  from { transform: translate(var(--fx, 0px), var(--fy, 0px)) rotate(calc(var(--tilt, 0deg) - 30deg)) scale(.6); opacity: .6; }
  to { transform: rotate(var(--tilt, 0deg)); opacity: 1; }
}
.gm-flight { position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none; animation: gm-fly-out .45s var(--ease) both; }
@keyframes gm-fly-out {
  from { transform: none; opacity: 1; }
  to { transform: translate(var(--tx, 0px), var(--ty, 0px)) scale(.3); opacity: 0; }
}
/* 当前花色与方向：一枚白色圆章里画着当前花色的记号 */
.gm-uno-state { position: absolute; left: 50%; top: 60%; transform: translate(88px, -50%); display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.gm-dot { width: 22px; height: 22px; border-radius: 50%; background: var(--gm-paper); color: var(--gm-ink); box-shadow: 0 0 0 1px var(--gm-edge), 0 2px 6px rgba(0, 0, 0, .25);
  display: flex; align-items: center; justify-content: center; }
.gm-dot > .gm-suit { width: 9px; height: 9px; }
.gm-dir { display: flex; opacity: .85; transition: transform .3s; }
.gm-dir:where(.is-ccw) { transform: scaleX(-1); }
/* 手牌扇开：每张按 --off/--rot/--lift 摆，能出的抬高，不能出的压暗 */
.gm-hand { position: relative; height: 128px; margin: 0 calc(-1 * var(--sp-2)); }
.gm-hand > .gm-card { position: absolute; left: 50%; bottom: 6px; z-index: var(--z, 0); transform-origin: 50% 120%; transform: translateX(calc(-50% + var(--off, 0px))) translateY(var(--lift, 0px)) rotate(var(--rot, 0deg)); }
.gm-hand > .gm-card:where(.is-on) { transform: translateX(calc(-50% + var(--off, 0px))) translateY(calc(var(--lift, 0px) - 16px)) rotate(var(--rot, 0deg)); box-shadow: 0 1px 0 var(--gm-edge), 0 10px 22px rgba(0, 0, 0, .3), inset 0 0 0 1px var(--gm-edge); }
:where(.gm-hand) .gm-card:not(.is-on) { filter: brightness(.86) contrast(.92); }
/* 彩色那一套（4.914，用户：「可不可以两套牌呀。彩色的可以优化牌面质感吗。我怕有人玩不习惯」，第 4 条的例外）：
   效果图第一版。白纸边框里一块带光泽的色块，中间斜放的椭圆写数字（字是这张牌的颜色），角标是纸色；
   万能牌是黑色色块；牌背黑底斜纹，红色椭圆框里写 UNO；桌面是墨绿绒面，内侧一圈缝线。花色记号不画 */
.gm-deck-color .gm-card { background: var(--gm-paper); color: var(--gm-paper);
  box-shadow: 0 1px 0 var(--gm-edge), 0 5px 12px rgba(0, 0, 0, .26), inset 0 0 0 1px var(--gm-edge); }
.gm-deck-color .gm-card:where(.gm-c-red) { --gm-c: var(--gm-red); }
.gm-deck-color .gm-card:where(.gm-c-yellow) { --gm-c: var(--gm-yellow); }
.gm-deck-color .gm-card:where(.gm-c-green) { --gm-c: var(--gm-green); }
.gm-deck-color .gm-card:where(.gm-c-blue) { --gm-c: var(--gm-blue); }
.gm-deck-color .gm-card:where(.gm-c-wild) { --gm-c: var(--gm-wild); }
.gm-deck-color .gm-field { inset: 4px; border-radius: 5px; border: 0; background: linear-gradient(160deg, var(--gm-gloss), var(--gm-shade)), var(--gm-c, var(--gm-wild));
  box-shadow: inset 0 0 0 1px var(--gm-shade); }
.gm-deck-color .gm-card-face { width: 94%; height: 50%; aspect-ratio: auto; transform: rotate(-30deg); color: var(--gm-c, var(--gm-wild));
  background: var(--gm-paper); box-shadow: inset 0 2px 5px var(--gm-shade); }
.gm-deck-color .gm-face-in { display: flex; transform: rotate(30deg); }
.gm-deck-color .gm-suit { display: none; }
.gm-deck-color .gm-ix { color: var(--gm-paper); }
.gm-deck-color .gm-card:where(.gm-c-wild) .gm-card-face { background: var(--gm-paper); color: var(--gm-wild); }
.gm-deck-color .gm-wheel { background: conic-gradient(var(--gm-red) 0 25%, var(--gm-yellow) 0 50%, var(--gm-green) 0 75%, var(--gm-blue) 0); }
.gm-deck-color .gm-back .gm-field { background: repeating-linear-gradient(45deg, var(--gm-wild) 0 3px, var(--gm-wild-2) 3px 6px); }
.gm-deck-color .gm-back::after { width: 64%; height: 46%; aspect-ratio: auto; background: none; box-shadow: 0 0 0 2px var(--gm-red); transform: rotate(-28deg); color: var(--gm-paper); }
.gm-felt.gm-deck-color {
  background: radial-gradient(ellipse at 50% 42%, var(--gm-hfelt-light), var(--gm-hfelt) 70%);
  box-shadow: inset 0 0 0 6px var(--gm-hfelt-edge), inset 0 18px 40px rgba(0, 0, 0, .25), var(--shadow-2);
}
.gm-felt.gm-deck-color::after { content: ""; position: absolute; inset: 12px; border-radius: 50% / 46%; border: 1px dashed var(--gm-stitch); pointer-events: none; }
.gm-deck-color .gm-dot { background: var(--gm-c, var(--gm-wild)); box-shadow: 0 0 0 2px var(--gm-paper), 0 2px 6px rgba(0, 0, 0, .25); }
.gm-deck-color .gm-dot:where(.gm-c-red) { --gm-c: var(--gm-red); }
.gm-deck-color .gm-dot:where(.gm-c-yellow) { --gm-c: var(--gm-yellow); }
.gm-deck-color .gm-dot:where(.gm-c-green) { --gm-c: var(--gm-green); }
.gm-deck-color .gm-dot:where(.gm-c-blue) { --gm-c: var(--gm-blue); }
.gm-hand:where(.gm-deck-color) .gm-card:not(.is-on) { filter: saturate(.6) brightness(.9); }
.gm-uno-btn { padding: 6px var(--sp-4); border-radius: var(--r-full); border: 1.5px solid var(--text); color: var(--text); font-size: var(--fs-13); font-weight: var(--fw-semi); background: var(--surface); }
.gm-uno-btn:where(.is-on) { background: var(--text); color: var(--bg); }

/* 大富翁（4.599）：7 乘 7 的格子，外圈是地，中间是骰子与按钮；棋子按 --px/--py 摆在格子中心，走动时滑过去 */
.gm-num { width: 90px; height: 34px; padding: 0 var(--sp-2); border-radius: var(--r-sm); border: 1px solid var(--border-2); background: var(--surface); color: var(--text); font-size: var(--fs-14); font-family: inherit; }
.mb-board {
  position: relative; display: grid; grid-template-columns: repeat(7, 1fr); grid-template-rows: repeat(7, 1fr); gap: 2px;
  width: 100%; aspect-ratio: 1; padding: 2px; box-sizing: border-box; border-radius: var(--r-md); background: var(--gm-board-line);
}
.mb-cell {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 0; min-width: 0;
  border-radius: 3px; background: var(--gm-board); color: var(--text); font-size: var(--fs-10); line-height: 1.1; overflow: hidden;
}
.mb-cell:where(.is-go, .is-jail, .is-park, .is-gotojail) { background: var(--surface-2); font-weight: var(--fw-semi); }
.mb-cell:where(.is-chance, .is-fate, .is-tax) { color: var(--text-2); }
.mb-cell:where(.is-sel) { box-shadow: inset 0 0 0 2px var(--accent); }
.mb-cell:where(.is-mort) .mb-name { text-decoration: line-through; opacity: .6; }
.mb-stripe { position: absolute; left: 0; right: 0; top: 0; height: 6px; background: var(--mb-g); }
.mb-cell:where(.is-g1) { --mb-g: var(--gm-g1); } .mb-cell:where(.is-g2) { --mb-g: var(--gm-g2); } .mb-cell:where(.is-g3) { --mb-g: var(--gm-g3); }
.mb-cell:where(.is-g4) { --mb-g: var(--gm-g4); } .mb-cell:where(.is-g5) { --mb-g: var(--gm-g5); } .mb-cell:where(.is-g6) { --mb-g: var(--gm-g6); }
.mb-cell:where(.is-g7) { --mb-g: var(--gm-g7); }
.mb-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 4px; }
.mb-price { font-size: 9px; color: var(--text-3); }
.mb-owner { position: absolute; right: 2px; bottom: 2px; width: 7px; height: 7px; border-radius: 50%; background: var(--owner); }
.mb-houses { position: absolute; left: 3px; bottom: 3px; display: flex; gap: 1px; }
.mb-houses > i { display: block; width: 5px; height: 5px; border-radius: 1px; background: var(--owner, var(--text-3)); }
.mb-houses > i:where(.is-hotel) { width: 12px; }
.mb-center { grid-area: 2 / 2 / 7 / 7; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2); padding: var(--sp-2); border-radius: 4px; background: var(--gm-board); text-align: center; }
.mb-dice { display: flex; gap: var(--sp-2); }
.mb-die {
  display: grid; grid-template-columns: repeat(3, 1fr); width: 34px; height: 34px; padding: 4px; box-sizing: border-box; border-radius: 7px;
  background: var(--surface); border: 1px solid var(--border-2); box-shadow: var(--shadow-1);
}
.mb-die > i { display: block; width: 6px; height: 6px; margin: auto; border-radius: 50%; background: transparent; }
.mb-die > i:where(.is-on) { background: var(--text); }
.mb-die:where(.is-rolling) { animation: mb-roll .45s var(--ease-out); }
@keyframes mb-roll { 0% { transform: rotate(-200deg) scale(.6); opacity: .4; } 70% { transform: rotate(10deg) scale(1.08); } 100% { transform: none; } }
.mb-round { font-size: var(--fs-11); color: var(--text-3); }
.mb-hint { font-size: var(--fs-12); color: var(--text-2); line-height: 1.4; }
.mb-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-1); }
.mb-piece {
  position: absolute; left: var(--px); top: var(--py); z-index: 2; pointer-events: none;
  transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + 8px)); transition: left .45s var(--ease), top .45s var(--ease), transform .25s;
}
.mb-piece > .avatar { box-shadow: 0 0 0 2px var(--pc), var(--shadow-1); }
.mb-piece:where(.is-turn) { transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + 8px)) scale(1.2); z-index: 3; }
.mb-sel { font-size: var(--fs-12); color: var(--text-2); text-align: center; line-height: 1.5; }
.mb-players { display: flex; flex-direction: column; gap: var(--sp-1); }
.mb-player { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2); border-radius: var(--r-md); background: var(--surface); border: 1.5px solid transparent; }
.mb-player > .avatar { box-shadow: 0 0 0 2px var(--pc); }
.mb-player:where(.is-turn) { border-color: var(--accent); }
.mb-player:where(.is-out) { opacity: .5; }
.mb-player-body { flex: 1; min-width: 0; }
.mb-player-name { font-size: var(--fs-13); font-weight: var(--fw-semi); }
.mb-player-sub { font-size: var(--fs-11); color: var(--text-3); }
.mb-player-say { margin-top: 2px; padding: 4px 6px; border-radius: var(--r-sm); background: var(--surface-2); font-size: var(--fs-12); line-height: 1.4; animation: gm-pop .25s ease-out; }
@keyframes gm-pop { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ---- 卡包（apps/wallet，ARCHITECTURE 4.611）----
   封面轮播（coverflow，4.612）：一排卡横着放，停在一张上；中间那张正对着，两边的绕竖轴往后转、往后退、缩小、变暗。
   转多少由 Stack.js 每一帧按离中线多远写进 --ry、--tz、--sc、--op、--zi，这里只把它们变成 transform。
   卡高是卡宽除以银行卡长宽比 */
.wl-page { padding: 0 var(--sp-4) var(--sp-8); }
.wl-sec { margin-top: var(--sp-8); }
.wl-sec-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--sp-2); font-size: var(--fs-17); font-weight: var(--fw-semi); color: var(--text); }
.wl-sec-n { font-weight: var(--fw-regular); color: var(--text-3); }
.wl-empty { padding: var(--sp-4); border-radius: var(--r-lg); border: 1px dashed var(--border-2); font-size: var(--fs-13); color: var(--text-3); text-align: center; line-height: 1.6; }
.wl-flow {
  --cw: 86%;
  display: flex; gap: 0; overflow-x: auto; overflow-y: visible; scroll-snap-type: x mandatory; scrollbar-width: none;
  margin: 0 calc(-1 * var(--sp-4)); padding: var(--sp-4) calc((100% - var(--cw)) / 2 + var(--sp-4)) var(--sp-5);
  perspective: 900px; perspective-origin: 50% 50%; -webkit-overflow-scrolling: touch;
}
.wl-flow::-webkit-scrollbar { display: none; }
.wl-slot {
  flex: none; width: 100%; aspect-ratio: 1.586; padding: 0; margin: 0 -10%; border-radius: 20px; scroll-snap-align: center;
  position: relative; z-index: var(--zi, 1); opacity: var(--op, 1); transform-style: preserve-3d;
  transform: translateZ(var(--tz, 0px)) rotateY(var(--ry, 0deg)) scale(var(--sc, 1));
  transition: transform .12s linear, opacity .12s linear, box-shadow .2s;
}
.wl-flow:where(.is-one) .wl-slot { margin: 0; }
.wl-slot:where(:first-child) { margin-left: 0; }
.wl-slot:where(:last-child) { margin-right: 0; }
.wl-slot:where(.is-on) > .wl-card { border-color: var(--border-2); box-shadow: var(--wl-shadow-on); }
.wl-dots { display: flex; justify-content: center; gap: 6px; margin-top: calc(-1 * var(--sp-2)); }
.wl-dots > i { width: 6px; height: 6px; border-radius: 50%; background: var(--border-2); transition: width .2s, background .2s; }
.wl-dots > i:where(.is-on) { width: 16px; border-radius: 3px; background: var(--text-2); }
.wl-detail { margin-top: var(--sp-4); animation: wl-in .32s var(--ease-out) both; }
/* 会一直变长的列表（流水、使用记录）放进限高的滑动区域（4.642，CLAUDE.md 第 26 条）：
   从前直接排在卡下面，条目一多整页无限往下长，下面那几组卡要翻很久才看得到。组名吸在顶上 */
.wl-scroll { max-height: 360px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
:where(.wl-scroll) .list-title { position: sticky; top: 0; z-index: 1; background: var(--bg); }
@keyframes wl-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* 卡面（4.613 改成和整体一样的样子）：白底、细边框、深色字、留白；颜色只是一层很淡的底色（--wl-tint）和名字前一个小色点。
   娱乐卡中间一道虚线、两侧各一个缺口，像一张票券；缺口用所在那一层的底色（--wl-notch）挖出来 */
.wl-card {
  --wl-c: var(--wl-rose); --wl-notch: var(--bg);
  position: relative; box-sizing: border-box; width: 100%; height: 100%; overflow: hidden;
  display: flex; flex-direction: column; padding: 22px 24px; border-radius: 20px; text-align: left;
  background: color-mix(in srgb, var(--wl-c) var(--wl-tint), var(--surface)); color: var(--text);
  border: 1px solid var(--border); box-shadow: var(--wl-shadow);
}
.wl-card:where(.wl-c-rose) { --wl-c: var(--wl-rose); } .wl-card:where(.wl-c-pink) { --wl-c: var(--wl-pink); }
.wl-card:where(.wl-c-peach) { --wl-c: var(--wl-peach); } .wl-card:where(.wl-c-sand) { --wl-c: var(--wl-sand); }
.wl-card:where(.wl-c-mint) { --wl-c: var(--wl-mint); } .wl-card:where(.wl-c-sky) { --wl-c: var(--wl-sky); }
.wl-card:where(.wl-c-lilac) { --wl-c: var(--wl-lilac); } .wl-card:where(.wl-c-ink) { --wl-c: var(--wl-ink); }
.wl-card:where(.wl-t-debit) { --wl-c: var(--wl-debit); } .wl-card:where(.wl-t-joint) { --wl-c: var(--wl-joint); }
.wl-card:where(.wl-t-kin) { --wl-c: var(--wl-kin); }
.wl-card > *, .wl-card-text > * { flex: none; }
.wl-eyebrow { font-size: var(--fs-11); letter-spacing: .16em; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wl-dot { display: inline-block; flex: none; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--wl-c); vertical-align: 2px; }
.wl-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); color: var(--text-3); }
.wl-card-name { margin-top: 10px; font-size: var(--fs-20); font-weight: var(--fw-semi); letter-spacing: .02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-card-desc { margin-top: 8px; font-size: var(--fs-14); line-height: 1.55; color: var(--text-2); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.wl-card-meta { margin-top: auto; display: flex; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-13); color: var(--text-3); }
/* 账户名再长也换行收在左边，右边「余额」那几个字不被压住（4.c158-10） */
.wl-card-meta > span:first-child { min-width: 0; }
.wl-card-meta > span:last-child { flex: none; }
.wl-bank-amount { margin-top: auto; margin-bottom: 12px; font-size: var(--fs-28); font-weight: var(--fw-semi); letter-spacing: .01em; font-variant-numeric: tabular-nums; }
/* 娱乐卡：上面是名字与说明（有图时图在左边），中间一道虚线与两侧缺口，下面是次数与期限 */
.wl-fun { padding: 0; }
.wl-card-body { flex: 1; min-height: 0; display: flex; gap: 12px; padding: 22px 24px 14px; }
.wl-card-pic { flex: none; width: 34%; height: 100%; max-height: 100%; border-radius: 10px; object-fit: cover; }
.wl-card-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.wl-cut { position: relative; flex: none; height: 0; margin: 0 18px; border-top: 1px dashed var(--border-2); }
.wl-cut::before, .wl-cut::after {
  content: ''; position: absolute; top: -9px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--wl-notch); border: 1px solid var(--border);
}
.wl-cut::before { left: -28px; } .wl-cut::after { right: -28px; }
.wl-fun .wl-card-meta { margin-top: 0; padding: 14px 24px 18px; }
.wl-amt { font-variant-numeric: tabular-nums; color: var(--text); }
.wl-amt:where(.is-in) { color: var(--accent); }
.wl-state { font-size: var(--fs-12); color: var(--text-3); }

/* 新建：预览、模板、送给谁、颜色 */
.wl-preview { container-type: inline-size; margin: var(--sp-3) 0 var(--sp-4); }
.wl-preview > .wl-card { height: calc(100cqw / 1.586); }
.wl-tpls, .wl-tos { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-3); }
.wl-tpl { padding: 6px var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border-2); background: var(--surface); font-size: var(--fs-13); color: var(--text); }
.wl-tpl:where(.is-on) { border-color: var(--accent); color: var(--accent); }
.wl-colors { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.wl-swatch { width: 32px; height: 32px; border-radius: 50%; padding: 0; background: var(--wl-c); box-shadow: inset 0 0 0 2px var(--surface), 0 0 0 1px var(--border-2); }
.wl-swatch:where(.wl-c-rose) { --wl-c: var(--wl-rose); } .wl-swatch:where(.wl-c-pink) { --wl-c: var(--wl-pink); }
.wl-swatch:where(.wl-c-peach) { --wl-c: var(--wl-peach); } .wl-swatch:where(.wl-c-sand) { --wl-c: var(--wl-sand); }
.wl-swatch:where(.wl-c-mint) { --wl-c: var(--wl-mint); } .wl-swatch:where(.wl-c-sky) { --wl-c: var(--wl-sky); }
.wl-swatch:where(.wl-c-lilac) { --wl-c: var(--wl-lilac); } .wl-swatch:where(.wl-c-ink) { --wl-c: var(--wl-ink); }
.wl-swatch:where(.is-on) { box-shadow: inset 0 0 0 2px var(--surface), 0 0 0 2px var(--accent); }
.wl-acts { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* 对话里：送卡画成一张小卡，用卡写明状态，要你同意的带两个按钮 */
.bubble-funcard { padding: 6px; background: var(--surface); }
.bubble-funcard .wl-card:where(.is-small) { --wl-notch: var(--surface); width: 220px; height: calc(220px / 1.586); box-shadow: none; }
.bubble-funcard .wl-card:where(.is-small) .wl-card-body { padding: 12px 14px 8px; }
.bubble-funcard .wl-card:where(.is-small) .wl-card-meta { padding: 8px 14px 10px; }
.bubble-funcard .wl-card:where(.is-small) .wl-card-name { font-size: var(--fs-15); }
.bubble-funcard .wl-card:where(.is-small) .wl-card-desc { font-size: var(--fs-12); -webkit-line-clamp: 2; }
.fc-foot { padding: 6px 4px 2px; font-size: var(--fs-11); color: var(--text-3); }
.fc-acts { display: flex; gap: var(--sp-2); padding: var(--sp-2) 0 2px; }
.fc-btn { flex: 1; height: 32px; border-radius: var(--r-full); border: 1px solid var(--border-2); background: var(--surface); font-size: var(--fs-13); color: var(--text); }
.fc-btn:where(.is-ok) { border-color: var(--accent); color: var(--accent); }

/* 谁是卧底 */
.gm-word { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); color: var(--text); }
.gm-word-label { font-size: var(--fs-12); color: var(--text-3); }
.gm-word-text { font-size: var(--fs-24); font-weight: var(--fw-bold); letter-spacing: .08em; }
.gm-spy-input { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); }
.gm-spy-input > textarea { width: 100%; }
.gm-vote { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); }
.gm-rounds { display: flex; flex-direction: column; gap: var(--sp-2); }
.gm-round { padding: var(--sp-3); border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--border); }
.gm-round-title { font-size: var(--fs-12); color: var(--text-3); margin-bottom: 4px; }
.gm-desc { font-size: var(--fs-14); line-height: 1.6; }
.gm-desc > b { font-weight: var(--fw-semi); margin-right: var(--sp-2); }
.gm-votes { margin-top: 4px; font-size: var(--fs-12); color: var(--text-3); }

/* 单行横滑（4.902）：数量跟着用户的数据或开关变的那一排（成员、角色、分组、相册），不换行、不长高。
   右边缘渐隐，露出半个，看得出后面还有（第 28 条）。和 .chip-row（或别的 flex 换行的一排）一起挂。
   放在旧版样式的最后，同样一个类名的特异度下压得住前面写的 flex-wrap: wrap */
.chip-strip {
  flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  mask-image: linear-gradient(to right, var(--text) calc(100% - 28px), transparent);
  -webkit-mask-image: linear-gradient(to right, var(--text) calc(100% - 28px), transparent);
  padding-right: var(--sp-5);
}
.chip-strip::-webkit-scrollbar { display: none; }
.chip-strip > * { flex: none; }
/* 本来就是一行横滑、但数量跟着用户的数据变的那几排（4.902）：看不出后面还有。右边缘同样渐隐 */
.dy-chips, .hb-chips, .cl-owners, .link-chars, .tb-tags {
  mask-image: linear-gradient(to right, var(--text) calc(100% - 28px), transparent);
  -webkit-mask-image: linear-gradient(to right, var(--text) calc(100% - 28px), transparent);
  padding-right: var(--sp-5);
}

/* ---- 桌宠（4.940，apps/deskpet）---- */
.dp-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.dp-card { display: flex; flex-direction: column; gap: 6px; padding: var(--sp-3); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--border); text-align: left; }
.dp-card-name { display: flex; justify-content: space-between; align-items: baseline; font-size: var(--fs-15); color: var(--text); }
.dp-card-name span { font-size: var(--fs-12); color: var(--text-3); }
.dp-pic { width: 100%; aspect-ratio: 1; display: grid; place-items: center; border-radius: var(--r-md); color: var(--text-3); overflow: hidden; }
.dp-pic img { width: 100%; height: 100%; object-fit: contain; display: block; }
.dp-pic.is-big { width: 200px; height: 200px; }
/* 动一动：待着、开心轻轻上下，睡着慢慢呼吸，饿了困了往下沉一点 */
.dp-pic:where(.is-idle, .is-happy) img { animation: dp-bob 2.4s var(--ease-out) infinite; }
.dp-pic:where(.is-happy, .is-eat) img { animation-duration: 0.9s; }
.dp-pic:where(.is-sleep) img { animation: dp-breathe 3.6s ease-in-out infinite; }
.dp-pic:where(.is-hungry, .is-sleepy) img { transform: translateY(4%); }
@keyframes dp-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4%); } }
@keyframes dp-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.03); } }
@media (prefers-reduced-motion: reduce) { .dp-pic img { animation: none !important; } }
.dp-bar { display: grid; grid-template-columns: 3em 1fr 2.2em; align-items: center; gap: var(--sp-2); font-size: var(--fs-12); color: var(--text-2); }
.dp-bar-track { height: 6px; border-radius: var(--r-full); background: var(--group-fill); overflow: hidden; }
.dp-bar-track i { display: block; height: 100%; width: var(--v); border-radius: inherit; background: var(--accent); transition: width var(--dur-slow) var(--ease-out); }
.dp-bar-n { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-3); }
.dp-start { font-size: var(--fs-13); color: var(--accent); }
.dp-stage { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: var(--sp-4) 0 var(--sp-3); }
.dp-stage-pic { border-radius: var(--r-lg); }
.dp-state { font-size: var(--fs-13); color: var(--text-3); }
.dp-level { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); font-size: var(--fs-12); color: var(--text-3); }
.dp-level b { font-size: var(--fs-15); color: var(--text); }
.dp-stage + .pad-x .dp-bar { margin: 4px 0; }
.dp-acts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2); margin: var(--sp-4) 0 var(--sp-2); }
.dp-act { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: var(--sp-3) 0; border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--border); font-size: var(--fs-12); color: var(--text); }
.dp-act:disabled { opacity: .4; }
.dp-last { font-size: var(--fs-12); color: var(--text-3); text-align: center; margin-bottom: var(--sp-3); }
.dp-set { padding: var(--sp-3) var(--sp-4) 0; }
.dp-set-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }
.dp-set-del { font-size: var(--fs-12); color: var(--danger); }
.dp-slots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.dp-slot { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.dp-slot-pic { width: 100%; aspect-ratio: 1; display: grid; place-items: center; border-radius: var(--r-md); border: 1px dashed var(--border); color: var(--text-3); overflow: hidden; }
.dp-slot-pic img { width: 100%; height: 100%; object-fit: contain; }
.dp-slot-label { font-size: var(--fs-12); color: var(--text-2); }
.dp-slot-clear { font-size: var(--fs-11); color: var(--text-3); }
.wg-pet { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: var(--sp-2); }
.wg-pet .dp-pic { width: auto; height: 78%; }
.wg-pet:where(.is-wide) { flex-direction: row; gap: var(--sp-3); }
.wg-pet:where(.is-wide) .dp-pic { height: 100%; }
.wg-pet:where(.is-empty) { font-size: var(--fs-12); color: var(--text-3); }
.wg-pet-name { font-size: var(--fs-12); color: var(--text-2); }
.wg-pet-side { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-12); color: var(--text-3); }
.wg-pet-side b { font-size: var(--fs-15); color: var(--text); font-weight: var(--fw-medium); }
.wg-pet-open { position: absolute; right: 6px; bottom: 6px; width: 22px; height: 22px; display: grid; place-items: center; border-radius: var(--r-full); color: var(--text-3); }

/* ==== 新版界面（ARCHITECTURE 4.524） ====
   只在 :root[data-ui="new"] 下生效，旧版一条都不受影响。
   条件一律包进 :where()，特异度停在一个类名：这些元素多半挂着 ph- 钩子，
   作者写一个契约类名就要盖得住（第 18 条）。放在最后，同特异度时靠「后写的赢」压过上面各处 */

/* 顶栏与列表：字号拉开一级，副标题从 34% 升到 56%，分组名做成小标题 */
:where(:root[data-ui="new"]) .nav-title { font-size: var(--fs-17); }
:where(:root[data-ui="new"]) .list-wrap { margin: var(--sp-6) 0; }
:where(:root[data-ui="new"]) .list-title {
  font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); letter-spacing: .04em;
}
:where(:root[data-ui="new"]) .list-item { min-height: 54px; }
:where(:root[data-ui="new"]) .li-title { font-size: calc(var(--fs-15) + 1px); }
:where(:root[data-ui="new"]) .li-sub { font-size: var(--fs-13); color: var(--text-2); }

/* 按钮（方案 A）：主按钮描边，其余是文字，删除是暗红文字。没有填色的按钮 */
:where(:root[data-ui="new"]) .btn { border-radius: var(--r-btn); font-weight: var(--fw-semi); }
:where(:root[data-ui="new"]) .btn-md { height: 44px; }
:where(:root[data-ui="new"]) .btn-lg { height: 48px; }
:where(:root[data-ui="new"]) .btn-primary { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); }
:where(:root[data-ui="new"]) .btn-ghost { background: none; color: var(--text); font-weight: var(--fw-medium); }
:where(:root[data-ui="new"]) .btn-outline { box-shadow: inset 0 0 0 1px var(--border-2); font-weight: var(--fw-medium); }
:where(:root[data-ui="new"]) .btn-danger { background: none; color: var(--danger-text); }
/* 次按钮旁边没有主按钮时照旧是浅灰底（用户指出「编辑本人人设」的底丢了）：
   一排全是次按钮、或者只有一颗的，去掉底色就成了几行散字，看不出能点。旁边有描边主按钮的才只留文字。
   :has 里不写逗号（契约核对按逗号切），两个条件拆开写 */
:where(:root[data-ui="new"] :not(:has(> .btn-primary)):not(:has(> .btn-outline))) > .btn-ghost { background: var(--surface-2); }

/* 说明：页顶那块不加灰底，页脚的左对齐。内容不删，只是不再像一块块贴上去的告示 */
/* 左右的留白照旧：有几页的说明框外面没有 pad-x，靠它自己这一圈离开屏幕边 */
:where(:root[data-ui="new"]) .hint-box { background: none; padding: var(--sp-1) var(--sp-3); font-size: var(--fs-13); }
:where(:root[data-ui="new"]) .settings-foot {
  text-align: left; font-size: var(--fs-12); line-height: 1.6; padding: var(--sp-4) var(--sp-4) var(--sp-6);
}
:where(:root[data-ui="new"]) .field-desc { color: var(--text-2); }

/* 空状态：往下放，宋体一句标题，说明一行 */
:where(:root[data-ui="new"]) .empty { padding: 72px var(--sp-6) var(--sp-8); }
:where(:root[data-ui="new"]) .empty-title {
  font-family: var(--font-display); font-size: var(--fs-20); font-weight: var(--fw-semi); color: var(--text);
}
:where(:root[data-ui="new"]) .empty-desc { font-size: var(--fs-13); color: var(--text-2); }

/* 默认头像与无图格子：不再是灰块里一个首字，换成应用图标那只猫（头像取脸，格子取整只）。
   组件在没有图时挂 cat-face / cat-full，首字留在里面给旧版用，新版藏起来 */
:where(:root[data-ui="new"]) .cat-face {
  background: var(--cat-face) center / var(--cat-size, 100%) no-repeat, var(--cat-bg); color: transparent; font-size: 0;
}
:where(:root[data-ui="new"]) .cat-full {
  background: var(--cat-full) center / var(--cat-size, 38%) no-repeat, var(--cat-bg); color: transparent; font-size: 0;
}
/* 两条分开写：契约核对按逗号切选择器，括号里的逗号会被它切坏 */
:where(:root[data-ui="new"] .cat-face) > :where(:not(.ct-badge)) { visibility: hidden; }
:where(:root[data-ui="new"] .cat-full) > :where(:not(.ct-badge)) { visibility: hidden; }
/* 联系首页那张大卡：爪印图自带留白，按原大铺 */
.ct-cover { --cat-size: 100%; }

/* 一级页的大标题（Page 的 hero）：宋体标题，上面一行眉题。滚过去之后顶栏小标题才出现 */
.page-hero { display: none; }
:where(:root[data-ui="new"]) .page-hero { display: block; padding: var(--sp-1) var(--sp-4) var(--sp-4); }
.page-hero-eb {
  font-size: var(--fs-11); font-weight: var(--fw-semi); letter-spacing: .2em; color: var(--text-3);
  text-transform: uppercase;
}
.page-hero-title {
  font-family: var(--font-display); font-size: calc(var(--fs-28) + 2px); font-weight: var(--fw-semi);
  line-height: 1.25; letter-spacing: .02em; margin-top: 2px;
}
:where(:root[data-ui="new"]) .nav-title { transition: opacity var(--dur-fast) var(--ease); }
:where(:root[data-ui="new"] .page.has-hero:not(.is-scrolled)) .nav-title { opacity: 0; }

/* 说明（4.525、4.527）：旧版里原样显示；新版里收起来，集中在「设置 - 说明书」 */
:where(:root[data-ui="new"]) .li-info { display: none; }
:where(:root[data-ui="new"]) .li-sub:where(.is-info-only) { display: none; }
:where(:root[data-ui="new"]) .field-desc:where(.is-info-only) { display: none; }
:where(:root[data-ui="new"]) .is-note { display: none; }
/* 说明收起来之后，前后两个按钮之间就没有间隔了（世界书列表底下「批量导入」与「注入位置总览」粘在一起，4.656）。
   紧跟在收起的说明后面的按钮补一段间隔。按钮挂着契约钩子，整段条件包进 :where()，只剩 .btn 一个类名的特异度（第 18 条） */
:where(:root[data-ui="new"] .is-note) + .btn { margin-top: var(--sp-3); }

/* 情侣空间新版（4.526）：只在新版里出现，类名不与旧版共用 */
.spn-hero { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4) var(--sp-4) 0; }
.spn-duo { display: flex; }
/* 头像挂着契约钩子：这里的条件包进 :where()，圆形用 Avatar 的 radius 传进去（第 18 条） */
:where(.spn-duo > :last-child) { margin-left: -16px; box-shadow: 0 0 0 3px var(--bg); }
.spn-days { display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.spn-days-n { font-family: var(--font-display); font-size: var(--fs-56); line-height: 1; font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.spn-days-n small { font-size: var(--fs-15); font-weight: var(--fw-normal); margin-left: 4px; }
.spn-days-s { font-size: var(--fs-12); color: var(--text-2); margin-top: var(--sp-2); }
.spn-days-set { font-size: var(--fs-14); color: var(--text); box-shadow: inset 0 -1px 0 var(--text); padding-bottom: 2px; }
.spn-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: var(--sp-6) var(--sp-4) 0; padding: var(--sp-3) 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.spn-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.spn-stat + .spn-stat { box-shadow: -1px 0 0 var(--border); }
.spn-stat b { font-size: var(--fs-20); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.spn-stat span { font-size: var(--fs-11); color: var(--text-2); }
.spn-sec { padding: var(--sp-6) var(--sp-4) var(--sp-2); font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); letter-spacing: .04em; }
.spn-next { display: flex; align-items: flex-end; justify-content: space-between; width: calc(100% - var(--sp-8)); margin: 0 var(--sp-4); padding: var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); text-align: left; }
.spn-next-l { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.spn-next-k { font-size: var(--fs-12); color: var(--text-2); }
.spn-next-v { font-size: var(--fs-15); }
.spn-next-v b { font-family: var(--font-display); font-size: var(--fs-28); font-weight: var(--fw-semi); margin: 0 4px; font-variant-numeric: tabular-nums; }
.spn-next-d { font-family: var(--font-display); font-size: var(--fs-14); color: var(--text-2); letter-spacing: .06em; font-variant-numeric: tabular-nums; }
.spn-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin: var(--sp-2) var(--sp-4) 0; }
.spn-cell { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); padding: var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); text-align: left; min-width: 0; }
.spn-cell svg { margin-bottom: var(--sp-2); }
.spn-cell-t { font-size: calc(var(--fs-15) + 1px); font-weight: var(--fw-semi); }
.spn-cell-s { font-size: var(--fs-12); color: var(--text-2); max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spc-list { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) 0; }
.spc { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); text-align: left; width: 100%; }
.spc-body { flex: 1; min-width: 0; }
.spc-name { font-family: var(--font-display); font-size: var(--fs-20); font-weight: var(--fw-semi); }
.spc-sub { font-size: var(--fs-12); color: var(--text-2); margin-top: 2px; }
.spc-days { font-family: var(--font-display); font-size: var(--fs-28); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; flex: none; }
.spc-days small { font-size: var(--fs-12); font-weight: var(--fw-normal); margin-left: 2px; color: var(--text-2); }
.spc-who { padding: var(--sp-4) var(--sp-4) 0; font-size: var(--fs-12); color: var(--text-3); }

/* 待办新版（4.526） */
.tdn-sec { padding: var(--sp-5) var(--sp-4) var(--sp-1); font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); letter-spacing: .04em; }
.tdn-list { margin: 0 var(--sp-4); }
.tdn-row { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) 0; }
.tdn-row + .tdn-row { border-top: 1px solid var(--border); }
.tdn-tick { flex: none; width: 20px; height: 20px; margin-top: 2px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--text); display: flex; align-items: center; justify-content: center; color: var(--bg); position: relative; }
.tdn-tick::after { content: ''; position: absolute; inset: -10px; }
.tdn-row:where(.is-done) .tdn-tick { background: var(--text); }
.tdn-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; text-align: left; }
.tdn-text { font-size: calc(var(--fs-15) + 1px); line-height: 1.45; }
.tdn-row:where(.is-done) .tdn-text { color: var(--text-3); text-decoration: line-through; }
.tdn-meta { font-size: var(--fs-12); color: var(--text-2); font-variant-numeric: tabular-nums; }
.tdn-fold { display: flex; align-items: center; gap: var(--sp-1); margin: var(--sp-5) var(--sp-4) 0; font-size: var(--fs-13); color: var(--text-2); }
/* 中文眉题不拉大字距（字距是给全大写英文用的），也不加粗 */
.page-hero-eb:where(.is-cjk) { letter-spacing: .04em; font-weight: var(--fw-normal); color: var(--text-2); }

/* 日常新版（4.526） */
.dyn-sec { padding: var(--sp-4) var(--sp-4) var(--sp-2); font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); letter-spacing: .04em; }
.dyn-cards { display: flex; flex-direction: column; gap: var(--sp-2); padding: 0 var(--sp-4); }
.dyn-card { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); text-align: left; width: 100%; }
.dyn-who { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.dyn-name { font-size: var(--fs-14); font-weight: var(--fw-semi); flex: 1; min-width: 0; }
.dyn-slot { font-size: var(--fs-12); color: var(--text-2); flex: none; }
.dyn-now { font-family: var(--font-display); font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1.35; }
.dyn-now:where(.is-quiet) { font-family: inherit; font-size: var(--fs-14); font-weight: var(--fw-normal); color: var(--text-2); }
.dyn-extra { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-13); color: var(--text-2); }

/* 只在一版里出现的小块（4.526）：组件两样都画，按版本显示其中一样 */
.ui-new-only { display: none; }
:where(:root[data-ui="new"]) .ui-new-only { display: flex; }
:where(:root[data-ui="new"]) .ui-classic-only { display: none; }
/* 主屏新版：没填的横条先显示日期 */
.wg-date { flex-direction: column; gap: 2px; }
.wg-date-big { font-family: var(--font-display); font-size: var(--fs-28); font-weight: var(--fw-semi); line-height: 1.2; }
.wg-date-sub { font-size: var(--fs-13); opacity: .7; }
.wg-empty-go { margin-top: var(--sp-2); font-size: var(--fs-12); box-shadow: inset 0 -1px 0 currentColor; padding-bottom: 1px; }
:where(:root[data-ui="new"]) .wg-empty { flex-direction: column; }
/* 说明书（4.527） */
.hbk-search { padding: var(--sp-2) var(--sp-4) var(--sp-3); position: sticky; top: 0; background: var(--bg); z-index: 1; }
.hbk-count { font-size: var(--fs-12); color: var(--text-2); margin-top: var(--sp-2); }
.hbk-list { padding: 0 var(--sp-4) var(--sp-8); }
.hbk-group + .hbk-group { border-top: 1px solid var(--border); }
.hbk-app { display: flex; align-items: center; gap: var(--sp-2); width: 100%; padding: var(--sp-4) 0; text-align: left; }
.hbk-app-name { flex: 1; font-size: calc(var(--fs-15) + 1px); font-weight: var(--fw-semi); }
.hbk-app-n { font-size: var(--fs-12); color: var(--text-3); font-variant-numeric: tabular-nums; }
.hbk-rows { display: flex; flex-direction: column; gap: var(--sp-4); padding-bottom: var(--sp-5); }
.hbk-title { font-size: var(--fs-14); font-weight: var(--fw-semi); margin-bottom: 2px; }
.hbk-text { font-size: var(--fs-14); line-height: 1.75; color: var(--text-2); }

/* ---- 新版：设置根页（4.528） ---- */
.stn-api { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: calc(100% - var(--sp-8)); margin: var(--sp-2) var(--sp-4) var(--sp-2); padding: var(--sp-4) var(--sp-4) var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); text-align: left; color: var(--text); }
.stn-api-k { font-size: var(--fs-12); color: var(--text-2); letter-spacing: .04em; }
.stn-api-name { margin-top: var(--sp-1); font-family: var(--font-display); font-size: var(--fs-20); font-weight: var(--fw-semi); line-height: 1.3; word-break: break-all; }
.stn-api-model { font-size: var(--fs-14); color: var(--text-2); word-break: break-all; }
.stn-api-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); align-self: stretch; margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: var(--fs-13); color: var(--text-2); }
.stn-api-go { display: inline-flex; align-items: center; gap: 2px; flex: none; color: var(--text); font-weight: var(--fw-medium); }
.stn-foot { padding: var(--sp-6) var(--sp-4) var(--sp-8); font-size: var(--fs-12); line-height: 1.7; color: var(--text-3); }

/* ---- 新版：用量与上限（4.528） ---- */
.lmn-sum { display: flex; flex-direction: column; gap: 2px; margin: var(--sp-2) var(--sp-4) var(--sp-4); padding: var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); }
.lmn-sum-k { font-size: var(--fs-12); color: var(--text-2); letter-spacing: .04em; }
.lmn-sum-n { font-size: var(--fs-15); }
.lmn-sum-n b { font-family: var(--font-display); font-size: var(--fs-28); font-weight: var(--fw-semi); margin-right: 4px; font-variant-numeric: tabular-nums; }
.lmn-sum-list { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.lmn-sum-row { display: flex; flex-direction: column; gap: 1px; font-size: var(--fs-14); }
.lmn-sum-row > :last-child { font-size: var(--fs-12); color: var(--text-2); line-height: 1.55; }
.lmn-sum-warn { margin-top: var(--sp-3); font-size: var(--fs-13); color: var(--danger-text); }

/* ---- 新版：收起组（ui/list.js 的 Fold，4.528） ---- */
.fold { border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.fold + .fold { border-top: none; }
.fold-head { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-height: 56px; padding: 0 var(--sp-4); text-align: left; color: var(--text); }
.fold-title { flex: 1; font-size: calc(var(--fs-15) + 1px); font-weight: var(--fw-semi); }
.fold-badge { font-size: var(--fs-12); color: var(--text-2); }
.fold-body { padding-bottom: var(--sp-3); }
/* 收起组里第一段列表自己的标题与组头重复，藏掉 */
:where(.fold-body > .list-wrap:first-child) > .list-title { display: none; }

/* ---- 新版：聊天二级页（4.530） ---- */
/* 危险的行（清空、删除群聊）：旧版 --danger 是黑色，和普通入口一模一样，新版用删除按钮那种暗红 */
:where(:root[data-ui="new"]) .list-item.is-danger .li-title { color: var(--danger-text); }
/* 角色主页的名字是这一页最该大的字 */
:where(:root[data-ui="new"]) .ig-name { font-family: var(--font-display); font-size: var(--fs-20); line-height: 1.3; }
/* 年度回顾、那年今天：数字和日期做主角 */
:where(:root[data-ui="new"]) .yr-head > b { font-family: var(--font-display); font-size: var(--fs-17); font-weight: var(--fw-semi); }
:where(:root[data-ui="new"]) .yr-cell b { font-family: var(--font-display); font-size: var(--fs-40); font-weight: var(--fw-semi); line-height: 1.1; font-variant-numeric: tabular-nums; }
:where(:root[data-ui="new"]) .yr-cell { padding: var(--sp-4) var(--sp-4) var(--sp-3); border-radius: var(--r-md); }

/* ---- 新版：联系（4.530） ---- */
:where(:root[data-ui="new"]) .pf-name { font-family: var(--font-display); font-size: var(--fs-24); line-height: 1.3; }
:where(:root[data-ui="new"]) .pf-fact b { font-family: var(--font-display); font-size: var(--fs-17); font-variant-numeric: tabular-nums; }
/* 别人眼中的我：灰卡里不再套一张白卡，统计数直接放在灰底上，上下两条细线隔开 */
:where(:root[data-ui="new"]) .im-stats { background: none; border-radius: 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
:where(:root[data-ui="new"]) .im-stats b { font-family: var(--font-display); font-size: var(--fs-24); font-variant-numeric: tabular-nums; }

/* ---- 新版：记忆（4.530） ---- */
/* 首页顶上 S/A/B/C 四个数是这一页的主角（情侣空间旧版那一页也用 stat-chip，新版那页已经换掉，不受影响） */
:where(:root[data-ui="new"]) .stat-chip b { font-family: var(--font-display); font-size: var(--fs-28); line-height: 1.15; font-variant-numeric: tabular-nums; }

/* ---- 新版：记账、相册、衣帽间（4.531） ---- */
/* 本月卡片：浅色块不描边；支出与收入同样大小（4.767） */
:where(:root[data-ui="new"]) .bl-card { background: var(--surface-2); border: none; border-radius: var(--r-md); }
/* 本月卡片（4.768，用户定的）：大字只放结余，点开才是支出与收入两行。从前支出 40 号、收入 17 号并排，支出一长收入就看不见了；
   4.767 改成两边一样大并排，用户嫌丑。数每三位一个逗号（currency.display） */
:where(:root[data-ui="new"]) .bl-net .bl-money.bl-lg { font-family: var(--font-display); font-size: var(--fs-40); font-weight: var(--fw-semi); line-height: 1.1; overflow-wrap: anywhere; }
:where(:root[data-ui="new"]) .bl-net:where(.is-long) .bl-money.bl-lg { font-size: var(--fs-28); }
:where(:root[data-ui="new"]) .bl-net:where(.is-longer) .bl-money.bl-lg { font-size: var(--fs-24); }
:where(:root[data-ui="new"]) .bl-card-net { display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; }
:where(:root[data-ui="new"]) .bl-card-net .bl-card-head { display: flex; align-items: center; justify-content: space-between; }
:where(:root[data-ui="new"]) .bl-sum-rows { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
:where(:root[data-ui="new"]) .bl-sum-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
:where(:root[data-ui="new"]) .bl-sum-row .bl-money { font-size: var(--fs-17); font-variant-numeric: tabular-nums; text-align: right; overflow-wrap: anywhere; min-width: 0; }
:where(:root[data-ui="new"]) .bl-card-row { align-items: flex-end; }
/* 流水行的分类：不再是灰方块（像缺图的头像），改成一枚细线小圆，字在里面 */
:where(:root[data-ui="new"]) .bl-cat { width: 40px; height: 40px; border-radius: var(--r-full); background: none; box-shadow: inset 0 0 0 1px var(--border-2); font-size: var(--fs-11); }
/* 衣帽间：整个 app 只有这里用虚线框，换成浅色块；「记到衣帽间」的候选不画黑粗框 */
:where(:root[data-ui="new"]) .cl-unsorted { border: none; background: var(--surface-2); border-radius: var(--r-md); }
:where(:root[data-ui="new"]) .cl-pick-row.cl-gen-row.is-on { box-shadow: none; background: var(--surface-2); border-radius: var(--r-md); }
/* 文字形式的删除（「删除这个相册」之类）：旧版 --danger 是黑色，新版用暗红 */
:where(:root[data-ui="new"]) .nav-text.is-danger { color: var(--danger-text); }

/* ---- 新版：商城、收藏馆自己画的黑底按钮改描边（4.531，方案 A） ---- */
/* 这几颗没走公用 Button，第 1 批的按钮规则管不到。选中态的胶囊、我发的气泡、数据条照旧是黑的，那是状态不是按钮 */
:where(:root[data-ui="new"]) .ml-save { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); font-weight: var(--fw-semi); }
:where(:root[data-ui="new"]) .ml-goods-act { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); }
:where(:root[data-ui="new"]) .ml-offer-btn:where(.is-primary) { background: none; color: var(--text); border-color: var(--text); }
:where(:root[data-ui="new"]) .ml-ib:where(.is-dark) { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); }
:where(:root[data-ui="new"]) .cx-hero-btn.is-k { background: var(--surface); color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); }
:where(:root[data-ui="new"]) .cx-fab { background: var(--surface); color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text), var(--shadow-2); }

/* ---- 记忆总结页（4.532）：上面这段对话积了多少，下面一颗「立即总结」 ---- */
.sum-card { display: flex; flex-direction: column; gap: 2px; margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-4); border-radius: var(--r-lg); background: var(--surface-2); }
.sum-k { font-size: var(--fs-12); color: var(--text-3); }
.sum-n { font-size: var(--fs-15); color: var(--text); }
.sum-n b { font-size: var(--fs-28); font-weight: var(--fw-semi); margin-right: 4px; font-variant-numeric: tabular-nums; }
.sum-sub { font-size: var(--fs-13); color: var(--text-2); }
:where(:root[data-ui="new"]) .sum-card { border-radius: var(--r-md); }
:where(:root[data-ui="new"]) .sum-n b { font-family: var(--font-display); font-size: var(--fs-40); line-height: 1.1; }

/* ---- 新版：第 4 批（4.536） ---- */
/* 各 app 自己画的黑底按钮改描边（方案 A）。「角色写」那颗随线下的版面主题走，不动 */
:where(:root[data-ui="new"]) .mz-save,
:where(:root[data-ui="new"]) .fc-save { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); font-weight: var(--fw-semi); }
:where(:root[data-ui="new"]) .mz-draw { background: var(--surface); color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); }
:where(:root[data-ui="new"]) .fc-start { background: none; color: var(--text); box-shadow: inset 0 0 0 1.4px var(--text); font-weight: var(--fw-semi); }
:where(:root[data-ui="new"]) .hb-up { background: none; color: var(--text); box-shadow: inset 0 0 0 1.2px var(--text); font-weight: var(--fw-semi); border-radius: var(--r-btn); }
/* 日记的月份是这一页的标题，改宋体 */
:where(:root[data-ui="new"]) .dy-m { font-family: var(--font-display); font-size: var(--fs-28); }
/* 健康首页四格：去描边改浅色块，数字改宋体（审计：已有焦点，只是不够大） */
:where(:root[data-ui="new"]) .hl-tile { background: var(--surface-2); border: none; box-shadow: none; border-radius: var(--r-md); }
:where(:root[data-ui="new"]) .hl-tile b { font-family: var(--font-display); font-size: var(--fs-24); font-variant-numeric: tabular-nums; }

/* ---- 主屏下滑搜索（4.541） ---- */
/* 挂在 body 上，读不到 .root 里定义的 --safe-top（4.567：搜索框顶到了状态栏下面），直接读系统的安全区 */
.spot { position: fixed; inset: 0; z-index: var(--z-sheet); display: flex; flex-direction: column; background: var(--bg); padding-top: calc(env(safe-area-inset-top, 0px) + var(--sp-2)); animation: spot-in var(--dur) var(--ease); }
@keyframes spot-in { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .spot { animation: none; } }
.spot-bar { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.spot-input { flex: 1; display: flex; align-items: center; gap: var(--sp-2); height: 40px; padding: 0 var(--sp-3); border-radius: var(--r-md); background: var(--surface-2); color: var(--text-3); }
.spot-input input { flex: 1; min-width: 0; border: 0; outline: 0; background: none; color: var(--text); font-size: var(--fs-15); }
.spot-clear { display: grid; place-items: center; width: 22px; height: 22px; border-radius: var(--r-full); background: var(--border-2); color: var(--bg); }
.spot-cancel { flex: none; font-size: var(--fs-15); color: var(--text); }
.spot-body { flex: 1; overflow-y: auto; padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sp-6)); }
.spot-sec { padding: var(--sp-5) var(--sp-4) var(--sp-2); font-size: var(--fs-12); font-weight: var(--fw-semi); color: var(--text-2); }
.spot-apps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-2); padding: 0 var(--sp-4); }
.spot-app { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); min-width: 0; }
.spot-app .app-tile { width: 52px; height: 52px; }
.spot-app-name { max-width: 100%; font-size: var(--fs-12); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot-row { display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 52px; padding: var(--sp-2) var(--sp-4); text-align: left; color: var(--text); }
.spot-row + .spot-row { box-shadow: inset 0 1px 0 var(--border); }
.spot-row-ico { flex: none; display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--r-full); background: var(--surface-2); color: var(--text-2); }
.spot-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.spot-row-title { font-size: var(--fs-15); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot-row-sub { font-size: var(--fs-12); color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spot-none { padding: var(--sp-6) var(--sp-4) var(--sp-2); font-size: var(--fs-14); color: var(--text-3); }
/* 挂在对话上的功能：先选是哪一段（4.646） */
.spot-pick-title { flex: 1; min-width: 0; font-size: var(--fs-14); color: var(--text-2); line-height: 1.4; }
.spot-row.is-static { cursor: default; }

/* ---- 新版主屏（4.543） ---- */
/* 播放器横条没配图、没写字：不画空封面，日期做这一条的主角 */
:where(:root[data-ui="new"] .wg-player.is-empty) .pl-cover { display: none; }
:where(:root[data-ui="new"] .wg-player.is-empty) .wg-date-big { font-size: var(--fs-40); line-height: 1.1; }
:where(:root[data-ui="new"] .wg-player.is-empty) .wg-date-sub { font-size: var(--fs-15); }
/* 最近会话空着：多一行告诉人点哪里 */
:where(:root[data-ui="new"]) .wg-empty-sub { display: block; margin-top: var(--sp-1); font-size: var(--fs-12); opacity: .7; }

/* ---- 换一套接口对比（4.561，apps/chat/pages/ComparePage.js）：两版并排 ---- */
.cmp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-4); }
.cmp-col { min-width: 0; border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3); background: var(--surface); }
.cmp-head { font-size: var(--fs-12); color: var(--text-2); margin-bottom: var(--sp-2); overflow-wrap: anywhere; }
.cmp-body { font-size: var(--fs-14); line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---- 扭蛋机（4.616） ---- */
.gc-page { padding-bottom: var(--sp-8); }
.gc-stage { display: flex; flex-direction: column; align-items: center; padding: var(--sp-5) var(--sp-4) var(--sp-3); }
.gc-machine { width: 52%; max-width: 220px; }
.gc-machine > svg { display: block; width: 100%; height: auto; overflow: visible; }
.gc-dome { fill: var(--surface); stroke: var(--border-2); stroke-width: 1.2; }
.gc-b { stroke: var(--surface); stroke-width: 1; }
.gc-b:where(.gc-b-a) { fill: var(--gc-ball-a); }
.gc-b:where(.gc-b-b) { fill: var(--gc-ball-b); }
.gc-b:where(.gc-b-c) { fill: var(--gc-ball-c); }
.gc-body { fill: var(--surface-2); stroke: var(--border-2); stroke-width: 1.2; }
.gc-neck { fill: var(--surface); stroke: var(--border-2); stroke-width: 1.2; }
.gc-knob > circle { fill: var(--surface); stroke: var(--text-2); stroke-width: 1.4; }
.gc-knob > path { stroke: var(--text-2); stroke-width: 2.2; stroke-linecap: round; }
.gc-knob { transform-box: fill-box; transform-origin: center; }
.gc-slot { fill: var(--bg); stroke: var(--border-2); stroke-width: 1.2; }
.gc-drop { fill: var(--gc-ball-a); opacity: 0; }
.gc-balls { transform-box: fill-box; transform-origin: center; }
.gc-machine:where(.is-spinning) .gc-knob { animation: gc-turn .7s var(--ease-out) both; }
.gc-machine:where(.is-spinning) .gc-balls { animation: gc-shake .7s ease-in-out both; }
.gc-machine:where(.is-spinning) .gc-drop { animation: gc-fall .4s .7s var(--ease-out) both; }
@keyframes gc-turn { to { transform: rotate(360deg); } }
@keyframes gc-shake { 0%, 100% { transform: none; } 25% { transform: translate(-2px, 1px) rotate(-4deg); } 50% { transform: translate(2px, -1px) rotate(4deg); } 75% { transform: translate(-1px, 1px) rotate(-2deg); } }
@keyframes gc-fall { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
.gc-stats { display: flex; gap: var(--sp-8); margin-top: var(--sp-4); }
.gc-stats > div { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.gc-stats b { font-size: var(--fs-24); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; }
.gc-stats span { font-size: var(--fs-12); color: var(--text-3); }
.gc-go { width: 100%; margin-top: var(--sp-4); }
.gc-hint { margin-top: var(--sp-2); min-height: 1em; font-size: var(--fs-12); line-height: 1.6; color: var(--text-3); text-align: center; }
.gc-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: var(--gc-common); }
.gc-dot:where(.gc-r-rare) { background: var(--gc-rare); }
.gc-dot:where(.gc-r-epic) { background: var(--gc-epic); }
.gc-swap { padding: 5px var(--sp-3); border-radius: var(--r-full); border: 1px solid var(--border-2); background: var(--surface); font-size: var(--fs-13); color: var(--text); }
.gc-swap:where(.is-off) { color: var(--text-3); }
.gc-gift { display: flex; gap: var(--sp-2); align-items: center; }
.gc-gift > .num-row { flex: 1; }
.gc-result {
  position: absolute; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; padding: var(--sp-6);
  background: color-mix(in srgb, var(--bg) 70%, transparent); animation: wl-in .25s var(--ease-out) both;
}
.gc-result-card {
  --gc-c: var(--gc-common);
  width: 100%; max-width: 320px; display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--sp-6) var(--sp-5) var(--sp-5); border-radius: 20px; background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--wl-shadow-on);
}
.gc-result-card:where(.gc-r-rare) { --gc-c: var(--gc-rare); }
.gc-result-card:where(.gc-r-epic) { --gc-c: var(--gc-epic); }
.gc-capsule { position: relative; width: 56px; height: 56px; margin-bottom: var(--sp-3); }
.gc-capsule > i { position: absolute; left: 0; right: 0; height: 28px; border: 1.5px solid var(--gc-c); }
.gc-top { top: 0; border-radius: 28px 28px 4px 4px; background: color-mix(in srgb, var(--gc-c) 30%, var(--surface)); animation: gc-open-top .5s .1s var(--ease-out) both; }
.gc-bottom { bottom: 0; border-radius: 4px 4px 28px 28px; background: var(--surface); animation: gc-open-bottom .5s .1s var(--ease-out) both; }
@keyframes gc-open-top { to { transform: translate(-10px, -8px) rotate(-18deg); } }
@keyframes gc-open-bottom { to { transform: translate(6px, 4px) rotate(8deg); } }
.gc-result-rare { font-size: var(--fs-12); letter-spacing: .12em; color: var(--gc-c); }
.gc-result-name { margin-top: 4px; font-size: var(--fs-24); font-weight: var(--fw-semi); }
.gc-result-desc { margin-top: 6px; font-size: var(--fs-14); line-height: 1.6; color: var(--text-2); }
.gc-result-note { margin-top: var(--sp-3); font-size: var(--fs-12); color: var(--text-3); }
.gc-result-acts { display: flex; gap: var(--sp-2); margin-top: var(--sp-5); width: 100%; justify-content: center; }
.gc-form { padding-bottom: var(--sp-8); }
/* 对话里的那一条 */
.bubble-gacha .gc-ball { display: inline-flex; color: var(--gc-common); }
.bubble-gacha:where(.gc-r-rare) .gc-ball { color: var(--gc-rare); }
.bubble-gacha:where(.gc-r-epic) .gc-ball { color: var(--gc-epic); }

/* 会话菜单最上面的搜索（4.636） */
.menu-search { padding: 0 var(--sp-4) var(--sp-3); }
.menu-search .menu-search-box { margin-bottom: 0; }
.menu-search-miss { padding: var(--sp-3) var(--sp-1) 0; font-size: var(--fs-13); color: var(--text-3); }
.menu-search-history {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  margin-top: var(--sp-3); padding: var(--sp-3) var(--sp-1);
  border: none; background: none; color: var(--text-2); font-size: var(--fs-14); text-align: left;
}
/* 不在这份菜单里、在别处的功能（4.646） */
.menu-search-sec { padding: var(--sp-3) var(--sp-1) var(--sp-1); font-size: var(--fs-12); color: var(--text-3); }
.menu-search-other {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2) var(--sp-1); border: none; background: none; color: var(--text-2); text-align: left;
}
.menu-search-other-main { display: flex; flex-direction: column; min-width: 0; }
.menu-search-other-t { font-size: var(--fs-14); color: var(--text); }
.menu-search-other-at { font-size: var(--fs-12); color: var(--text-3); }

/* 扭蛋机的奖池与生成结果：会越放越多，放进限高的滑动区域（4.642，CLAUDE.md 第 26 条） */
.gc-scroll { max-height: 420px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
:where(.gc-scroll) .list-title { position: sticky; top: 0; z-index: 1; background: var(--bg); }

/* 记账：当场加分类的那一枚（4.642）虚线描边，和已有分类分得开；小类明细放进限高滑动区域（第 26 条） */
.chip-add { border-style: dashed; color: var(--text-2); }
.bl-scroll { max-height: 360px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
:where(.bl-scroll) .list-title { position: sticky; top: 0; z-index: 1; background: var(--bg); }

/* 门禁卡、钥匙、房卡（4.643）：和账户卡同一套浅色卡面，左上角一块小芯片；权限被收回时整张变淡 */
.wl-pass { background: var(--surface); }
.wl-pass-chip { width: 26px; height: 20px; border-radius: 5px; border: 1px solid var(--border); background: var(--surface-2); }
.wl-pass.is-revoked { opacity: .55; }
.wl-pass.is-revoked .wl-card-name { text-decoration: line-through; text-decoration-thickness: 1px; }

/* 票券、会员卡、证件、纪念卡（4.644）：同一套浅色卡面 */
.wl-unit { font-size: var(--fs-14); font-weight: var(--fw-regular); color: var(--text-2); }
.wl-id-row { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); }
.wl-id-face { flex: none; width: 56px; height: 56px; border-radius: var(--r-md); object-fit: cover; display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text-2); font-size: var(--fs-20); }
.wl-id-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wl-ticket.is-revoked, .wl-pass.is-revoked { opacity: .55; }
/* 卡包的分类（4.644）：一排横着滑，选中一类只显示那一类，不一组组往下堆 */
.wl-tabs { display: flex; gap: var(--sp-2); overflow-x: auto; scrollbar-width: none; padding: 0 var(--sp-4) var(--sp-3); }
.wl-tabs::-webkit-scrollbar { display: none; }
.wl-tabs .chip { flex: none; }

/* 记忆：NPC 与小号那一组（4.649）。人数会越来越多，放进限高的滑动区域，组名吸顶（第 26 条） */
.mem-extra-scroll { max-height: 480px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
:where(.mem-extra-scroll) .list-title { position: sticky; top: 0; z-index: 1; background: var(--bg); }
/* 一个角色的记忆：排序（4.801）。发生日期 / 记下的时间，右边切先后 */
.mem-sort { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
.mem-sort > .segmented { flex: 1; }

/* 联机好友的在线状态（4.683）：一个圆点加几个字。私聊顶上那一行写在名字下面 */
.link-pres { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.link-pres-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--presence-off); }
.link-pres:where(.is-online) .link-pres-dot { background: var(--presence-on); }
.link-pres:where(.is-busy) .link-pres-dot { background: var(--presence-busy); }
.link-pres-tail { color: var(--text-3); }
.link-title { display: inline-flex; flex-direction: column; align-items: center; line-height: 1.2; max-width: 100%; }
.link-title > .link-pres { font-size: var(--fs-11); font-weight: var(--fw-normal); color: var(--text-3); }

/* 专注记录里那一行的「不算」（4.717） */
.fc-unleave { flex: none; margin-left: var(--sp-2); font-size: var(--fs-13); }

/* 元模式（4.817，apps/chat/pages/MetaChat.js）。回复按 Markdown 画，气泡比角色会话的宽一些；你发的原样保留换行 */
.meta-chat .meta-msg .msg-col { max-width: 86%; }
.meta-plain { white-space: pre-wrap; word-break: break-word; }
/* 气泡不让里面的长代码块撑宽（4.880，用户截图：窄窗口里整只气泡被撑到屏幕外，右边一截字看不到）。
   气泡是一列里的弹性子项，默认最小宽度等于内容最宽处，代码块一行不折就把它连同前后段落一起撑出去：最小宽度归零，代码块里的长行折行 */
.meta-bubble { min-width: 0; max-width: 100%; }
.meta-bubble .md pre { max-width: 100%; }
.meta-bubble .md pre code { white-space: pre-wrap; overflow-wrap: anywhere; }
.meta-bubble .md > :first-child { margin-top: 0; }
.meta-bubble .md > :last-child { margin-bottom: 0; }
/* 元模式里的表情包、照片、语音（4.825）：不套气泡，和角色会话里一样直接画 */
.meta-media { max-width: 72%; }
.meta-error { color: var(--danger); }
.meta-intro { margin: var(--sp-6) var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2);
  font-size: var(--fs-13); line-height: 1.7; color: var(--text-2); text-align: center; }
.meta-intro-title { font-size: var(--fs-15); font-weight: var(--fw-semi); color: var(--text); }
/* 美化编辑器第三步（4.838）：按住看原样的小按钮、面板头上两个按钮、搜到的那一项闪一下 */
.ed .gen-stage-wrap { position: relative; }
.ed-compare {
  position: absolute; left: var(--sp-2); top: var(--sp-2); z-index: 3;
  padding: 4px var(--sp-3); border: 0; border-radius: var(--r-full);
  background: var(--surface); color: var(--text-2); font-size: var(--fs-12); box-shadow: var(--shadow-1);
  touch-action: none;
}
.ed-head-btns { display: flex; align-items: center; gap: var(--sp-2); }
.ed [data-item].is-found { animation: ed-found 1.2s var(--ease-out); }
@keyframes ed-found { 0%, 40% { background: var(--surface-2); } 100% { background: transparent; } }
/* 预览切场景（4.839）：右上角三个小按钮，和左上角「按住看原样」一个样子 */
.ed-scenes {
  position: absolute; right: var(--sp-2); top: var(--sp-2); z-index: 3;
  display: flex; gap: 2px; padding: 2px; border-radius: var(--r-full);
  background: var(--surface); box-shadow: var(--shadow-1);
}
.ed-scene {
  padding: 3px var(--sp-2); border: 0; border-radius: var(--r-full);
  background: none; color: var(--text-2); font-size: var(--fs-12);
}
.ed-scene:where(.is-on) { background: var(--surface-2); color: var(--text); font-weight: var(--fw-semi); }
/* 美化首页的大小（4.844）：大是原样一行两个；中三个、小四个，字跟着小一号，小那一档不写「正在使用」那一行 */
.gf-grid:where([data-size="md"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4) var(--sp-3); }
.gf-grid:where([data-size="sm"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-2); }
:where(.gf-grid[data-size="md"]) .gf-tile-name { font-size: var(--fs-13); }
:where(.gf-grid[data-size="sm"]) .gf-tile-name { font-size: var(--fs-12); }
:where(.gf-grid[data-size="sm"]) .gf-tile-sub { display: none; }
:where(.gf-grid[data-size="sm"]) .gf-front { padding: var(--sp-1) var(--sp-2); }
.gf-items:where([data-size="md"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.gf-items:where([data-size="sm"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2); }
:where(.gf-items[data-size="md"]) .gf-item-name, :where(.gf-items[data-size="sm"]) .gf-item-name { font-size: var(--fs-12); }
:where(.gf-items[data-size="sm"]) .gf-item-sub { display: none; }

/* 收藏（4.853） */
.fav-thumb { flex: none; width: 36px; height: 36px; margin-right: var(--sp-2); border-radius: var(--r-sm); object-fit: cover; }
.fav-text { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; }
/* 状态栏（4.857）：可以折叠时整块都能点；展开后标题那一行留在最上面 */
.sb:where(.is-foldable) { cursor: pointer; }
:where(.sb:not(.is-folded)) .sb-brief { margin-bottom: var(--sp-1); font-weight: var(--fw-semi); }
/* 花园：状态栏方案的样式预览（4.858），里面是影子区域 */
.hb-sb-preview { margin-bottom: var(--sp-2); padding: var(--sp-2); border-radius: var(--r-md); background: var(--group-fill); }
/* 图片版本（4.861）：两列并排比较，当前显示的那一版描边 */
.imgver-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); margin: var(--sp-3) 0; }
.imgver-cell { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.imgver-pic { display: block; width: 100%; aspect-ratio: 1; padding: 0; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; background: var(--group-fill); }
.imgver-cell:where(.is-current) .imgver-pic { border: 2px solid var(--accent); }
.imgver-pic img { display: block; width: 100%; height: 100%; object-fit: cover; }
.imgver-foot { display: flex; align-items: center; gap: var(--sp-2); min-height: 32px; font-size: var(--fs-13); }
.imgver-no { flex: 1; min-width: 0; color: var(--text-2); }
.imgver-act { margin: var(--sp-2) 0; }
/* 背景音乐的歌名栏（4.862）：线下、长篇、小剧场共用。颜色跟着所在的那一页走（currentColor），线下换了主题也对得上 */
.bgm-bar { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; margin: var(--sp-1) var(--sp-3); padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
  border: 1px solid color-mix(in srgb, currentColor 16%, transparent); border-radius: var(--r-full); color: inherit; font-size: var(--fs-12); }
.bgm-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.bgm-name { min-width: 0; }
.bgm-sub { min-width: 0; opacity: .6; }
.bgm-btn { flex: none; display: grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-full); color: inherit; }


/* ---- 新版界面：规格统一（4.866，按设计审查） ----
   颜色、灰的档位在 tokens.css 新版那一段。这里只改几样控件的画法，旧版一条都不受影响。
   条件一律包进 :where()，特异度停在一个类名（第 18 条） */

/* 开关：关着时描边轨道配灰圆点，开着时深灰底配白圆点。悬浮球面板那一套仿 iOS，不动 */
:where(:root[data-ui="new"]) .switch:where(:not(.qb-panel .switch)) { background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--switch-off); }
:where(:root[data-ui="new"]) .switch-dot:where(:not(.qb-panel .switch-dot)) { background: var(--switch-off); box-shadow: none; }
:where(:root[data-ui="new"]) .switch:where(.is-on):where(:not(.qb-panel .switch)) { background: var(--accent); box-shadow: none; }
:where(:root[data-ui="new"] .switch.is-on) .switch-dot:where(:not(.qb-panel .switch-dot)) { background: var(--on-accent); }

/* 输入框：一圈看得见的细边，点进去换成深灰。提示字压到 4.5 : 1 */
:where(:root[data-ui="new"]) input { border-color: var(--border-2); }
:where(:root[data-ui="new"]) textarea { border-color: var(--border-2); }
:where(:root[data-ui="new"]) input:focus { border-color: var(--focus-ring); }
:where(:root[data-ui="new"]) textarea:focus { border-color: var(--focus-ring); }
:where(:root[data-ui="new"]) ::placeholder { color: var(--text-3); }

/* 灰块里面不再灰上叠灰：头像、次按钮用白 */
:where(:root[data-ui="new"] .list) .cat-face { --cat-bg: var(--on-group); }
:where(:root[data-ui="new"] .capsule) .cat-face { --cat-bg: var(--on-group); }
:where(:root[data-ui="new"] .list :not(:has(> .btn-primary)):not(:has(> .btn-outline))) > .btn-ghost { background: var(--on-group); }

/* 主屏挂件：平的灰块，不要投影；里面没有图的格子与头像用白 */
:where(:root[data-ui="new"]) .cell-widget { box-shadow: none; }
:where(:root[data-ui="new"] .cell-widget) .cat-full { --cat-bg: var(--on-group); }
:where(:root[data-ui="new"] .cell-widget) .cat-face { --cat-bg: var(--on-group); }

/* 用键盘或读屏切到一个能点的东西时，给一圈看得见的框。手指点按不出现 */
:where(:root[data-ui="new"]) button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
:where(:root[data-ui="new"]) .press:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* 副标题行高统一 */
:where(:root[data-ui="new"]) .li-sub { line-height: 1.4; }



/* 名字旁的切换（4.871）：灰色的向下小箭头 */
.acc-switch { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin-left: var(--sp-1);
  color: var(--text-3); vertical-align: middle; position: relative; }
.acc-switch::after { content: ''; position: absolute; inset: -6px; }
.ig-name-row { display: flex; align-items: center; gap: var(--sp-1); }
.acc-add { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: var(--text-2); box-shadow: inset 0 0 0 1px var(--border); }

/* 创作（4.873） */
.cr-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-2); }
.cr-cell { aspect-ratio: 1; border-radius: var(--r-md); background: var(--surface-2, var(--surface)) var(--cell-img, none) center / cover no-repeat; border: none; }
.cr-cell:where(.is-wait) { display: flex; align-items: center; justify-content: center; }
.cr-thumb { width: 44px; height: 44px; border-radius: var(--r-sm); background: var(--surface) var(--cell-img, none) center / cover no-repeat; }
.cr-big { display: block; width: 100%; border-radius: var(--r-md); }
.cr-prompt { white-space: pre-wrap; word-break: break-word; font-size: var(--fs-12); color: var(--text-2); background: var(--surface); padding: var(--sp-3); border-radius: var(--r-md); max-height: 320px; overflow-y: auto; overscroll-behavior: contain; }
.cr-fold { max-height: 360px; overflow-y: auto; overscroll-behavior: contain; }

/* 语音页里每个角色一行的音色 ID（4.891）。右边那一格不要把名字挤成一列 */
.li-right .voice-id-input { width: 10em; min-width: 0; }

/* 限高滚动框看得出是一个框（4.891，第 28 条第 4 项）：从前框没有边，装不下的那几条要在框里滑，看起来像只有三四条。
   新版给它一圈边线，底下再压一道内阴影，露出的半行像被框截住 */
:where(:root[data-ui="new"]) .list-cap { border: 1px solid var(--border-2); box-shadow: inset 0 -10px 8px -8px var(--border-2); }
.empty .btn-row { justify-content: center; }
/* 下滑搜索没打字时按类列出全部应用（4.893） */
.spot-cat { margin: 0 var(--sp-4) var(--sp-3); padding: var(--sp-3) 0; border-radius: var(--r-lg); background: var(--surface-2); }
.spot-cat .spot-apps { padding: 0 var(--sp-3); }
.spot-cat-title { display: flex; align-items: baseline; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-2); font-size: var(--fs-13); color: var(--text-2); }
.spot-cat-n { font-size: var(--fs-12); color: var(--text-3); }

/* 角色截下的聊天记录（4.904）：按 430 宽排好整体缩小，最高那一截以下裁掉，像一张长截图的预览 */
.shot-thumb {
  display: block; position: relative; overflow: hidden; padding: 0;
  width: var(--shot-w); height: var(--shot-h);
  border-radius: var(--r-md); border: 1px solid var(--border); background: var(--surface);
}
.shot-thumb-stage { position: absolute; left: 0; top: 0; width: 430px; transform: scale(var(--shot-k)); transform-origin: 0 0; pointer-events: none; }
.shot-thumb-stage .cardbox { border-radius: 0; box-shadow: none; }
.bubble-shot { display: block; }
.mo-shot { margin-top: var(--sp-2); }
.tp-shot.is-chat .tp-shot-note { text-align: left; }
/* 接口页「已保存的接口」（4.907）：按站点折叠，点开展开；每个站点最多露四条，多的在框里滑，框有底色看得出能滑（第 26、28 条） */
.api-site { margin: 0 var(--sp-4) var(--sp-2); border-radius: var(--r-md); background: var(--surface-2); overflow: hidden; }
.api-site-head { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-height: 48px; padding: 0 var(--sp-4); text-align: left; color: var(--text); }
.api-site-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.api-site-n { font-size: var(--fs-12); color: var(--text-3); }
.api-site-list { max-height: 248px; overflow-y: auto; overscroll-behavior: contain; background: var(--surface); }

/* 单聊：会话菜单最上面两人的头像，中间一条心电图样的线（4.921） */
:where(:root[data-ui="new"]) .duo {
  margin: var(--sp-3) var(--sp-4) 0; padding: var(--sp-5) var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg); background: var(--surface-2);
}
:where(:root[data-ui="new"]) .duo-row { display: grid; grid-template-columns: 92px 1fr 92px; align-items: start; }
:where(:root[data-ui="new"]) .duo-person { display: flex; flex-direction: column; align-items: center; min-width: 0; }
:where(:root[data-ui="new"]) .duo-face { position: relative; padding: 0; border: 0; background: none; border-radius: var(--r-full); }
:where(:root[data-ui="new"]) .duo-face .avatar { box-shadow: 0 0 0 3px var(--surface), var(--shadow-2); }
:where(:root[data-ui="new"]) .duo-edit {
  position: absolute; right: -1px; bottom: -1px; width: 20px; height: 20px; border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--text-2); box-shadow: 0 0 0 1px var(--border-2), var(--shadow-1);
}
:where(:root[data-ui="new"]) .duo-name {
  max-width: 100%; margin-top: var(--sp-3); font-family: var(--font-display); font-size: var(--fs-15);
  font-weight: var(--fw-medium); letter-spacing: .06em; color: var(--text);
}
:where(:root[data-ui="new"]) .duo-reset { margin-top: 2px; padding: 0; border: 0; background: none; font-size: var(--fs-11); color: var(--text-3); letter-spacing: .04em; }
:where(:root[data-ui="new"]) .duo-mid { display: flex; flex-direction: column; align-items: center; min-width: 0; padding-top: 16px; }
:where(:root[data-ui="new"]) .duo-line { position: relative; width: 100%; height: 40px;
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--text) 22%, var(--text) 78%, transparent); mask-image: linear-gradient(90deg, transparent, var(--text) 22%, var(--text) 78%, transparent); }
:where(:root[data-ui="new"]) .duo-wave { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
:where(:root[data-ui="new"]) .duo-wave path { fill: none; stroke: var(--text-3); stroke-opacity: .45; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
:where(:root[data-ui="new"]) .duo-wave.is-glow path { stroke: var(--text); stroke-opacity: 1; stroke-width: 1.6; }
:where(:root[data-ui="new"]) .duo-glow {
  position: absolute; inset: 0;
  -webkit-mask-image: linear-gradient(90deg, transparent 42%, var(--text) 50%, transparent 58%); mask-image: linear-gradient(90deg, transparent 42%, var(--text) 50%, transparent 58%);
  -webkit-mask-size: 300% 100%; mask-size: 300% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  animation: duo-sweep 2.8s linear infinite;
}
@keyframes duo-sweep { from { -webkit-mask-position: 100% 0; mask-position: 100% 0; } to { -webkit-mask-position: 0 0; mask-position: 0 0; } }
@media (prefers-reduced-motion: reduce) { :where(:root[data-ui="new"]) .duo-glow { animation: none; -webkit-mask-position: 50% 0; mask-position: 50% 0; } }
:where(:root[data-ui="new"]) .duo-days { margin-top: var(--sp-2); font-family: var(--font-display); font-size: var(--fs-11); letter-spacing: .2em; color: var(--text-3); white-space: nowrap; }
:where(:root[data-ui="new"]) .duo-days b { font-size: var(--fs-13); font-weight: var(--fw-medium); color: var(--text-2); letter-spacing: .04em; padding: 0 .3em; }
/* 「头像」那一格：点了在这一排上面展开卡片（4.921） */
:where(:root[data-ui="new"]) .menu-tile:where(.is-on) { background: var(--surface-3); }
:where(:root[data-ui="new"]) .duo-fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-slow) var(--ease-out); }
:where(:root[data-ui="new"]) .duo-fold.is-open { grid-template-rows: 1fr; }
:where(:root[data-ui="new"]) .duo-fold-in { min-height: 0; overflow: hidden; opacity: 0; transition: opacity var(--dur-slow) var(--ease-out); }
:where(:root[data-ui="new"]) .duo-fold.is-open .duo-fold-in { opacity: 1; }

/* 美化编辑器「预览消息」（4.953） */
.stage-kinds { padding: var(--sp-2) 0; }
.stage-row { display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); }
.stage-row-head { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-2); }
.stage-row-kind { font: inherit; font-size: var(--fs-14); padding: var(--sp-1) var(--sp-2); border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.stage-row-btns { display: flex; gap: var(--sp-1); color: var(--text-2); }
.stage-row-btns button { width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; color: inherit; }
.stage-row-btns button:disabled { opacity: 0.3; }

/* 气泡外面那一份译文（4.958）。默认不显示，美化选「气泡外」时放出来（契约里的 .ph-trans-out），气泡里那一份随之藏起 */
.bubble-trans-out {
  display: none; align-self: flex-start; max-width: 100%;
  margin-top: var(--sp-1); padding: 6px var(--sp-3); border-radius: var(--r-md);
  background: var(--group-fill); color: var(--text-2);
  font-size: var(--fs-13); line-height: 1.55; white-space: pre-wrap; word-break: break-word; cursor: pointer;
}
:where(.msg.is-mine) .bubble-trans-out { align-self: flex-end; }
