/* ============================================================
   主题：青提玻璃感（grape glass）
   ------------------------------------------------------------
   为什么把变量名保留成原来那套：整套样式表有 1800 行、几百处引用
   var(--bg-2) 之类。重命名变量等于要改几百处，改漏一处就白屏。
   所以做法是——**变量名不动，往里灌新颜色**。

   施工卡里写过「不要在现有变量上叠补丁」，那条针对的是「往夜灯配色上
   再糊一层主题切换」。这里不是叠补丁：夜灯那套色值已经整体退役，
   下面是青提玻璃的原生色板，旧名只是别名。

   浅色系最容易出的两个问题，这里都躲开了：
     · 浅底浅字 → --text 用偏墨绿的深灰，对比度够；
     · 玻璃面板叠玻璃面板 → 每层都有 border + 内高光，边界不糊。
   ============================================================ */
:root{
  /* ---- 白玻璃原生色板（2026-09-17 第二轮定调）----
     用户原话：「桌面不要米白色的背景，目前只有设置页需要【织物图】类似
     的颜，其他默认白色」「其次没有光，没有透亮感」。
     所以底色从米白 #F7F2EA 整体抬到**纯白**，米白只保留给设置页那一张
     织物纸（--g-fabric*）。字色 / 焦糖主色不动 —— 用户只否掉了背景，
     没否掉暖棕这一套。 */
  --g-accent:#B08A5E;          /* 焦糖：主色（按钮/选中态） */
  --g-accent-deep:#8A6844;     /* 压过一层的棕，用于文字态 */
  --g-accent-soft:#EAD9C2;     /* 浅驼 */
  --g-accent-pale:#F7F2EA;     /* 浅驼卡底（原来是米白底，现在只当浅色块用） */
  /* 压在主色块上的前景色（音乐卡那颗播放键）。
     浅色主题的主色是中等明度的焦糖，白图标读得清；
     夜灯主题的主色是**亮**薄荷绿，再压白色就糊了，得换成深色。 */
  --on-accent:#FFFFFF;
  /* 桌面上「不加面板的文字」的光晕（见 .w-hdr-* / .w-app-name 那条 text-shadow）。
     浅色主题给白晕，把深色字从任何底上托起来；
     深色主题必须换成一圈淡黑影 —— 否则浅色字 + 白晕＝整块在发光
     （用户第六轮：「开了夜间模式后这里全是糊的」）。
     这一支是**字面值**，不是 var() 套 var()，所以主题块覆盖它就够，
     不会踩「自定义属性在声明处冻结」那个坑。 */
  --ink-halo:0 0 1px rgba(255,255,255,1),0 0 4px rgba(255,255,255,.9),0 1px 9px rgba(255,255,255,.6);

  --g-ink:#43382C;             /* 暖深棕：主文字 */
  --g-ink-2:#8A7A67;           /* 次要文字 */
  --g-ink-3:#B4A693;           /* 最弱的文字 */

  --g-base:#FFFFFF;            /* 纯白底（原来米白 #F7F2EA） */
  --g-base-2:#FBFBFD;
  --g-base-3:#F1F3F7;

  /* ---- 玻璃 ----
     **白底上的玻璃不能靠填色被看见**（白叠白＝什么都没有）。所以下面这四件
     缺一不可，这也是「有没有透亮感」的全部来源：
       1. --g-ring   一圈极淡冷灰细线 —— 唯一能勾出玻璃外轮廓的东西
       2. --g-inset  内高光 —— 玻璃有厚度，顶上是亮的、底下是薄的
       3. --g-spec   镜面反光 —— 弧面才有的左上一道斜光
       4. 投影       把玻璃从白底上「抬」起来
     fills（--g-glass*）反而要更淡：填得越实，越像一块塑料板。

     2026-09-17 第三轮（用户：「还是不够亮」「不用蓝色」）：
     填充整体提亮两档，并且**去蓝** —— 原来那支 rgba(245,248,254) 是冷蓝灰，
     叠在白底上把整屏拉灰了。现在填充接近纯白，靠 ring + 投影定形；
     冷灰只留在 ring 和分割线里，而且是**中性偏冷**，不是蓝。
     分割线尤其别给蓝：蓝线在白底上比灰线显眼得多，一显眼就是「加了蓝」。
     saturate 也从 170% 降到 120% —— 高饱和会把底下那一点点冷调放大成蓝。 */
  --g-glass:rgba(253,254,255,.50);       /* 玻璃面板 */
  --g-glass-2:rgba(253,254,255,.72);     /* 压在上面的玻璃，更实一点 */
  --g-glass-3:rgba(255,255,255,.90);     /* 输入框 / 卡片内页 */
  --g-glass-edge:rgba(255,255,255,1);    /* 玻璃的亮边（白底上要全白才看得见） */
  --g-glass-line:rgba(126,136,156,.16);  /* 冷灰分割线（中性偏冷，别给蓝） */
  --g-glass-shadow:0 10px 26px rgba(120,132,156,.13),0 2px 5px rgba(120,132,156,.07);
  --g-glass-blur:blur(26px) saturate(120%);
  --g-inset:
    inset 0 1.5px 1px rgba(255,255,255,1),
    inset 0 -16px 22px -18px rgba(255,255,255,.95),
    inset 0 -1px 2px rgba(150,162,186,.10);
  --g-ring:0 0 0 1px rgba(122,134,158,.15);
  --g-spec:radial-gradient(130% 78% at 16% 4%,rgba(255,255,255,1) 0%,rgba(255,255,255,0) 64%);
  /* ---- 透镜层：这块玻璃「有没有厚度」全靠它 ----
     一块真玻璃在光下是**上亮下暗**的：上半截迎着光，下半截背光、
     会把身后的东西压暗一点。平涂一个色是出不来这个的 ——
     那正是用户说的「没有玻璃感，有点很实」（第四轮反馈）。
     中间那 40%~56% 故意留成完全透明，让「迎光面」和「背光面」
     之间有一道明确的分界，那道光带就是玻璃的弧面转折。
     色相走中性灰，不要蓝：第四轮刚因为蓝色被返工过。

     **这两支不抽中转变量**（不写 `--g-lens-bottom:...` 再在 `--g-lens` 里
     引它）：自定义属性里的 var() 在声明处解析，`:root` 引了就等于把颜色
     焊死在根上，主题块再覆盖 `--g-lens-bottom` 也传导不进来 ——
     本项目已经为这个坑返工过两次。要换色的主题**整支 --g-lens 重写一遍**。 */
  --g-lens:linear-gradient(178deg,
    rgba(255,255,255,.58) 0%,
    rgba(255,255,255,.16) 34%,
    rgba(255,255,255,0) 54%,
    rgba(228,234,244,.30) 100%);

  /* ---- 图标玻璃方块（.w-app-ic / .dt-dock-ic 共用那一块）----
     为什么要单独抽一组：这套方块是**唯一一块「浅色打光」的材质** ——
     它靠的是「近纯白的面 + 一片白高光」，这些色值没法从 --g-glass*
     里推出来（那组是中性玻璃，没有方向）。一开始写死在规则里，
     结果夜灯主题下三块方块变成三个白灯泡、图标还隐形了（踩过）。

     2026-09-17 第五轮（用户：「不管我换什么颜色的壁纸，都可以直接透出壁纸
     的样子的那种，所以要透明，要亮」）：
     这一组整体压到几乎全透明（a/b/c/d 都 ≤ .30）。
     上一版为了在白底上「看得见」把 alpha 堆到 .84，代价是这排图标
     在**任何**别的底色上都变成白瓷砖 —— 而用户要的是玻璃，不是瓷砖。
     第六轮又翻了半页：用户「不要每个app单独加光，而且还是有黑色的阴影」——
     glare / 中间那汪白 / 两层投影 / 线条上的白晕**全部拆掉**。
     拆完发现浅色主题下图标整个不见了：白底上叠透明的白，等于没有。
     所以填充不能再走「白色 + alpha」，改成**带色调的玻璃**
     （冷灰蓝 rgba(212~240,222~245,240~253)，alpha .40~.62）：
     压在纯白上能看见形状（约 15~18 个亮度单位的差），
     压在壁纸上仍然透得出来（alpha 只有一半上下），
     而深色主题下它比原来的「白 + alpha」更亮 —— 夜灯那版反而更好看了。
     **不要再往这里加任何光或影子**，那正是这一版被否掉的东西。 */
  --tk-a:rgba(240,245,253,.62);        /* 迎光面（上）*/
  --tk-b:rgba(226,233,246,.48);
  --tk-c:rgba(212,222,240,.40);        /* 背光面（下）*/
  --tk-d:rgba(230,237,249,.52);
  --tk-line:rgba(255,255,255,.66);     /* 亮边 —— 玻璃唯一的「轮廓」 */
  --tk-glare:rgba(255,255,255,.85);    /* 左上那团镜头光晕 */
  --tk-refract:rgba(198,220,255,.22);  /* 下缘贴边那一丝冷调（很淡，且只在下缘） */
  /* 开关轨道：凹进去的那道槽。必须比面板本身**暗一档**才有「槽」的感觉 ——
     拿 --g-glass-3（接近纯白）去画，槽就看不见了，开关会像一颗浮在空中的糖。 */
  --mode-track:rgba(224,230,241,.58);
  --mode-track-inset:rgba(116,128,152,.24);
  --tk-shadow:
    0 8px 20px rgba(46,56,80,.20),
    0 2px 5px rgba(46,56,80,.12),
    0 18px 30px -16px rgba(46,56,80,.32);
  /* 注意：图标线条**不在这里抽变量**，规则里直接写 color:var(--g-ink)。
     抽成 `--tk-ink:var(--g-ink)` 会踩本项目那个老坑 —— 自定义属性里的
     var() 是在**声明它的元素**（:root）上解析的，等于在这里就把颜色
     固化成了浅色主文字；夜灯主题在 #phone 上覆盖 --g-ink 传导不进来。 */

  /* ---- 设置页的织物纸 ----
     整部手机只有设置页不是纯白：一张米白偏灰的亚麻布（用户的参考图）。
     纹理由 style.css 底部那段 data-URI 噪声 + 经纬细线叠出来，
     色值只在这里出现一次。 */
  --g-fabric:#F7F5F1;
  --g-fabric-2:#F1EEE9;

  /* ---- 朋友圈默认封面（还没设壁纸时的那片底）----
     三档由深到浅的**雾霾蓝灰**：自己的名字是白字，压在上面看得清，
     又不会抢正文的戏。第一版是蓝→浅绿的渐变，用户原话
     「朋友圈上面的那个默认背景换一个颜色，现在这个颜色太丑了」。
     **这三个色是唯一出处** —— page-moments.js 的 WALL_FALLBACK 也是
     引用它们（内联样式里同样能用 var()），别在 JS 里另抄一份色值。 */
  --mo-wall-1:#6F7C99;
  --mo-wall-2:#A8B2C6;
  --mo-wall-3:#E7EAEE;

  /* ---- 语义层：页面里几个「必须是一整块实底」的地方 ----
     注意 --bg 是**不透明**的青提底色（子页面的底座靠它挡桌面），
     透明的只有桌面那一页。所以「输入框内页 / 吸顶头部 / 全屏搜索」
     这类要压住背后内容的表面，得单独有一支更实的色。 */
  --surface:rgba(255,255,255,.78);        /* 输入框、卡片内页 */
  /* 吸顶头部 / 全屏面板的实底 —— 跟随底部主色（现在是白），
     原来写死 #F1F9F2 是上一代青提绿遗留，白底上会漏出一层绿。 */
  --surface-solid:#FFFFFF;
  --scrim:rgba(58,66,84,.26);             /* 遮罩。浅色主题不能用深黑，会脏 */

  /* ---- 旧变量名 → 白玻璃（别名，勿单独改） ---- */
  --bg:var(--g-base);
  --bg-2:var(--g-glass);
  --bg-3:var(--g-base-3);
  --paper:var(--g-glass-3);
  --amber:var(--g-accent-deep);      /* 原来是小标题的琥珀色，现在是焦糖棕 */
  --coral:#D9736B;                   /* 危险色要能在浅底上看清，压暗了 */
  --mist:#5C86A8;
  --wood:#7A5C4A;
  --gold:#B9913F;
  --text:var(--g-ink);
  --text-dim:var(--g-ink-2);
  --text-faint:var(--g-ink-3);
  --line:var(--g-glass-line);

  --ff:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  --ff-serif:Georgia,"Songti SC","SimSun",serif;
  --ease:cubic-bezier(.22,.61,.36,1);
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}

/* 别名必须在 #phone 上**再定义一遍**。
   CSS 变量的 var() 是在「声明它的元素」上解析的 —— :root 上的
   `--bg: var(--g-base)` 在根上就固化成浅色了，往下继承的都是固化值；
   外观 App 在 #phone 上覆盖 --g-base，根本传导不到 --bg 里去
   （实测：同一个 .page 上 --g-base 已是深色、--bg 还是浅色）。
   在 #phone 上重定义别名后，解析发生在 #phone 上，
   主题覆盖 --g-base 就能一路带过去了。 */
#phone{
  --bg:var(--g-base);
  --bg-2:var(--g-glass);
  --bg-3:var(--g-base-3);
  --paper:var(--g-glass-3);
  --amber:var(--g-accent-deep);
  --text:var(--g-ink);
  --text-dim:var(--g-ink-2);
  --text-faint:var(--g-ink-3);
  --line:var(--g-glass-line);
}

html,body{margin:0;padding:0;height:100%;overscroll-behavior:none;}

body{
  background:#FFFFFF;
  font-family:var(--ff);
  color:var(--text);
  display:flex;
  justify-content:center;
}

/* 光晕底：白底 + 三点布光。
   固定在 #phone 后面，不跟着页面滚动 —— 否则翻页时背景会「漂」。
   只动 opacity/transform 的那几条动画走 CSS，其余全静态。

   **这一层是「有没有光」的全部来源。** 上一版是在米白上再叠米白，
   底和光同一个色系，叠出来只是一块更黄的板子，读不出「亮」。

   打光方式：**先把整屏照白，再只在四角描一点色**。
     亮度核心 → 上方正中一团白光，这是「够不够亮」的全部来源
     冷调     → 只贴左上角一小片，很淡（--ambient-c1）
     暖调     → 只贴右下角一小片，比冷调更淡
     中间     → 留纯白，不叠任何颜色

   2026-09-17 第四轮（用户：「目前没有玻璃感，有点很实的感觉」）：
   这一层还有一个更关键的职责 —— **给玻璃提供「可透的东西」**。
   上一版把底打得几乎是均匀白，玻璃底下没有明暗差，
   backdrop-filter 再怎么 blur 也是一片白，所以整块读起来是实心的。
   现在补上最后一层「**中心亮、四周收一层极浅雾**」的暗角：
   中心到四角大约差 10 个亮度单位（#FFFFFF → #F4F6F9）。
   这点差别单看几乎察觉不到，但它穿过玻璃之后会变成一条明确的明暗渐变 ——
   玻璃的「透」就是这么被读出来的。
   雾用**中性冷灰**，不是蓝（#F4F6F9 的 B−R 只有 5）。 */
.ambient{
  position:absolute;
  inset:0;
  z-index:0;
  overflow:hidden;
  pointer-events:none;
  background:
    /* ① 亮度核心：上方正中一大团白光 */
    radial-gradient(94% 54% at 50% 2%,#FFFFFF 0%,rgba(255,255,255,0) 80%),
    /* ② 冷调：只贴左上角，且**只到 B−R≈8** ——
       第四轮把这里从 #EEF5FF 再降一档（原来角上测出来 B−R=11，
       用户已经因为蓝返工过一次，边缘这点冷调也得收着给） */
    radial-gradient(62% 38% at -8% -12%,#F3F6FB 0%,rgba(243,246,251,0) 68%),
    /* ③ 暖调：只贴右下角，比冷调更淡 */
    radial-gradient(64% 42% at 108% 112%,#FFF9F4 0%,rgba(255,249,244,0) 66%),
    /* ④ 暗角：整屏的「体积感」来源，也是玻璃能显形的前提 */
    radial-gradient(152% 112% at 50% 24%,#FFFFFF 0%,#FDFEFF 44%,#F7F9FC 76%,#F4F6F9 100%);
}
.ambient::before,
.ambient::after,
.ambient .ambient-3{
  content:"";
  position:absolute;
  border-radius:50%;
  filter:blur(96px);
}
.ambient::before{width:420px;height:420px;background:#F0F5FC;top:-190px;left:-190px;opacity:.45;}
.ambient::after{width:400px;height:400px;background:#FFF6EC;bottom:-210px;right:-210px;opacity:.40;}
/* 第三团只负责在横向滚动时补一点冷调，别让它变成一片蓝 */
.ambient .ambient-3{
  width:320px;height:320px;background:#FFFFFF;top:18%;left:-170px;opacity:.55;
}

#phone{
  position:relative;
  width:100%;
  max-width:480px;
  height:100vh;     /* 兜底：不认 dvh 的老浏览器没这行高度会塌成 auto */
  height:100dvh;    /* 手机地址栏伸缩时跟着走（动态视口） */
  background:transparent;   /* 底色交给 .ambient，玻璃才有东西可透 */
  display:flex;
  flex-direction:column;
  overflow:hidden;
}

#statusbar{
  /* **浮在页面之上，不占布局** —— 用户在朋友圈截图里看到状态栏那条白带，
     要求「所有的屏幕的显示都改成透明底」。状态栏一透明，后面得能看见
     **当前页面自己的顶**（朋友圈就是封面），所以它不能再占一条 32px 的位置，
     否则页面内容永远从它下面开始，封面顶不到屏幕最上边。
     代价：所有页面内容会往上移 32px，由 .page-inner 的 padding-top 补回来。 */
  position:absolute;
  top:0;left:0;right:0;
  padding:calc(env(safe-area-inset-top) + 8px) 24px 0;
  height:calc(env(safe-area-inset-top) + 32px);
  display:flex;
  align-items:center;
  justify-content:space-between;
  font-size:12px;
  letter-spacing:.3px;
  color:var(--text-dim);
  /* 这里原来还有一条 position:relative —— 它会把上面那条 absolute 盖掉
     （同一条规则里后者胜出，改的时候踩过一次：computed 还是 relative）。 */
  z-index:60;
}

#stack{
  position:relative;
  flex:1;
  overflow:hidden;
}

.page{
  position:absolute;
  inset:0;
  display:flex;
  flex-direction:column;
  /* 子页面必须有不透明底座。
     桌面的「玻璃要透」是靠 .page[data-page="home"] 单独透明做到的 ——
     桌面底下是 .ambient 极光，透出来好看。
     但子页面底下**不是极光，是桌面**（home 是 #stack 里 z-index 1 的兄弟
     节点，页面上叠时它只是被推左、并没有消失）。
     这里一旦写 transparent，桌面上的网格组件就会从页面里透出来，
     和页面内容叠字（「还没有角色」压着「收藏夹」）。
     所以：底座给 --bg（现在是纯白），玻璃感交给页面内部的卡片和面板。 */
  background:var(--bg);
  overflow-y:auto;
  overflow-x:hidden;
  transform:translateX(100%);
  transition:transform .3s var(--ease);
  will-change:transform;
  z-index:10;
  --shift:-11%;
}
.page.is-active{transform:translateX(0);}
.page.is-behind{transform:translateX(var(--shift));}
.page.is-dragging{transition:none;}

/* 主屏＝桌面（page-desktop）。它是 4 屏横向滑动的网格，
   纵向滚动和横向翻页都归它自己管，壳子不插手。
   background 必须显式透明：它是唯一「底下是光晕」的页面，
   玻璃质感全靠这里透出来的底色（别的页面底下是它，所以不能透）。 */
.page[data-page="home"]{
  padding:0;
  z-index:1;
  overflow:hidden;
  background:transparent;
}

/* ============================================================
   设置页专属：一张亚麻织物纸
   ------------------------------------------------------------
   用户（2026-09-17 第二轮）：「桌面不要米白色的背景，目前只有设置页
   需要【织物图】类似的颜，其他默认白色」。
   所以**整部手机只有这一页不是纯白** —— 改这里之前先想一遍，
   别的页面要米白是有意为之还是抄漏了。

   织物的做法（零依赖，不引图片）：
     · 两层 repeating-linear-gradient 当经纬线（一横一竖，错开半个像素）
     · 一层 SVG feTurbulence 噪点当纱线颗粒
     · 最底一层从 #F8F6F3 到 #F4F1ED 的极浅渐变，给布一点「受光」
   三样叠在一起，凑近看是布的织纹，退开看是一张米白偏灰的纸。

   **噪点块必须够大（这里是 300px）**：一开始用 140px，
   在设置子页那种大片空白的区域上，能一眼看出 140px 的方格接缝 ——
   布变成瓷砖。stitchTiles='stitch' 只保证接缝不突变，不保证
   一张 140px 的纹理重複几百次看不出来。所以块放大、透明度压低，
   让它只当颗粒，不当图案。
   `background-attachment:local` 让布跟着内容滚 —— 写默认的 scroll 的话，
   列表滚动时纹理会「粘」在屏幕上不动，像贴纸而不像纸。

   选择器用前缀匹配，一次盖住设置这件事底下的**一整族**页面：
   settings / settings-mainapi / settings-mainapi-add / -edit。
   只写 [data-page="settings"] 的话，点进「主 API」里那一屏又会变回纯白，
   来回跳的时候像两套皮。 */
.page[data-page^="settings"]{
  background-color:var(--g-fabric);
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,.52) 0 .5px, rgba(255,255,255,0) .5px 2.6px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,.38) 0 .5px, rgba(255,255,255,0) .5px 2.6px),
    url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.86' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23f)' opacity='0.17'/%3E%3C/svg%3E"),
    linear-gradient(180deg,var(--g-fabric) 0%,var(--g-fabric-2) 100%);
  background-size:auto,auto,300px 300px,auto;
  background-attachment:local,local,local,local;
}

.app-body{
  flex:1;
  display:flex;
  flex-direction:column;
}

/* toast：页面正中、浅色玻璃底（用户：「放页面中心，不要黑色」——
   底部那条深色药丸是老样式，已废）。 */
#toast{
  position:absolute;
  left:50%;
  top:42%;
  max-width:78%;
  padding:10px 18px;
  border-radius:14px;
  background:color-mix(in srgb,var(--surface) 92%,transparent);
  border:1px solid var(--g-glass-line);
  color:var(--text);
  box-shadow:0 6px 22px rgba(60,45,25,.14);
  font-size:12.5px;
  line-height:1.5;
  text-align:center;
  opacity:0;
  transform:translate(-50%,-46%) scale(.97);
  transition:opacity .22s var(--ease),transform .22s var(--ease);
  pointer-events:none;
  z-index:200;
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
}
#toast.show{opacity:1;transform:translate(-50%,-50%) scale(1);}
#toast.err{border-color:rgba(192,122,107,.65);color:#A04A42;}
#toast.ok{border-color:rgba(111,155,106,.65);color:#4E7A48;}

.greet{margin:14px 0 26px;}
.greet-title{
  margin:0;
  font-family:var(--ff-serif);
  font-style:italic;
  font-size:24px;
  letter-spacing:.5px;
  color:var(--text);
}
.greet-sub{
  margin:7px 0 0;
  font-size:12px;
  color:var(--amber);
  letter-spacing:.4px;
}

.grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:24px 6px;
}

.icon{
  background:none;
  border:0;
  padding:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:8px;
  cursor:pointer;
  font-family:inherit;
}
.ic{
  position:relative;
  display:block;
  width:54px;
  height:54px;
  transition:transform .16s var(--ease);
}
.ic svg{display:block;width:54px;height:54px;}
/* 首页图标统一线性 SVG：fill/stroke/线宽在 CSS 统一接管，
   HTML 里只画形状 —— 想换粗细换颜色改这里一处就够 */
.ic svg, .dock-ic svg{
  fill:none;
  stroke:var(--text);
  stroke-width:1.6;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.dock-ic svg{display:block;width:30px;height:30px;stroke:var(--text-faint);}
.icon:active .ic{transform:scale(.9);}
.ic-name{
  font-size:11.5px;
  color:var(--text-dim);
  letter-spacing:.4px;
}

.dock{
  margin-top:auto;
  margin-bottom:6px;
  display:flex;
  align-items:center;
  justify-content:space-around;
  padding:11px 18px;
  background:var(--bg-2);
  border-radius:20px;
}
.dock-btn{
  background:none;
  border:0;
  padding:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:6px;
  cursor:pointer;
  font-family:inherit;
}
.dock-ic{
  display:block;
  width:30px;
  height:30px;
  transition:transform .16s var(--ease);
}
.dock-btn:active .dock-ic{transform:scale(.9);}
.dock-name{font-size:10.5px;color:var(--text-faint);}

.page-inner{
  /* padding-top = 状态栏的高度：状态栏现在是 absolute 浮着的（不占布局），
     所以由这里把位置补回来 —— 这样所有页面的视觉跟以前一模一样，
     而状态栏背后看见的正是「页面自己的顶」。 */
  padding:calc(env(safe-area-inset-top) + 32px) 22px calc(env(safe-area-inset-bottom) + 22px);
  display:flex;
  flex-direction:column;
  min-height:100%;
}
.app-head{
  display:flex;
  align-items:center;
  gap:12px;
  padding:16px 0 18px;
  position:sticky;
  /* 吸顶要让开状态栏那一条 —— 状态栏是 absolute 浮着的，
     写 top:0 的话页面一滚，顶栏就钻到状态栏底下跟时间电量叠字。
     这个值跟 .page-inner 的 padding-top 是同一个数，所以起滚时不跳。 */
  top:calc(env(safe-area-inset-top) + 32px);
  background:var(--surface-solid);
  z-index:5;
}
.back-btn{
  flex:none;
  width:34px;
  height:34px;
  border-radius:50%;
  border:0;
  background:var(--bg-2);
  color:var(--text-dim);
  font-size:16px;
  line-height:1;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  font-family:inherit;
}
.back-btn:active{background:var(--bg-3);}
.app-title{
  margin:0;
  font-family:var(--ff-serif);
  /* 之前是 italic —— 用户明确说过要避开斜体（可读性优先），
     而且这个衬线字体的斜体在小屏上发虚。改成正体。 */
  font-style:normal;
  font-size:19px;
  color:var(--text);
}
/* 头部右侧插槽：放「保存」「测试」这类页面级动作 */
.app-head-side{
  margin-left:auto;
  display:flex;
  align-items:center;
  gap:8px;
  flex:none;
}

.empty{
  flex:1;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:14px;
  padding:40px 8px;
  text-align:center;
}
.empty-paper{
  width:88px;
  height:88px;
  background:var(--paper);
  border-radius:3px;
  transform:rotate(-3deg);
  position:relative;
}
.empty-paper::after{
  content:"";
  position:absolute;
  right:0;
  bottom:0;
  border-style:solid;
  border-width:0 0 20px 20px;
  border-color:transparent transparent #D6C7AC transparent;
}
.empty-text{
  font-size:13px;
  color:var(--text-dim);
  line-height:1.7;
  margin:0;
}
.empty-hint{
  font-size:11.5px;
  color:var(--text-faint);
  margin:0;
}

/* 这里原来有一条 #edge-hint —— 「页面栈里有子页面」时在屏幕左缘亮一根
   3px 的琥珀色小条。用户明确要去掉（「然后去掉小绿条」，说了不止一次），
   元素（index.html）、样式、app.js 里的 toggle 一起删干净了。别再加回来。 */

@media (max-width:360px){
  .grid{gap:20px 4px;}
  .ic,.ic svg{width:48px;height:48px;}
}

/* ============================================================
   设置页组件（ROADMAP 2.1 / 2.2）
   夜灯手账：卡片是纸，分组标题是铅笔字，灰行是还没贴好的
   ============================================================ */

.head-act{
  border:0;
  background:var(--bg-2);
  color:var(--text-dim);
  font-family:inherit;
  font-size:12px;
  letter-spacing:.3px;
  padding:7px 13px;
  border-radius:12px;
  cursor:pointer;
  transition:background .16s var(--ease),transform .16s var(--ease);
}
.head-act:active{transform:scale(.94);}

/* 只有图形没有文字的动作按钮（名片夹的导入 / 导出）。
   收到 32 见方，两个图标并排也不会把标题挤走。 */
.head-act-icon{
  width:32px;height:32px;
  padding:0;
  display:inline-flex;align-items:center;justify-content:center;
}
.head-act-icon svg{display:block;}
.head-act:disabled{opacity:.4;cursor:default;}
.head-act-primary{background:var(--amber);color:#2A2118;font-weight:600;}

.set-group{margin:0 0 20px;}
.set-group-title{
  margin:0 0 8px 4px;
  font-size:11px;
  letter-spacing:1.4px;
  color:var(--text-faint);
  text-transform:uppercase;
}
.set-group-note{
  margin:8px 4px 0;
  font-size:11px;
  line-height:1.6;
  color:var(--text-faint);
}

.set-card{
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:14px;
  overflow:hidden;
}

.set-row{
  width:100%;
  display:flex;
  align-items:center;
  gap:10px;
  padding:13px 14px;
  background:none;
  border:0;
  border-bottom:1px solid var(--line);
  font-family:inherit;
  text-align:left;
  cursor:pointer;
  color:inherit;
}
.set-row:last-child{border-bottom:0;}
.set-row:active{background:var(--bg-3);}
.set-row.is-soon{cursor:default;opacity:.45;}
.set-row.is-soon:active{background:none;}
.set-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}
.set-row-label{font-size:calc(14px * var(--fs-scale, 1));color:var(--text);}
.set-row-hint{font-size:11px;color:var(--text-faint);line-height:1.5;}
.set-row-right{flex:none;display:flex;align-items:center;gap:7px;}
.set-row-value{font-size:12px;color:var(--text-dim);}
.set-row-arrow{font-size:17px;color:var(--text-faint);line-height:1;}

.set-badge{
  font-size:10.5px;
  padding:2px 7px;
  border-radius:8px;
  letter-spacing:.3px;
}
.set-badge-ok{background:rgba(163,184,153,.18);color:#B9CDAE;}
.set-badge-dim{background:rgba(185,175,201,.12);color:var(--text-faint);}

.set-field{padding:12px 14px;border-bottom:1px solid var(--line);}
.set-field:last-child{border-bottom:0;}
.set-field-row{display:flex;align-items:center;gap:12px;}
.set-field-main{flex:1;min-width:0;}
.set-label{
  display:block;
  font-size:12px;
  color:var(--text-dim);
  margin-bottom:7px;
  letter-spacing:.3px;
}
.set-field-row .set-label{margin-bottom:3px;}
.set-hint{
  margin:0 0 7px;
  font-size:10.5px;
  line-height:1.55;
  color:var(--text-faint);
}
.set-line{display:flex;align-items:center;gap:8px;}

.set-input{
  flex:1;
  min-width:0;
  width:100%;
  background:var(--surface);
  border:1px solid var(--g-glass-line);
  border-radius:10px;
  padding:10px 11px;
  color:var(--text);
  font-family:inherit;
  font-size:13.5px;
  outline:none;
  transition:border-color .16s var(--ease);
}
.set-input:focus{border-color:rgba(232,184,123,.55);}
.set-input::placeholder{color:var(--text-faint);}

.set-eye{
  flex:none;
  border:1px solid var(--line);
  background:var(--bg-3);
  color:var(--text-dim);
  font-family:inherit;
  font-size:11px;
  padding:8px 10px;
  border-radius:10px;
  cursor:pointer;
}

.set-switch{flex:none;position:relative;display:inline-block;width:44px;height:26px;}
.set-switch input{
  position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer;z-index:2;
}
.set-switch-track{
  position:absolute;inset:0;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:13px;
  transition:background .2s var(--ease),border-color .2s var(--ease);
}
.set-switch-track::after{
  content:"";
  position:absolute;
  top:3px;left:3px;
  width:18px;height:18px;
  border-radius:50%;
  background:var(--text-faint);
  transition:transform .2s var(--ease),background .2s var(--ease);
}
.set-switch input:checked + .set-switch-track{
  background:rgba(232,184,123,.22);
  border-color:rgba(232,184,123,.5);
}
.set-switch input:checked + .set-switch-track::after{
  transform:translateX(18px);
  background:var(--amber);
}

.btn-row{display:flex;gap:10px;padding:14px;}
.btn{
  flex:1;
  border:0;
  border-radius:12px;
  padding:12px 14px;
  font-family:inherit;
  font-size:13.5px;
  letter-spacing:.4px;
  cursor:pointer;
  transition:transform .16s var(--ease),opacity .16s;
}
.btn:active{transform:scale(.97);}
.btn:disabled{opacity:.45;cursor:default;}
.btn-primary{background:var(--amber);color:#2A2118;font-weight:600;}
.btn-ghost{background:var(--bg-3);color:var(--text-dim);}

.test-result{
  margin:12px 14px 0;
  padding:12px;
  border-radius:11px;
  background:var(--surface);
  border:1px solid var(--line);
}
.test-result.is-ok{border-color:rgba(163,184,153,.45);}
.test-result.is-err{border-color:rgba(244,162,156,.4);}
.test-result.is-loading{border-color:rgba(232,184,123,.4);}
.test-title{margin:0 0 8px;font-size:13px;color:var(--text);}
.is-ok .test-title{color:#B9CDAE;}
.is-err .test-title{color:var(--coral);}
.is-loading .test-title{color:var(--amber);}
.test-kv{display:flex;flex-direction:column;gap:4px;}
.test-line{display:flex;gap:10px;font-size:11.5px;line-height:1.5;}
.test-k{flex:none;width:56px;color:var(--text-faint);}
.test-v{flex:1;min-width:0;color:var(--text-dim);word-break:break-all;}
.test-reply{
  margin:9px 0 0;
  padding:8px 10px;
  border-left:2px solid var(--amber);
  background:rgba(232,184,123,.07);
  font-family:var(--ff-serif);
  font-size:12.5px;
  line-height:1.6;
  color:var(--text-dim);
  word-break:break-all;
}
.test-detail{
  margin:9px 0 0;
  font-size:11px;
  line-height:1.55;
  color:var(--text-faint);
  word-break:break-all;
  max-height:110px;
  overflow:auto;
}
.test-tip{margin:8px 0 0;font-size:11px;line-height:1.6;color:var(--text-faint);}
/* 拉取模型列表：结果盒 + 可点的模型名行 */
.model-pick{margin-top:8px;display:flex;flex-direction:column;gap:6px;}
.model-pick .set-row-label{font-size:12px;}

/* 生图「试一张」的结果区：加载/成功/失败共用一个壳，
   图本身按正方形封顶，圆角跟其他图一致 */
.imggen-out{margin-top:10px;}
.imggen-out .imggen-pic{
  margin-top:10px;
  width:100%;
  max-width:320px;
  aspect-ratio:1;
  border-radius:12px;
  background:#f2f2f4 center/cover no-repeat;
  border:1px solid var(--line, rgba(0,0,0,.06));
}
.imggen-out.is-loading .test-tip{animation:pulse-dim 1.4s ease-in-out infinite;}
@keyframes pulse-dim{0%,100%{opacity:.55;}50%{opacity:1;}}

/* 滑轨全部去掉（用户：「太丑了」）：小手机里滚动全靠手势，
   滚动条没有任何信息量 —— 隐藏但不影响滚动本身。 */
#phone, #phone *{
  scrollbar-width:none;           /* Firefox */
  -ms-overflow-style:none;        /* 老 Edge */
}
#phone::-webkit-scrollbar,
#phone *::-webkit-scrollbar{      /* Chromium / WebKit */
  width:0;height:0;display:none;
}

/* 输入框旁的小圆钮（拉取模型等）：32px，跟 set-input 同高傍着站 */
.set-mini-ic{
  flex:none;
  width:32px;height:32px;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--g-glass-line);
  background:var(--surface);
  color:var(--text-dim);
  border-radius:50%;
  cursor:pointer;
  transition:border-color .16s var(--ease),color .16s var(--ease);
}
.set-mini-ic:active{transform:scale(.92);}
.set-mini-ic:disabled{opacity:.45;}

/* 可收起的组（试一张 / 词条表单）：头部行 + 展开体。
   收起时 body 整个 display:none，箭头转 180°。 */
.imggen-fold .imggen-fold-head{
  width:100%;
  background:none;border:none;
  font-family:inherit;
  text-align:left;
  cursor:pointer;
  padding:13px 14px;
}
.imggen-fold .imggen-fold-arrow{
  float:right;
  color:var(--text-faint);
  transition:transform .2s var(--ease);
  display:inline-flex;
}
.imggen-fold.is-open .imggen-fold-arrow{transform:rotate(180deg);}
.imggen-fold .imggen-fold-body{display:none;padding:2px 14px 14px;}
.imggen-fold.is-open .imggen-fold-body{display:block;}

/* 类别下拉：跟 set-input 一个长相，高度略收 */
.set-select{
  width:100%;
  background:var(--surface);
  border:1px solid var(--g-glass-line);
  border-radius:10px;
  padding:9px 11px;
  color:var(--text);
  font-family:inherit;
  font-size:13.5px;
  outline:none;
  appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23999' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M6 8l4 4 4-4'/></svg>");
  background-repeat:no-repeat;
  background-position:right 10px center;
  background-size:14px;
}

.set-foot{
  margin:4px 4px 0;
  font-size:11px;
  line-height:1.7;
  color:var(--text-faint);
  text-align:center;
}
/* ============================================================
   数据与备份页（ROADMAP 2.5 / 2.6 / 2.7）补充样式
   ============================================================ */

/* 只读信息行：能看清，但不假装能点 */
.set-row.is-plain{cursor:default;}
.set-row.is-plain:active{background:none;}
.set-row.is-plain .set-row-label{color:var(--text-dim);}

.btn-danger{
  background:rgba(178,58,47,.18);
  color:var(--coral);
  border:1px solid rgba(178,58,47,.5);
}
.btn-danger.is-armed{
  background:#B23A2F;
  color:#F2E8DC;
  border-color:#B23A2F;
  font-weight:600;
}/* ============================================================
   聊天页样式（ROADMAP 3.2 聊天页 UI）
   ============================================================ */

/* 会话列表 */
.chat-list-wrap{margin:0 -22px 0;}
.chat-item{
  display:flex;align-items:center;gap:14px;
  padding:16px 22px;margin:0;
  background:none;border:0;
  border-bottom:1px solid var(--line);
  cursor:pointer;font-family:inherit;color:inherit;
}
.chat-item:active{background:var(--bg-2);}
.chat-item-main{flex:1;min-width:0;}
.chat-item-name{
  display:block;font-size:15px;
  margin-bottom:4px;color:var(--text);
}
.chat-item-meta{
  display:flex;align-items:center;gap:8px;
  font-size:12px;color:var(--text-faint);
}
.chat-item-time{flex:none;}
.chat-item-preview{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}

.chat-item-del{
  flex:none;width:32px;height:32px;
  border-radius:16px;background:var(--bg-3);
  border:0;margin-right:8px;
  color:var(--text-faint);font-size:13px;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;
}

/* 消息气泡 */
.msg-wrap{
  flex:1;overflow-y:auto;
  padding:16px 18px 8px;
  display:flex;flex-direction:column;gap:12px;
}
.msg-bubble{
  max-width:82%;display:flex;flex-direction:column;
  position:relative;word-break:break-word;
}
/* 角色的气泡：头像在左，引用条 / 正文 / 时间在右 */
.msg-assistant{flex-direction:row;align-items:flex-start;}
.msg-body{display:flex;flex-direction:column;min-width:0;}
.msg-user{align-self:flex-end;}
.msg-user .msg-text{
  background:var(--amber);color:#2A2118;
  border-radius:18px 3px 18px 18px;
}
.msg-assistant .msg-text{
  background:var(--paper);
  /* 原本写的是 color:var(--text)，而 --text 就是 #F2E8DC，和这张纸同一个颜色，
     所以角色的每句话都是浅字写在浅底上，等于隐身。 */
  color:#2A2118;
  border-radius:3px 18px 18px 18px;
}
.msg-text{
  padding:8px 12px 9px;
  /* 字号走变量：外观 App 里的「正文字号」改的就是它 */
  font-size:calc(14px * var(--fs-scale, 1));line-height:1.55;
  position:relative;
  box-shadow:0 1px 2px rgba(0,0,0,.08);
}
.msg-user .msg-text::after{
  content:'';position:absolute;top:0;right:-6px;
  border-style:solid;border-width:0 0 6px 6px;
  border-color:transparent transparent transparent var(--amber);
}
.msg-assistant .msg-text::after{
  content:'';position:absolute;top:0;left:-6px;
  border-style:solid;border-width:0 6px 6px 0;
  border-color:transparent var(--paper) transparent transparent;
}
.msg-time{
  font-size:10.5px;color:var(--text-faint);
  margin-top:4px;text-align:right;
  padding:0 4px;
}

/* 输入区域 */
.input-area{
  padding:12px 16px 20px;margin:0 0 -8px;
  background:var(--bg-2);
  border-top:1px solid var(--line);
  display:flex;align-items:flex-end;gap:8px;
}
.chat-input{
  flex:1;min-width:0;
  background:var(--surface);border:1px solid var(--g-glass-line);
  border-radius:16px;padding:10px 14px;
  color:var(--text);font-family:inherit;font-size:14px;
  line-height:20px;
  min-height:42px;      /* rows=1 时也要有个像样的高度，别被 autoGrow 算成 0 */
  resize:none;outline:none;max-height:120px;
}
.chat-input:focus{border-color:var(--amber);}
.send-btn{
  width:44px;height:44px;
  border-radius:50%;border:0;
  background:var(--amber);color:#2A2118;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;flex:none;
  transition:transform .12s var(--ease), background .2s var(--ease);
}
.send-btn:active{transform:scale(.94);}
/* 忙碌状态：爪印变淡呼吸，比单纯置灰更像「对方在打字」 */
.send-btn.is-busy{
  background:var(--bg-3);color:var(--text-faint);
  cursor:default;
  animation:paw-wait 1.15s ease-in-out infinite;
}
.send-btn.is-busy:active{transform:none;}
@keyframes paw-wait{0%,100%{opacity:.4}50%{opacity:.95}}

/* 加号面板（+）v0.2 — UI 微调 */
/* 加号按钮：输入区里的普通按钮。
   老版把它 position:absolute 到页面右下角，正好压在发送键上。 */
.plus-btn{
  width:40px;height:40px;flex:none;
  border-radius:50%;border:0;
  background:var(--bg-3);color:var(--text-dim);
  font-size:19px;line-height:1;font-family:inherit;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;
  transition:background .15s var(--ease), transform .12s var(--ease);
}
.plus-btn:active{transform:scale(.92);}

/* 面板：贴在输入区上方，靠 .is-open 控制显隐 */
.plus-panel{
  display:none;
  flex-wrap:wrap;
  gap:8px;
  padding:12px 16px;
  background:var(--bg-2);
  border-top:1px solid var(--line);
}
.plus-panel.is-open{display:flex;}

.plus-item{
  flex:1 1 20%;
  min-width:0;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:10px 4px;
  background:var(--bg-3);
  border:0;border-radius:12px;
  color:var(--text-dim);font-family:inherit;font-size:11.5px;
  cursor:pointer;
  transition:transform .12s var(--ease), background .15s var(--ease);
}
.plus-item:active{transform:scale(.95);background:var(--bg-2);}
.plus-item.is-soon{opacity:.45;cursor:default;}
.plus-item.is-soon:active{transform:none;background:var(--bg-3);}
/* 图标位统一成 22 见方，里面放线性 SVG。
   （原来是 emoji 文字，各系统渲染不一样，摆一排像拼的） */
.plus-ic{
  display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;
  font-size:17px;line-height:1;
}
.plus-ic svg{display:block;width:100%;height:100%;}
.plus-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;}

/* 图标改用 .plus-ic 文字字形。
   老版这里每个 data-id 都挂了 ::before 的 SVG，但 8 条里有 5 条用的是
   同一张对勾图，转账 / 拍一拍 / 生图 / 查岗 / 表情包 长得一模一样，反而看不出是什么。 */

/* 移动端适配 */
@media (max-width: 480px) {
  .plus-panel {
    gap: 6px;
    padding: 10px 12px;
  }
  .plus-item {
    padding: 8px 4px;
    font-size: 11px;
  }
}

/* 呼吸光动画（用于顶部头像） */
@keyframes heartbeat {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.03); opacity: 0.92; }
}

.nav-avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  margin: 0 8px;
  cursor: pointer;
  transition: transform .2s;
  animation: heartbeat 3s ease-in-out infinite;
}

.msg-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  margin-right: 8px;
  cursor: pointer;
  vertical-align: middle;
  flex: 0 0 32px;
  object-fit: cover;
  /* 注意：角色头像是「透明底 + 圆形」的 SVG —— 这里**不能**给底色，
     否则透明部分会透出一块方框（实测）。 */
}
/* user 头像占位（没设头像时显示首字） */
span.msg-avatar-initial{
  display:flex;align-items:center;justify-content:center;
  font-size:13px;color:#fff;background:linear-gradient(145deg,#c9b394,#a18561);
  cursor:default;
}
/* user 行：头像在右（row-reverse，margin 跟着换边） */
.msg-user{flex-direction:row-reverse;}
.msg-user .msg-avatar{margin-right:0;margin-left:8px;}

/* 顶部导航栏基础样式 */
.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  background: rgba(255,255,255,0.8);
  backdrop-filter: blur(4px);
  border-bottom: 1px solid rgba(214,199,172,0.3);
  z-index: 9;
}

.nav-back, .nav-action {
  background: transparent;
  border: none;
  font-size: 18px;
  color: #7A5C4A;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
  transition: all .15s;
}

.nav-back:hover, .nav-action:hover {
  background: #F2E8DC;
}

.nav-actions {
  display: flex;
  gap: 8px;
}
/* 搜索栏（内嵌展开） */
.search-bar-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 10px;
  border: 1px solid rgba(214, 199, 172, 0.3);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  z-index: 12;
}

.search-input {
  flex: 1;
  border: 1px solid #D6C7AC;
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 14px;
  outline: none;
  background: transparent;
  color: #333;
  transition: border-color .15s;
}

.search-input:focus {
  border-color: var(--amber, #E8B87B);
}

.search-close {
  background: transparent;
  border: none;
  font-size: 18px;
  color: #7A5C4A;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}

.search-close:hover {
  color: #333;
}
/* 搜索结果列表 */
.search-results {
  max-height: 300px;
  overflow-y: auto;
  margin-top: 8px;
  background: white;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  display: none;
}

.search-result-item {
  padding: 8px 12px;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: background .15s;
}

.search-result-item:hover {
  background: #f9f9f9;
}

.search-result-preview {
  flex: 1;
  font-size: 14px;
  color: #333;
  line-height: 1.4;
}

.search-result-preview mark {
  background: yellow;
  color: #000;
  padding: 0 2px;
  border-radius: 2px;
}

.search-result-meta {
  font-size: 12px;
  color: #888;
  white-space: nowrap;
}

.search-result-jump {
  background: #D6C7AC;
  color: #7A5C4A;
  border: none;
  border-radius: 4px;
  padding: 4px 8px;
  font-size: 12px;
  cursor: pointer;
  transition: all .15s;
}

.search-result-jump:hover {
  background: #C9BBA6;
}

.search-result-empty {
  padding: 12px;
  text-align: center;
  color: #888;
  font-size: 14px;
}
/* 转账弹窗 */
.transfer-dialog {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.15);
  z-index: 20;
  width: 80%;
  max-width: 300px;
}

.transfer-title {
  margin: 0 0 16px 0;
  font-size: 18px;
  color: #7A5C4A;
  text-align: center;
}

.transfer-label {
  display: block;
  margin: 12px 0 4px 0;
  font-size: 14px;
  color: #333;
}

.transfer-input, .transfer-textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #D6C7AC;
  border-radius: 6px;
  font-size: 14px;
  outline: none;
}

.transfer-input:focus, .transfer-textarea:focus {
  border-color: var(--amber, #E8B87B);
}

.transfer-btns {
  display: flex;
  gap: 8px;
  margin-top: 16px;
}

.transfer-btn {
  flex: 1;
  padding: 8px;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  transition: all .15s;
}

.transfer-cancel {
  background: #f0f0f0;
  color: #666;
}

.transfer-cancel:hover {
  background: #e0e0e0;
}

.transfer-confirm {
  background: #D6C7AC;
  color: #7A5C4A;
}

.transfer-confirm:hover {
  background: #C9BBA6;
}
/* 文件消息气泡 */
.msg-file {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: #f0f0f0;
  border-radius: 8px;
  border: 1px solid #d0d0d0;
  font-size: 14px;
  color: #333;
}

.msg-file-icon {
  width: 20px;
  height: 20px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%237A5C4A'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L16.5 7H13z'/%3E%3C/svg%3E") no-repeat center;
  background-size: contain;
}

.msg-file-name {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.msg-file-size {
  font-size: 12px;
  color: #888;
}
/* 图片消息气泡 */
.msg-image {
  display: inline-block;
  max-width: 60%;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.msg-image img {
  width: 100%;
  height: auto;
  display: block;
}
/* 日记消息气泡 */
.msg-diary {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  position: relative;
}

.msg-diary::before {
  content: '';
  position: absolute;
  left: -24px;
  top: 12px;
  width: 16px;
  height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%237A5C4A'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z'/%3E%3Cpath d='M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z'/%3E%3C/svg%3E") no-repeat center;
  background-size: contain;
}

.diary-input {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #D6C7AC;
  border-radius: 6px;
  font-size: 14px;
  outline: none;
  resize: none;
}

.diary-input:focus {
  border-color: var(--amber, #E8B87B);
}

.diary-btn {
  padding: 8px 12px;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  transition: all .15s;
}

.diary-now {
  background: #D6C7AC;
  color: #7A5C4A;
}

.diary-later {
  background: #F2E8DC;
  color: #333;
}

.diary-cancel {
  background: #f0f0f0;
  color: #666;
}

.diary-now:hover {
  background: #C9BBA6;
}

.diary-later:hover {
  background: #e0e0e0;
}

.diary-cancel:hover {
  background: #d0d0d0;
}





/* 发送键的置灰交给 .is-busy 的呼吸动画表达，这里只管光标 */
.send-btn:disabled{cursor:not-allowed;}

/* FAB 新建按钮 */
.fab-btn{
  position:fixed;bottom:92px;right:24px;
  width:52px;height:52px;border:0;
  border-radius:50%;
  background:var(--amber);color:#2A2118;
  font-size:24px;font-weight:600;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;box-shadow:0 4px 16px rgba(232,184,123,.3);
  z-index:10;
}/* 消息 meta 行：时间 + 动作（停止 / 重新生成） */
.msg-meta{
  display:flex;align-items:center;gap:10px;
  margin-top:4px;padding:0 4px;
}
.msg-meta .msg-time{margin:0;}
.msg-act{
  border:0;background:var(--bg-3);
  color:var(--text-dim);font-family:inherit;
  font-size:10.5px;padding:3px 9px;
  border-radius:9px;cursor:pointer;
}
.msg-act:active{transform:scale(.95);}

.msg-bubble.is-pending .msg-text{
  background:var(--bg-3);
  color:var(--text-dim);
  border-radius:3px 18px 18px 18px;
  min-width:56px;
}

/* 等回复的…… 呼吸点 */
.typing-dots{
  letter-spacing:2px;
  animation:blink 1.1s ease-in-out infinite;
}
@keyframes blink{0%,100%{opacity:.35}50%{opacity:1}}
/* ============================================================
   模块 D 补丁：聊天页交互 + 心声 / 手账本 / 拼贴墙 / 收藏夹
   这一批类名原来在 JS 里被用到，但 style.css 里一个都没定义，
   所以「长按菜单、多选条、引用条、附件气泡」即使 JS 修好也是裸 DOM。
   配色一律走 :root 里的夜灯变量，不再出现写死的 #f0f0f0。
   ============================================================ */

/* 底部整块：引用条 + 加号面板 + 输入行 */
.chat-foot{flex:none;display:flex;flex-direction:column;}

/* ------------------------- 多选条 ------------------------- */
.msg-select-bar{
  flex:none;align-items:center;gap:10px;
  padding:10px 16px;
  background:var(--bg-2);
  border-bottom:1px solid var(--line);
}
.msg-select-info{margin-right:auto;font-size:12.5px;color:var(--text-dim);}
.msg-select-act{
  border:0;background:var(--bg-3);color:var(--text-dim);
  font-family:inherit;font-size:12px;padding:5px 12px;
  border-radius:10px;cursor:pointer;
}
.msg-select-act:active{transform:scale(.95);}
.msg-select-act.is-danger{background:rgba(244,162,156,.18);color:var(--coral);}

/* --------------------- 选中态 / 引用条 --------------------- */
.msg-bubble.is-selected .msg-text{
  outline:1.5px solid var(--amber);
  outline-offset:2px;
}
.msg-quote{
  font-size:11.5px;line-height:1.45;
  color:var(--text-faint);
  border-left:2px solid var(--line);
  padding:2px 0 2px 8px;
  margin-bottom:6px;
  overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
}
.msg-quote-bar{
  align-items:center;gap:10px;
  padding:8px 16px;
  background:var(--bg-2);
  border-top:1px solid var(--line);
}
.msg-quote-text{
  flex:1;min-width:0;
  font-size:11.5px;color:var(--text-faint);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.msg-quote-x{
  flex:none;width:22px;height:22px;
  border:0;border-radius:50%;
  background:var(--bg-3);color:var(--text-dim);
  font-size:14px;line-height:1;font-family:inherit;
  cursor:pointer;
}

/* ------------------------ 附件气泡 ------------------------ */
.msg-attach{
  display:flex;align-items:center;gap:10px;
  padding:12px 14px;
  background:var(--paper);color:#2A2118;
  border-radius:14px;
  max-width:100%;
}
.msg-attach-ic{flex:none;font-size:18px;line-height:1;}
.msg-attach-main{min-width:0;display:flex;flex-direction:column;gap:2px;}
.msg-attach-name{
  font-size:13px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.msg-attach-size{font-size:11px;opacity:.7;}

/* ------------------------ 系统气泡 ------------------------ */
/* 拍一拍：微信那种居中灰字。跟系统消息一个量级，但更轻 ——
   没有底、没有边，就是一行小字；两个方向共用，颜色不区分
   （谁拍的写得很清楚，不用再靠颜色分）。 */
.msg-pat{
  align-self:center;
  max-width:88%;
  font-size:11px;
  letter-spacing:.02em;
  color:var(--g-ink-3);
  text-shadow:var(--ink-halo);
  padding:2px 0;
}
.msg-system{align-self:center;max-width:88%;}
.msg-system .msg-text{
  background:transparent;color:var(--text-faint);
  font-size:11.5px;text-align:center;
  box-shadow:none;padding:4px 10px;
}
.msg-system .msg-text::after{display:none;}

/* --------------------- 长按菜单（底部动作表） --------------------- */
.msg-menu-mask{
  position:absolute;inset:0;
  background:var(--scrim);
  z-index:70;
  display:none;
}
.msg-menu-mask.is-open{display:block;}
.msg-menu{
  position:absolute;left:0;right:0;bottom:0;
  z-index:71;
  display:none;flex-direction:column;
  padding:12px 14px calc(env(safe-area-inset-bottom) + 14px);
  background:var(--bg-2);
  border-top:1px solid var(--line);
  border-radius:18px 18px 0 0;
}
.msg-menu.is-open{display:flex;}
.msg-menu-list{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px;}
.msg-menu-item{
  flex:1 1 28%;
  padding:13px 6px;
  background:var(--bg-3);
  border:0;border-radius:12px;
  color:var(--text);font-family:inherit;font-size:13.5px;
  cursor:pointer;
}
.msg-menu-item:active{transform:scale(.97);}
.msg-menu-item.is-danger{color:var(--coral);}
.msg-menu-cancel{
  padding:13px 6px;
  background:transparent;border:0;
  border-top:1px solid var(--line);
  color:var(--text-dim);font-family:inherit;font-size:13.5px;
  cursor:pointer;
}

/* ------------------------- 收藏夹 ------------------------- */
.fav-list{display:flex;flex-direction:column;gap:12px;}
.fav-item{
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:14px;
  padding:12px 14px;
}
.fav-text{
  font-size:13.5px;line-height:1.55;color:var(--text);
  white-space:pre-wrap;word-break:break-word;
}
.fav-meta{display:flex;align-items:center;gap:8px;margin-top:10px;}
.fav-src{margin-right:auto;font-size:11px;color:var(--text-faint);}
.fav-btn{
  border:0;background:var(--bg-3);color:var(--text-dim);
  font-family:inherit;font-size:11.5px;padding:5px 11px;
  border-radius:9px;cursor:pointer;
}
.fav-btn:active{transform:scale(.95);}
.fav-btn.is-danger{color:var(--coral);}

/* --------------------- 心声（模块 E 占位） --------------------- */
.heartbeat-feed{display:flex;flex-direction:column;gap:12px;}
.heartbeat-item{
  padding:14px 16px;
  background:var(--bg-2);
  border-left:2px solid var(--mist);
  border-radius:0 12px 12px 0;
}
.heartbeat-text{
  margin:0;font-family:var(--ff-serif);
  font-size:13.5px;line-height:1.6;color:var(--text);
}
.heartbeat-time{margin:8px 0 0;font-size:11px;color:var(--text-faint);}

/* ------------------------- 手账本 ------------------------- */
.diary-feed{display:flex;flex-direction:column;gap:16px;}
.diary-item{display:flex;gap:12px;align-items:flex-start;}
.diary-time{
  flex:none;width:56px;padding-top:3px;
  font-size:11px;color:var(--text-faint);text-align:right;
}
.diary-content{flex:1;min-width:0;}
.diary-text{
  margin:0;font-family:var(--ff-serif);
  font-size:calc(13.5px * var(--fs-scale, 1));line-height:1.65;color:var(--text);
  white-space:pre-wrap;word-break:break-word;
}
.diary-text.is-pending{color:var(--text-faint);}
.diary-remind{
  margin-top:8px;
  border:0;background:var(--bg-3);color:var(--text-dim);
  font-family:inherit;font-size:11.5px;padding:5px 11px;
  border-radius:9px;cursor:pointer;
}

/* ------------------------- 拼贴墙 ------------------------- */
.moment-feed{display:flex;flex-direction:column;gap:14px;}
.moment-item{
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:14px;
  padding:14px 16px;
}
.moment-head{display:flex;align-items:center;gap:8px;margin-bottom:8px;}
.moment-avatar{flex:none;width:28px;height:28px;border-radius:50%;}
.moment-name{font-size:12.5px;color:var(--text-dim);}
.moment-text{margin:0;font-size:13.5px;line-height:1.6;color:var(--text);}
.moment-time{margin:8px 0 0;font-size:11px;color:var(--text-faint);}

/* ============================================================
   模块 E：心声
   E1 顶部头像的未读呼吸光点 · E2 独立渲染层（便签，不是气泡）
   ============================================================ */

/* ------------------- E1 头像 + 未读呼吸光点 ------------------- */
.avatar-slot{
  position:relative;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;cursor:pointer;
}
.head-avatar{
  width:32px;height:32px;border-radius:50%;display:block;
  transition:transform .12s var(--ease);
}
.avatar-slot:active .head-avatar{transform:scale(.92);}
.hb-dot{
  position:absolute;top:-1px;right:-1px;
  width:9px;height:9px;border-radius:50%;
  background:var(--coral);
  box-shadow:0 0 0 2px var(--bg);      /* 和背景同色的描边，让光点从头像上「浮」起来 */
  display:none;
}
.avatar-slot.has-unread .hb-dot{display:block;}
/* 向外扩散的呼吸圈，只动 transform / opacity */
.avatar-slot.has-unread .hb-dot::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  background:var(--coral);
  animation:hb-breath 1.9s ease-out infinite;
}
@keyframes hb-breath{
  0%{transform:scale(1);opacity:.75;}
  70%{transform:scale(2.4);opacity:0;}
  100%{transform:scale(2.4);opacity:0;}
}
@media (prefers-reduced-motion: reduce){
  .avatar-slot.has-unread .hb-dot::after{animation:none;opacity:.45;}
}
/* 顶栏头像居中模式（聊天详情）：名字不显示，头像 absolute 正中 */
.app-head.head-ava-mode .app-title{visibility:hidden;}
.avatar-slot.head-ava-center{
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
}
.avatar-slot.head-ava-center .head-avatar{width:34px;height:34px;}
/* 名字槽（替代头像）：横向、不换行；未读光点挂在名字右上 */
.avatar-slot.head-name-slot{
  width:auto;min-width:32px;height:32px;
  padding:0 10px;white-space:nowrap;
  background:none;border:0;font-family:inherit;
}
.head-char-name{
  font-size:15px;font-weight:600;color:var(--text);
  letter-spacing:.01em;
}
.avatar-slot.head-name-slot .hb-dot{top:-2px;right:-4px;}

/* ---------------------- 搜索聊天记录 ---------------------- */
/* 盖在整个页面上：找的是「这段对话里说过的话」，动作很轻，不开新页面 */
.chat-search{
  position:absolute;inset:0;z-index:40;
  background:var(--surface-solid);
  display:none;flex-direction:column;
}
.chat-search.is-open{display:flex;}
.chat-search-bar{
  flex:none;
  display:flex;align-items:center;gap:10px;
  padding:14px 18px;
  border-bottom:1px solid var(--bg-3);
}
.chat-search-input{
  flex:1;min-width:0;
  background:var(--bg-2);
  border:1px solid var(--bg-3);border-radius:12px;
  padding:10px 14px;
  color:var(--text);font:inherit;font-size:14px;
  outline:none;
}
.chat-search-input:focus{border-color:var(--accent,var(--bg-3));}
.chat-search-close{
  flex:none;background:none;border:0;cursor:pointer;
  color:var(--accent-soft,var(--text-dim));font:inherit;font-size:13px;
}
.chat-search-results{
  flex:1;overflow-y:auto;
  padding:10px 18px 24px;
  display:flex;flex-direction:column;gap:8px;
}
.chat-search-empty{margin:24px 0;text-align:center;color:var(--text-faint);font-size:13px;}
.chat-search-hit{
  display:flex;align-items:baseline;gap:10px;
  text-align:left;
  background:var(--bg-2);border:0;border-radius:12px;
  padding:10px 14px;cursor:pointer;
  font-family:inherit;color:var(--text);
}
.chat-search-hit:active{transform:scale(.985);}
.chat-search-role{
  flex:none;font-size:11px;color:var(--text-faint);
}
.chat-search-text{
  flex:1;min-width:0;
  font-size:13px;line-height:1.5;color:var(--text-dim);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;
}
/* 搜索跳转命中后的高亮闪烁 */
@keyframes msg-flash{
  0%,60%{box-shadow:0 0 0 2px var(--coral);}
  100%{box-shadow:none;}
}
.msg.is-flash{animation:msg-flash 1.6s var(--ease);}

/* ---------------------- E2 独立渲染层 ---------------------- */
/* 面板做在**页面正中**，不是底部抽屉。
   底部抽屉和「长按菜单 / 加号面板」是同一种姿势，会和它们混在一起；
   心声是一个独立的小世界，居中浮起来更像「翻开一页心里的东西」。 */
.hb-mask{
  position:absolute;inset:0;
  background:var(--scrim);
  z-index:72;
  display:none;
}
.hb-mask.is-open{display:block;}

.hb-panel{
  position:absolute;left:50%;top:50%;
  width:min(86%, 340px);
  max-height:70%;
  z-index:73;
  display:flex;flex-direction:column;
  padding:16px;
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:18px;
  box-shadow:0 18px 48px rgba(0,0,0,.45);
  /* 用 opacity / visibility / transform 出场，留得住过渡动画；
     直接用 display 切换是没法过渡的 */
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translate(-50%,-50%) scale(.94);
  transition:opacity .18s var(--ease),transform .18s var(--ease),visibility .18s;
}
.hb-panel.is-open{
  opacity:1;visibility:visible;pointer-events:auto;
  transform:translate(-50%,-50%) scale(1);
}

.hb-head{flex:none;display:flex;align-items:flex-start;gap:10px;margin-bottom:12px;}
.hb-titles{flex:1;min-width:0;}
.hb-title{
  margin:0;font-family:var(--ff-serif);
  font-size:16px;color:var(--text);
}
.hb-sub{margin:3px 0 0;font-size:11px;color:var(--text-faint);}
.hb-close{
  flex:none;width:26px;height:26px;
  border:0;border-radius:50%;
  background:var(--bg-3);color:var(--text-dim);
  font-size:15px;line-height:1;font-family:inherit;cursor:pointer;
}

.hb-list{
  flex:1;min-height:0;overflow-y:auto;
  display:flex;flex-direction:column;gap:10px;
  padding-right:2px;
}

/* 纸条：没有尾巴、没有大圆角、左边一道竖线、衬线字体。
   刻意和 .msg-bubble（圆角 + 尖角尾巴 + 实底）拉开距离。 */
.hb-note{
  padding:10px 12px 8px 14px;
  background:rgba(232,184,123,.08);
  border-left:2px solid var(--amber);
  border-radius:0 10px 10px 0;
}
.hb-note-text{
  margin:0;font-family:var(--ff-serif);
  font-size:13.5px;line-height:1.7;color:var(--text);
  word-break:break-word;
}
.hb-note-time{
  margin:6px 0 0;font-size:10.5px;
  color:var(--text-faint);text-align:right;
}

.hb-foot{
  flex:none;display:flex;align-items:center;gap:10px;
  margin-top:12px;padding-top:12px;
  border-top:1px solid var(--line);
}
.hb-foot .btn{flex:1;}

.hb-auto{flex:none;display:flex;align-items:center;gap:6px;cursor:pointer;}
.hb-auto input{
  appearance:none;-webkit-appearance:none;
  width:34px;height:20px;margin:0;
  border-radius:10px;background:var(--bg-3);
  position:relative;cursor:pointer;
  transition:background .18s var(--ease);
}
.hb-auto input::after{
  content:'';position:absolute;top:2px;left:2px;
  width:16px;height:16px;border-radius:50%;
  background:var(--text-faint);
  transition:transform .18s var(--ease), background .18s var(--ease);
}
.hb-auto input:checked{background:rgba(232,184,123,.28);}
.hb-auto input:checked::after{transform:translateX(14px);background:var(--amber);}
.hb-auto-text{font-size:11.5px;color:var(--text-dim);}

.hb-empty{text-align:center;padding:22px 0;}
.hb-empty-text{
  margin:0;font-family:var(--ff-serif);
  font-size:13px;color:var(--text-dim);
}
.hb-empty-hint{margin:6px 0 0;font-size:11px;color:var(--text-faint);}

/* ============================================================
   A5 人设预设库：多行文本框 + 字数
   ============================================================ */
.set-textarea{
  width:100%;
  background:var(--surface);
  border:1px solid var(--g-glass-line);
  border-radius:10px;
  padding:10px 11px;
  color:var(--text);
  font-family:var(--ff);
  font-size:13.5px;
  line-height:1.65;
  outline:none;
  resize:vertical;
  min-height:130px;
  transition:border-color .16s var(--ease);
}
.set-textarea:focus{border-color:rgba(232,184,123,.55);}
.set-textarea::placeholder{color:var(--text-faint);}
.set-count{
  margin:6px 0 0;
  font-size:10.5px;
  color:var(--text-faint);
  text-align:right;
}

/* ============================================================
   E2 心声面板改版：最新一条 + 可翻历史
   ============================================================ */
/* 滚动容器从 .hb-list 上移到 .hb-body —— 标题和底部按钮要固定住 */
.hb-body{
  flex:1;
  min-height:0;
  overflow-y:auto;
  padding-right:2px;
}
.hb-list{
  display:flex;
  flex-direction:column;
  gap:10px;
  margin-top:10px;
}

/* 最新那条放大一点，一眼就能看完 */
.hb-note.is-latest{
  padding:14px 14px 10px 16px;
  background:rgba(232,184,123,.13);
  border-left-width:3px;
}
.hb-note.is-latest .hb-note-text{
  font-size:15px;
  line-height:1.8;
}

/* 「看前面的 N 条」/「回到最新」 */
.hb-more{
  display:block;
  width:100%;
  margin-top:10px;
  padding:9px 6px;
  background:transparent;
  border:1px dashed rgba(185,175,201,.26);
  border-radius:10px;
  color:var(--text-dim);
  font-family:inherit;
  font-size:11.5px;
  cursor:pointer;
  transition:background .15s var(--ease);
}
.hb-more:active{background:var(--bg-3);}

/* ============================================================
   应用内弹层（ui.prompt / ui.confirm）
   替代原生 prompt() / confirm() —— 原生弹窗的标题是「127.0.0.1:5173 显示」，
   还挂着地址栏，在一个「小手机」里非常出戏，手机上还会把页面顶上去。
   ============================================================ */
.dl-mask{
  position:absolute;inset:0;
  background:var(--scrim);
  z-index:80;
  display:none;
}
.dl-mask.is-open{display:block;}

.dl-card{
  position:absolute;
  left:50%;top:50%;
  width:min(320px, 82%);
  z-index:81;
  display:none;
  flex-direction:column;
  padding:18px 18px 14px;
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:16px;
  box-shadow:0 18px 44px rgba(0,0,0,.5);
}
.dl-card.is-open{
  display:flex;
  animation:dl-in .16s var(--ease) both;
}
@keyframes dl-in{
  from{opacity:0;transform:translate(-50%,-50%) scale(.95);}
  to{opacity:1;transform:translate(-50%,-50%) scale(1);}
}

.dl-title{
  margin:0 0 12px;
  font-family:var(--ff-serif);
  font-size:15px;line-height:1.55;
  color:var(--text);
}

/* 副说明：删除类操作把后果写在这里，比塞进标题里好读 */
.dl-note{
  margin:-8px 0 12px;
  font-size:11.5px;line-height:1.55;
  color:var(--text-faint);
}

.dl-input{
  width:100%;
  box-sizing:border-box;
  margin-bottom:14px;
  padding:10px 12px;
  background:var(--surface);
  border:1px solid var(--g-glass-line);
  border-radius:10px;
  color:var(--text);
  font-family:var(--ff);
  font-size:14px;
  outline:none;
}
.dl-input:focus{border-color:rgba(232,184,123,.55);}
.dl-input::placeholder{color:var(--text-faint);}

.dl-acts{display:flex;gap:8px;}
.dl-btn{
  flex:1;
  padding:10px 8px;
  border:0;border-radius:11px;
  background:var(--bg-3);
  color:var(--text-dim);
  font-family:inherit;font-size:13.5px;
  cursor:pointer;
  transition:transform .12s var(--ease);
}
.dl-btn:active{transform:scale(.97);}
.dl-btn-ok{
  background:var(--amber);color:#2A2118;
  font-weight:600;
}
.dl-btn-ok.is-danger{background:var(--coral);color:#2A2118;}

/* ============================================================
   名片夹（角色）
   预设库原本挂在设置里，但那本来就该是「新增角色」。
   ============================================================ */
.contact-list{
  display:flex;flex-direction:column;gap:10px;
  padding-bottom:84px;          /* 给右下角 FAB 让位 */
}

.contact-card{
  display:flex;align-items:center;gap:12px;
  width:100%;box-sizing:border-box;
  padding:12px 14px;
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:14px;
  color:var(--text);
  font-family:inherit;text-align:left;
  cursor:pointer;
  transition:transform .12s var(--ease);
}
.contact-card:active{transform:scale(.985);}

.contact-av{
  flex:none;
  width:40px;height:40px;border-radius:50%;
  background:var(--bg-3);
  color:var(--text-dim);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--ff-serif);font-size:17px;
}
/* 世界书：停用的条目整卡压暗，头像圈换成叉 */
.contact-card.is-off{opacity:.55;}
.contact-card.is-off .contact-av{background:transparent;box-shadow:inset 0 0 0 1.5px var(--bg-3);}
.contact-main{
  flex:1;min-width:0;
  display:flex;flex-direction:column;gap:4px;
}
.contact-name{
  font-size:14.5px;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.contact-line{
  font-size:11.5px;color:var(--text-faint);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

.contact-empty{
  padding:26px 0 10px;
  text-align:center;
}
.contact-empty-text{
  margin:0;font-family:var(--ff-serif);
  font-size:13.5px;color:var(--text-dim);
}
.contact-empty-hint{
  margin:8px 0 0;font-size:11.5px;color:var(--text-faint);
}

/* ============================================================
   「挑个人来聊」浮层（page-chat-settings）
   和心声面板同一套材质：居中卡片 + 遮罩，一行一个角色。
   新建对话从此是「挑人」而不是「起名字」。
   ============================================================ */
.pk-mask{
  position:absolute;inset:0;
  background:var(--scrim);
  z-index:74;
  display:none;
}
.pk-mask.is-open{display:block;}

.pk-panel{
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
  width:min(340px, 84%);
  max-height:72%;
  z-index:75;
  display:none;flex-direction:column;
  padding:16px 14px 14px;
  background:var(--bg-2);
  border:1px solid var(--line);
  border-radius:18px;
  box-shadow:0 18px 44px rgba(0,0,0,.5);
}
/* 复用弹层的入场关键帧（同样是 -50%,-50% 定位） */
.pk-panel.is-open{display:flex;animation:dl-in .16s var(--ease) both;}

.pk-head{flex:none;display:flex;align-items:center;gap:10px;margin-bottom:12px;}
.pk-title{
  flex:1;min-width:0;margin:0;
  font-family:var(--ff-serif);
  font-size:15px;color:var(--text);
}
.pk-close{
  flex:none;width:26px;height:26px;
  border:0;border-radius:50%;
  background:var(--bg-3);color:var(--text-dim);
  font-size:15px;line-height:1;font-family:inherit;cursor:pointer;
}

.pk-list{
  flex:1;min-height:0;overflow-y:auto;
  display:flex;flex-direction:column;gap:8px;
  padding-right:2px;
}
.pk-list .btn{width:100%;}

.pk-empty{padding:18px 0 14px;text-align:center;}
.pk-empty-text{
  margin:0;font-family:var(--ff-serif);
  font-size:13.5px;color:var(--text-dim);
}
.pk-empty-hint{margin:8px 0 0;font-size:11.5px;color:var(--text-faint);}

/* ============================================================
   青提玻璃感 · 材质层（套在既有组件上）
   ------------------------------------------------------------
   这一层只做一件事：把「一块面板」统一成玻璃。
   做法是把 `.glass` 那套材质复用到已有类上，而不是去改那 1800 行里
   每一处的 border-radius / box-shadow —— 那种改法漏一处就花一块。

   玻璃的三个必备件（少一个就变成「半透明色块」而不是玻璃）：
     backdrop-filter: blur()   —— 透过去的东西要虚
     border: 亮边              —— 玻璃有厚度
     inset 高光                —— 玻璃是弧面，顶上有反光
   ============================================================ */

/* 玻璃三件套，独立的工具类。新写的组件直接用 .glass 就行。

   ::before 必须 z-index:-1。它现在同时承担**镜面反光**（一层白色径向渐变）——
   用 z-index:auto 的话它排在「定位后代」那一档，会盖在正文上面，
   卡片左上角的字会被那层高光洗白。给 -1 之后它落在「元素自身的背景之上、
   正文之下」的位置，正是真实玻璃的层次：底色 → 反光 → 内容。
   （.widget / .glass 都有 backdrop-filter，本身已经是层叠上下文，
    -1 不会漏到页面背景后面去。） */
.glass{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  border-radius:20px;
  box-shadow:var(--g-ring),var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
  position:relative;
}
.glass::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  border-radius:inherit;
  background:var(--g-spec),var(--g-lens);
  box-shadow:var(--g-inset);
  pointer-events:none;
}
.glass-2{background:var(--g-glass-2);}

/* ---- 既有组件：贴玻璃 ---- */

#statusbar{color:var(--g-ink-2);text-shadow:0 1px 2px rgba(255,255,255,.5);}

.app-head{
  background:transparent;
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
}
.app-head::after{
  content:"";
  position:absolute;
  left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--g-glass-line),transparent);
  pointer-events:none;
}
.back-btn{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  color:var(--g-ink-2);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
}
.back-btn:active{background:var(--g-glass-2);}

.set-card{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  border-radius:18px;
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
}
.set-row{border-bottom-color:var(--g-glass-line);}
.set-row:active{background:var(--g-glass-2);}

.set-input,.set-textarea{
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-line);
}
.set-input:focus,.set-textarea:focus{
  border-color:var(--g-accent);
  box-shadow:0 0 0 3px rgba(111,184,106,.16);
}

/* 按钮：主按钮是实心青提绿（浅底上要有唯一一个最重的色块） */
.btn{border-radius:12px;}
.btn-primary{
  background:linear-gradient(135deg,var(--g-accent) 0%,var(--g-accent-deep) 100%);
  border-color:transparent;
  color:#FFFFFF;
  box-shadow:0 6px 16px rgba(139,108,76,.30);
}
.btn-ghost{
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  color:var(--g-ink-2);
}
.btn-danger{background:rgba(217,115,107,.14);border:1px solid rgba(217,115,107,.4);color:#B85A52;}

/* 导航栏 / 输入区：都是玻璃 */
.dock{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:blur(30px);
  -webkit-backdrop-filter:blur(30px);
}
.chat-foot{
  background:var(--g-glass);
  border-top:1px solid var(--g-glass-edge);
  backdrop-filter:blur(24px);
  -webkit-backdrop-filter:blur(24px);
}

/* 列表卡片 */
.chat-item,.contact-card{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  border-radius:16px;
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
}
.chat-item:active,.contact-card:active{background:var(--g-glass-2);}

/* 气泡。我方＝青提绿实心，对方＝白玻璃。
   施工卡里踩过「文字和底色同色」的坑（.msg-assistant 隐身），
   所以两边都写死对比色，不依赖继承。 */
.msg-user .msg-text,.msg-user .msg-body{
  color:#FFFFFF;
}
.msg-user .msg-text{
  background:linear-gradient(135deg,var(--g-accent) 0%,#5FA95C 100%);
  border-color:transparent;
  box-shadow:0 4px 14px rgba(139,108,76,.22);
}
.msg-assistant .msg-text{
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  color:var(--g-ink);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
}
.msg-system .msg-text{background:rgba(139,108,76,.10);color:var(--g-ink-2);}

/* 弹层与面板 */
.msg-menu,.hb-panel,.dl-card,.pk-panel{
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:blur(30px);
  -webkit-backdrop-filter:blur(30px);
}
.plus-panel{
  background:var(--g-glass);
  border-top:1px solid var(--g-glass-edge);
  backdrop-filter:blur(24px);
  -webkit-backdrop-filter:blur(24px);
}

/* 发送键：底是青提绿，爪印就得是**浅色**。
   原来这里写的是 `color:var(--g-accent-deep)`（爪印也绿）——
   后来 `--amber` 也被重映射成了同一个绿，于是绿底绿爪、爪印整个隐形，
   用户以为小猫爪丢了。教训：**给底色配字色时，两边不能引用同一个变量**。 */
.send-btn{color:#F4FCF3;}
.send-btn.is-busy{color:var(--g-ink-3);}

/* 空心纸：夜灯时期是米色便签，浅色主题下要能看见 */
.empty-paper{
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
}
.empty-paper::after{border-color:transparent transparent rgba(139,108,76,.18) transparent;}

.fab-btn{
  background:linear-gradient(135deg,var(--g-accent) 0%,var(--g-accent-deep) 100%);
  color:#fff;
  box-shadow:0 8px 22px rgba(139,108,76,.34);
}

/* ============================================================
   桌面（page-desktop）：4 屏网格
   ------------------------------------------------------------
   用 scroll-snap 做翻页，不用 transform 自己算位移 ——
   移动端的惯性和回弹是原生的，自己写只会更差。

   尺寸公式：4 列网格，两侧各留 20px，列间距 16px。
   用 calc 从 100vw 推，而不是写死 px —— 写死的话
   在 360px 的窄屏上会溢出到屏幕外。
   ============================================================ */

.dt-scroll{
  flex:1;
  display:flex;
  width:100%;
  min-height:0;
  overflow-x:auto;
  overflow-y:hidden;
  scroll-snap-type:x mandatory;
  scroll-behavior:smooth;
  scrollbar-width:none;
}
.dt-scroll::-webkit-scrollbar{display:none;}

.dt-screen{
  flex:0 0 100%;
  width:100%;
  height:100%;
  scroll-snap-align:start;
  padding:var(--dt-pad-top) 20px var(--dt-pad-bottom);
  box-sizing:border-box;
  /* 网格尺寸是按「可用高度」算的，正常情况下 6 行正好装下、不会滚动。
     但极矮的窗口（比如桌面浏览器把窗口压到很扁）还是会溢出，
     所以留着 overflow-y —— 以前是 overflow:hidden，
     溢出的格子被**静默裁掉**：DOM 里有、有宽高、数得到，就是看不见。 */
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
}
.dt-screen::-webkit-scrollbar{display:none;}

.dt-tail{
  flex:0 0 1px;
  height:100%;
  scroll-snap-align:end;
}

/* 网格尺寸。
   ---- 算的是「高度」不是「宽度」----
   早先 --dt-cell 从 100vw 推（(100vw-40px-3*16)/4），在 480px 宽的手机上
   算出 98px。但 6 行 × 98 + 5 × 16 = 668px，而可用高度只有 ~379px ——
   下面两行整个掉到屏幕外，还被 dock 盖住。
   格子是正方形，长宽必须一起看：取「按宽度算」和「按高度算」里**小的那个**，
   保证 6 行一定装得下，同时宽屏上不会撑成大方块。

   可用高度 = 100dvh − 状态栏(32+8) − 屏幕上下内边距(26 + 132)。
   132 是给 dock 留的位置（74 高 + 14 底距 + 44 呼吸）。 */
:root{
  --dt-gap:16px;
  --dt-pad-top:26px;
  --dt-pad-bottom:132px;
  --dt-chrome:calc(env(safe-area-inset-top) + 32px + var(--dt-pad-top) + var(--dt-pad-bottom));
  --dt-cell-w:calc((100vw - 40px - 3 * var(--dt-gap)) / 4);
  --dt-cell-h:calc((100dvh - var(--dt-chrome) - 5 * var(--dt-gap)) / 6);
  /* 取小：宽屏时按宽度算更小，矮屏时按高度算更小。
     min() 是 CSS 的原生能力，比在 JS 里重算一遍可靠。 */
  --dt-cell:min(var(--dt-cell-w), var(--dt-cell-h), 98px);
  /* App 图标那块玻璃的边长。必须跟着格子缩 —— 矮屏上 --dt-cell 会掉到
     60 出头，写死 54px 会跟下面的文字标签挤在一起。
     .66 是量出来的：格子 81.5px 时方块 53.8px，留出 6px 间距 +
     一行 10.5px 的文字，正好装下。 */
  --dt-tile:min(54px, calc(var(--dt-cell) * .66));
}
@media (min-width:520px){
  /* 窄屏 / 宽屏的宽度上限不同，所以宽度那一项也要跟着改 */
  :root{
    --dt-cell-w:calc((480px - 40px - 3 * var(--dt-gap)) / 4);
    --dt-cell:min(var(--dt-cell-w), var(--dt-cell-h), 98px);
    --dt-tile:min(54px, calc(var(--dt-cell) * .66));
  }
}

.dt-grid{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  grid-template-rows:repeat(6,var(--dt-cell));
  gap:var(--dt-gap);
  align-content:start;
  position:relative;
  z-index:1;
  /* 不要写 height:100% —— 父 .dt-screen 是 block 且带 padding，
     100% 会解析成「内容盒高度」，6 行格子放不下时被裁掉。
     让网格自己撑高，交给 .dt-screen 滚动。 */
}

/* ============================================================
   网格底纹 + 布局编辑态

   为什么要画网格：组件本身是圆角玻璃块，光看根本不知道底下有格子。
   用户不会去长按一个「看起来是整块画布」的东西 ——
   所以平时给一层极淡的点阵当暗示，编辑态才把格子画实。
   ============================================================ */

.dt-mesh{
  position:absolute;
  left:20px;right:20px;
  /* 和 .dt-screen 的上下内边距对齐，否则底纹和组件错开半格 ——
     那比不画还糟，用户会以为格子就是歪的。 */
  top:var(--dt-pad-top);
  bottom:var(--dt-pad-bottom);
  display:grid;
  grid-template-columns:repeat(4,1fr);
  grid-template-rows:repeat(6,var(--dt-cell));
  gap:var(--dt-gap);
  align-content:start;
  pointer-events:none;
  z-index:0;
}
.dt-mesh-cell{
  border-radius:20px;
  border:1px dashed transparent;
  transition:border-color .3s var(--ease), background .3s var(--ease);
}

/* 平时：完全不可见（2026-09-17 用户定调「没进编辑态不要显示
   明显的 app 占位框」—— 原来那层极淡点阵也不要了）。
   网格只在编辑态出现，平时桌面就是干干净净的图标 + 文字。 */
.dt-screen .dt-mesh-cell{
  background:transparent;
  border-color:transparent;
}

/* 编辑态：格子画实、玻璃组件轻轻抖 —— 手机上「可以挪了」的通用语汇。
   反馈必须**明显**：早先只加了 0.45° 的抖动和很淡的虚线，
   静态看一眼跟平时没区别，用户根本不知道已经进了编辑态
   （踩过：截图上完全看不出区别，用户以为长按没反应）。
   所以这里加了：每个组件的边缘高亮 + 明显的抖动幅度 + 角上的把手点。 */
.dt-screen.is-editing .dt-mesh-cell{
  background:rgba(139,108,76,.07);
  border-color:rgba(139,108,76,.34);
}
.dt-screen.is-editing .widget{
  animation:dt-jiggle 300ms var(--ease) infinite alternate;
  cursor:grab;
  /* 编辑态里组件不该还能点开 —— 用户此刻是想摆位置，不是想进 App */
  outline:2px solid rgba(139,108,76,.42);
  outline-offset:-2px;
}
.dt-screen.is-editing .widget:nth-child(even){animation-delay:-150ms;}

/* 角上的小把手：四个角各一个点，是「这块可以抓起来」最直白的信号。
   用 ::after 画，不额外加 DOM —— 加了会占网格位置。 */
.dt-screen.is-editing .widget::after{
  content:'';
  position:absolute;
  right:5px;bottom:5px;
  width:7px;height:7px;
  border-radius:50%;
  background:rgba(139,108,76,.55);
  box-shadow:-103px 0 0 rgba(139,108,76,.35), 0 -103px 0 rgba(139,108,76,.35);
  pointer-events:none;
}

@keyframes dt-jiggle{
  from{transform:rotate(-1.1deg);}
  to{transform:rotate(1.1deg);}
}

/* 拖动中的那一格：抬起、跟上手、盖住别人 */
.widget.is-dragging{
  animation:none !important;
  cursor:grabbing;
  box-shadow:0 18px 40px rgba(88,70,52,.28), var(--g-glass-shadow);
  transition:none;
}

/* 落点幽灵：显示「松手会落在哪」。合法是虚线框，非法是红色 —— 
   拖动时最需要的就是这个即时反馈，否则用户只能靠猜。 */
.dt-ghost{
  border-radius:20px;
  border:2px dashed rgba(139,108,76,.5);
  background:rgba(139,108,76,.09);
  pointer-events:none;
  z-index:0;
}
.dt-ghost.is-bad{
  border-color:rgba(206,88,74,.55);
  background:rgba(206,88,74,.09);
}

/* ---------------- 玻璃组件本体 ---------------- */

.widget{
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  border-radius:20px;
  box-shadow:var(--g-ring),var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;
  position:relative;
  overflow:hidden;
  min-width:0;
  min-height:0;
  color:var(--g-ink);
  font-family:inherit;
}
/* 镜面反光 + 内高光：玻璃是弧面，顶上有反光。
   少了这层就只是半透明色块；z-index:-1 的理由见上面 .glass::before。 */
.widget::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  border-radius:inherit;
  background:var(--g-spec),var(--g-lens);
  box-shadow:var(--g-inset);
  pointer-events:none;
}
.widget.w-1x1{border-radius:18px;}

/* ---------------- App 图标格 ----------------
   2026-09-17 第二轮，用户给了参考图（iOS 玻璃桌面）并定调：
   「有边框但是是透亮感强一些且好看的」。
   上一版是**裸图标**（无框无底），在纯白底上就剩一根细线，飘；
   现在把图标放进一块**高透玻璃方块**里。

   方块为什么能又透又立得住：靠的还是四件（见 :root 里玻璃那段注释）——
     边框  1px 近白亮边 + 一圈极淡冷灰 --g-ring（白底上唯一看得见的轮廓）
     填充  白→微冷 的斜向渐变，四角比中间透，像块压薄了的玻璃
     反光  ::after 左上那团镜头光晕 —— 这是「透亮」最直接的一笔
     折射  ::before 下缘一条冷蓝辉光，模仿玻璃对底下光晕的折射
   底下的光晕（.ambient）从四角打过来，透过这块玻璃会变亮一点，
   所以它看起来是「透光的」而不是「贴上去的白块」。 */

.w-app{
  /* 外壳仍然透明：那块玻璃只包住图标，文字在主色底上 */
  background:transparent !important;
  border:none !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
  cursor:pointer;
  padding:0;
  font-family:inherit;
  justify-content:flex-end;   /* 图标贴格子中上，文字贴在其下 */
}
.w-app::before{display:none;}
.w-app:active .w-app-ic{transform:scale(.93);}

/* 玻璃方块。**桌面图标和底栏图标共用这一段** ——
   两处各抄一份的话，改一次高光要改两个地方，迟早长歪。
   边长由局部变量 --tk 决定，各自在自己那条规则里赋值。
   --tk 跟着 --dt-cell 走 —— 矮屏上格子会缩小，
   写死 54px 会顶到文字（--dt-cell 最小可能只有 62px 左右）。

   填充**故意不是纯白**：白底上的纯白玻璃＝隐形。

   2026-09-17 第五轮（用户：「app要透明玻璃，也就是不管我换什么颜色的壁纸，
   都可以直接透出壁纸的样子的那种，所以要透明，要亮」）：
   上一版的 alpha 是 .48~.84 —— 在**白底**上够用，但它是「白玻璃」：
   换一张深色壁纸，这排图标就会变成一排白瓷砖，把壁纸整个盖住。
   现在把填充压到 .07~.30（几乎是透明的），让壁纸的颜色直接穿过来，
   「亮」靠 backdrop-filter 里的 brightness(1.10) 把背后的壁纸提亮。

   2026-09-18 第六轮（用户：「不要每个app单独加光，那样太丑了，
   而且还是有黑色的阴影！」）：**把每个图标身上的特效全部拆掉** ——
     · ::after 那片镜头光晕（.85 的白）—— 那就是「每个 app 单独的一团光」
     · 填充层里「中间一小汪白」（radial-gradient 那层）
     · 两层外部投影（--tk-shadow）
     · 图标线条外面那圈白晕（.w-app-ic svg 上的 drop-shadow）
   叠了五项效果之后，每个图标看起来都在自己发光 —— 一排看过去非常脏。
   现在只剩：一层很淡的斜向填充 + 一条 1px 亮边。玻璃感靠底下的壁纸自己透出来，
   不靠往上加光。 */
.w-app-ic,.dt-dock-ic{
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
  width:var(--tk);
  height:var(--tk);
  border-radius:calc(var(--tk) * .315);
  background:linear-gradient(160deg,
    var(--tk-a) 0%,
    var(--tk-b) 42%,
    var(--tk-c) 78%,
    var(--tk-d) 100%);
  border:1px solid var(--tk-line);
  backdrop-filter:blur(18px) saturate(165%) brightness(1.10);
  -webkit-backdrop-filter:blur(18px) saturate(165%) brightness(1.10);
  /* 直接引 --g-ink（不抽 --tk-ink）—— 理由见 :root 里那组变量的注释 */
  color:var(--g-ink);
  line-height:0;
  overflow:hidden;
  transition:transform .18s var(--ease);
}
/* 这里原本有 ::before（下缘冷色折射）和 ::after（左上镜头光晕）两层。
   第六轮一起去掉了 —— 见上面那段。**别再加回来**：
   用户明确说过「不要每个app单独加光」。 */
.w-app-ic{--tk:var(--dt-tile);}
.w-app-ic svg,.dt-dock-ic svg{
  position:relative;
  width:22px;
  height:22px;
  z-index:1;
  /* 这里原本挂了一圈白晕（drop-shadow）来保深色壁纸上的可读性，
     第六轮去掉了（用户：「不要每个app单独加光」）。
     代价：深色壁纸上深色线条会偏弱 —— 等壁纸功能真做了，
     应该做的是**按壁纸明暗自动切字色**，而不是再给每个图标糊一圈光。 */
}
/* 玻璃对底下光晕的折射、左上那团镜头光晕 —— 两层 ::before/::after
   第六轮一起去掉了（见上面 .w-app-ic 那段注释）。 */

.w-app-name{
  margin-top:6px;
  font-size:10.5px;
  font-weight:500;
  color:var(--g-ink-2);
  letter-spacing:.3px;
}
.w-dead{opacity:.35;}

/* 裸字压在壁纸上：一律带一圈光晕。
   桌面第五轮去掉面板之后，日期头和应用名都是**直接压在壁纸上**的
   字 —— 换成深色壁纸它们会整行消失（实测：深紫壁纸上
   「九月 · 星期五」和「世界书」完全看不见）。
   **以后往桌面上加任何「不加面板的文字」，都要挂进这个选择器。**

   2026-09-18 第六轮：光晕的**颜色必须跟着主题翻**。
   上一版写死了白色，夜灯主题下变成「浅色字 + 白晕」——
   用户原话「开了夜间模式后这里全是糊的」，截图里整块日期头都在发光。
   现在抽成 --ink-halo：浅色主题是白晕（深字托起来），
   深色主题换成一圈淡黑影（浅字压下去）。 */
.w-hdr-kicker,.w-hdr-day,.w-hdr-date,.w-hdr-greet,.w-hdr-pull-label,.w-app-name{
  text-shadow:var(--ink-halo);
}
/* （分隔线原本也挂了一圈白晕，第六轮连同其它「加光」一起去掉了。
     线本身的渐变用的是 --g-ink-3，是主题感知的。） */

/* ---------------- 首页日期头（主屏最上面那一块） ----------------
   2026-09-17 第四轮。参考版式：一行小字抬头 / 一个很大的日期数字 /
   一行日期，右侧一根细绳挂下来一个小玻璃坠子。
   占 4 列 × 3 行的格子，所以字号和间距全部挂在 --dt-cell 上 ——
   矮屏上格子会缩到 60 出头，写死 px 的话这块头会撑破。

   第五轮（用户：「我要字体直接呈现在上面，而不是加框」）：
   **这块不是玻璃面板了** —— 没有底、没有边框、没有投影、没有 backdrop。
   和 .w-app 同一套做法（!important 压掉 .widget 的材质 + 关掉 ::before）。
   加框的时候字是被「装」在盒子里；去掉框之后就是排版本身在撑场面。
   代价是字直接压在壁纸上，所以下面所有文字颜色都不能写死，
   一律走 --g-ink*（深色主题会自动翻成浅色）。

   数字为什么用细体无衬线而不是本项目那套衬线标题：
   参考图要的就是这个「轻」的对比（一块很大的浅色字压住整屏留白）。
   衬线在 100px 这个尺码上会显得很重，把留白压没了。
   字体名里带 Segoe UI Light 是给 Windows 的，mac 上走 -apple-system
   的 200 字重，两边都能拿到细体，不会退化成大黑体。 */
.w-hdr{
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
  align-items:stretch;
  justify-content:flex-start;
  padding:0;
  cursor:default;
}
.w-hdr::before{display:none;}
.w-hdr-inner{
  flex:1;
  min-width:0;
  display:flex;
  flex-direction:column;
  justify-content:center;
  /* 右边留出坠子的位置，否则那根绳子和「星期四」叠字 */
  padding:0 calc(var(--dt-cell) * .78) 0 calc(var(--dt-cell) * .30);
  text-align:left;
}
.w-hdr-kicker{
  display:flex;
  align-items:center;
  gap:8px;
  font-size:11px;
  letter-spacing:.34em;
  color:var(--g-ink-3);
  margin-bottom:calc(var(--dt-cell) * .14);
}
.w-hdr-sep{font-style:normal;letter-spacing:0;opacity:.65;}
.w-hdr-day{
  font-family:"Segoe UI Light","Segoe UI",-apple-system,BlinkMacSystemFont,
    "Helvetica Neue",Arial,sans-serif;
  font-weight:200;
  /* 去掉面板之后整块轻了一圈，数字再大一档才压得住 ——
     它是这块版面的主角，太小就变成「一屏散字」。 */
  font-size:calc(var(--dt-cell) * 1.42);
  line-height:.88;
  letter-spacing:-.02em;
  color:var(--g-ink);
  font-variant-numeric:tabular-nums;
}
.w-hdr-date{
  margin-top:calc(var(--dt-cell) * .10);
  font-size:12.5px;
  letter-spacing:.26em;
  color:var(--g-ink-2);
}
/* 日期下面那条细横线 —— 参考图底部本来就有这一道。
   去掉面板之后它还有个实际作用：把「日期」和「问候」上下分开，
   否则四行字悬在空白的壁纸上会散成四块，连不成一体。
   宽度只占一段（不是通栏），跟参考图一致。 */
.w-hdr-rule{
  width:calc(var(--dt-cell) * 1.5);
  height:1px;
  margin-top:calc(var(--dt-cell) * .30);
  background:linear-gradient(90deg,var(--g-ink-3),rgba(180,166,147,0));
  opacity:.8;
}
/* 时段问候：中文化之后版面比英文瘦一圈（用户：「换成全部中文之后太空了」），
   这一行是最下面那根压舱 —— 没有它，下半块就整个空着。 */
.w-hdr-greet{
  margin-top:calc(var(--dt-cell) * .18);
  font-size:12px;
  letter-spacing:.30em;
  color:var(--g-ink-3);
}

/* ---- 坠子（这一轮只做外观，不可拖） ----
   结构就是参考图那三件：上面一截细绳 → 中间一颗玻璃小胶囊 → 下面竖排标签。
   胶囊本身用的还是全套玻璃（亮边 + 内高光 + 投影 + 镜头光晕），
   所以它跟网格里那排图标是同一个材质家族。 */
.w-hdr-pull{
  position:absolute;
  right:calc(var(--dt-cell) * .16);
  top:0;
  bottom:calc(var(--dt-cell) * .24);
  width:48px;
  display:flex;
  flex-direction:column;
  align-items:center;
  padding:0;
  border:0;
  background:none;
  cursor:pointer;
  font-family:inherit;
  color:var(--g-ink-3);
  -webkit-tap-highlight-color:transparent;
}
.w-hdr-cord{
  flex:0 0 auto;
  width:1px;
  height:calc(var(--dt-cell) * .34);
  /* 用 currentColor（= 按钮上的 --g-ink-3）而不是写死棕色 ——
     写死的话夜灯主题下这根绳子在深底上直接消失。 */
  background:linear-gradient(180deg,rgba(255,255,255,0),currentColor);
  opacity:.55;
}
.w-hdr-knob{
  position:relative;
  flex:0 0 auto;
  width:14px;
  height:22px;
  border-radius:7px;
  /* 和网格图标共用同一套玻璃变量，夜灯主题自动跟着翻过来 */
  background:linear-gradient(180deg,var(--tk-a),var(--tk-c));
  border:1px solid var(--tk-line);
  box-shadow:
    var(--g-ring),
    0 3px 8px rgba(120,132,156,.20),
    0 9px 16px -7px rgba(120,132,156,.34),
    inset 0 1px 1px var(--tk-glare);
  backdrop-filter:blur(12px) saturate(130%);
  -webkit-backdrop-filter:blur(12px) saturate(130%);
  overflow:hidden;
  transition:transform .2s var(--ease);
}
.w-hdr-knob::after{
  content:"";
  position:absolute;
  left:14%;top:6%;
  width:62%;height:34%;
  border-radius:50%;
  background:radial-gradient(closest-side,var(--tk-glare),rgba(255,255,255,0));
  pointer-events:none;
}
.w-hdr-pull:active .w-hdr-knob{transform:translateY(3px);}
/* 标签是英文（PULL TO CHOOSE），第五轮从中文改回来的。
   vertical-rl 下拉丁字母会跟着转 90°，正是参考图那个姿势；
   中文在同样的 writing-mode 下是正立的，气质差很远。
   字距收到 .2em —— 14 个字符，还给 .42em 的话竖直方向会顶到坠子。 */
.w-hdr-pull-label{
  margin-top:11px;
  writing-mode:vertical-rl;
  font-size:9.5px;
  letter-spacing:.2em;
  color:var(--g-ink-3);
}

/* ---------------- 主屏下拉：选一段存档降落 ----------------
   拉手点开（或按住往下拽）后：桌面往后仰（.page.is-pulled），
   前面垂下一叠岛卡，点一张降落过去。
   面板挂在 .page 这一层 —— 那里有 transform，fixed 的包含块
   正好是一块手机屏；塞进 .dt-scroll 会被底栏的层叠上下文压住。 */
.page.is-pulled{perspective:1100px;}
.page.is-pulled .dt-scroll{
  transform:translateY(14px) scale(.95) rotateX(7deg);
  transition:transform .34s var(--ease);
  pointer-events:none;
}
.page.is-pulled .dt-dock{
  opacity:.22;
  pointer-events:none;
}
.page.is-pulled .dt-dots{opacity:.4;}

.dt-pull-scrim{
  position:fixed;
  inset:0;
  z-index:30;
  display:flex;
  justify-content:center;
  align-items:flex-start;
  background:rgba(64,52,38,0);
  opacity:0;
  pointer-events:none;
  transition:background .32s var(--ease), opacity .32s var(--ease);
  -webkit-backdrop-filter:blur(0px);
  backdrop-filter:blur(0px);
}
.dt-pull-scrim.is-open{
  opacity:1;
  pointer-events:auto;
  background:rgba(64,52,38,.26);
  -webkit-backdrop-filter:blur(5px);
  backdrop-filter:blur(5px);
}
.dt-pull{
  width:min(85%, 330px);
  margin-top:calc(56px + env(safe-area-inset-top, 0px));
  padding:16px 14px 10px;
  border-radius:20px 16px 18px 22px / 18px 20px 16px 20px;
  background:var(--g-glass-2, rgba(255,255,255,.92));
  border:1px solid var(--tk-line, rgba(255,255,255,.9));
  box-shadow:
    0 24px 48px -18px rgba(64,52,38,.42),
    var(--g-ring, 0 0 0 1px rgba(122,134,158,.14));
  -webkit-backdrop-filter:blur(22px) saturate(150%);
  backdrop-filter:blur(22px) saturate(150%);
}
.dt-pull-head{
  font-family:var(--ff-serif);
  font-size:15px;
  font-weight:600;
  letter-spacing:.06em;
  color:var(--g-ink);
  padding:0 2px 10px;
}
.dt-pull-empty{
  margin:2px 2px 8px;
  font-size:12px;
  color:var(--g-ink-3);
}
.dt-pull-card{
  display:flex;
  align-items:center;
  gap:11px;
  width:100%;
  padding:10px 11px;
  margin-bottom:7px;
  border:0;
  border-radius:13px;
  background:none;
  font-family:inherit;
  text-align:left;
  cursor:pointer;
  transition:background .16s var(--ease), transform .16s var(--ease);
  -webkit-tap-highlight-color:transparent;
  /* 手风琴：初始藏起一点、往下错，is-open 后归位。
     每张卡的延迟由 JS 内联（transitionDelay）。 */
  opacity:0;
  transform:translateY(-12px);
  transition:opacity .3s var(--ease), transform .3s var(--ease),
    background .16s var(--ease);
}
.dt-pull-scrim.is-open .dt-pull-card{opacity:1;transform:none;}
.dt-pull-card:active{transform:scale(.97);}
.dt-pull-av{
  flex:0 0 auto;
  display:flex;
  align-items:center;
  justify-content:center;
  width:34px;
  height:34px;
  border-radius:50%;
  font-family:var(--ff-serif);
  font-size:15px;
  font-weight:600;
  color:var(--g-accent-deep);
  background:
    radial-gradient(70% 70% at 32% 26%, rgba(255,255,255,.9), rgba(255,255,255,0) 70%),
    var(--g-accent-pale);
  box-shadow:inset 0 0 0 1px rgba(176,138,94,.22);
}
.dt-pull-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.dt-pull-name{
  font-size:13.5px;
  font-weight:600;
  color:var(--g-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.dt-pull-sub{
  font-size:10.5px;
  letter-spacing:.06em;
  color:var(--g-ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.dt-pull-now{
  flex:0 0 auto;
  font-size:9.5px;
  letter-spacing:.14em;
  color:var(--g-accent-deep);
  border:1px solid rgba(176,138,94,.35);
  border-radius:8px;
  padding:2px 7px;
}
/* 群岛多人的段卡只是分组头：点击展开/收起角色卡，不降落。
   右侧的「›」随展开转向下 —— 手机上最省解释的展开暗示。 */
.dt-pull-card.is-group{cursor:pointer;}
.dt-pull-card.is-group::after{
  content:"›";
  flex:0 0 auto;
  color:var(--g-ink-3);
  font-size:15px;
  transition:transform .22s var(--ease);
}
.dt-pull-card.is-group.is-open::after{transform:rotate(90deg);}
.dt-pull-card.is-group.is-open{background:rgba(176,138,94,.06);}

/* 角色子卡：一人一张，缩进一档，点了带着这个角色降落。
   初始藏起，is-open 后归位；延迟由 JS 内联（跟着段卡错开一拍）。 */
.dt-pull-chars{display:flex;flex-direction:column;gap:5px;margin:0 2px 7px 0;}
.dt-pull-char{
  display:flex;
  align-items:center;
  gap:9px;
  width:100%;
  padding:8px 10px;
  border:0;
  border-radius:11px;
  background:rgba(255,255,255,.45);
  box-shadow:inset 0 0 0 1px rgba(176,138,94,.14);
  font-family:inherit;
  text-align:left;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  opacity:0;
  transform:translateY(-8px);
  transition:opacity .28s var(--ease), transform .28s var(--ease),
    background .16s var(--ease);
}
.dt-pull-scrim.is-open .dt-pull-char{opacity:1;transform:none;}
.dt-pull-char:active{transform:scale(.97);}
.dt-pull-char-av{
  flex:0 0 auto;
  display:flex;
  align-items:center;
  justify-content:center;
  width:26px;
  height:26px;
  border-radius:50%;
  font-family:var(--ff-serif);
  font-size:12.5px;
  font-weight:600;
  color:var(--g-accent-deep);
  background:var(--g-accent-pale);
  box-shadow:inset 0 0 0 1px rgba(176,138,94,.20);
}
.dt-pull-char-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;}
.dt-pull-char-name{
  font-size:12.5px;
  font-weight:600;
  color:var(--g-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.dt-pull-char-sub{
  font-size:10px;
  color:var(--g-ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.dt-pull-char.is-current{background:rgba(176,138,94,.10);}

.dt-pull-card.is-current{background:rgba(176,138,94,.08);}
.dt-pull-hint{
  margin:2px 2px 2px;
  padding-top:8px;
  border-top:1px solid var(--g-glass-line, rgba(126,136,156,.14));
  font-size:10px;
  letter-spacing:.10em;
  color:var(--g-ink-3);
  text-align:center;
}

/* ---- 装饰：一枚细描边的环 ----
   用户第五轮：「目前这个还是有点空了……可以加一点别的装饰」。
   空的其实是**字右边那一大片** —— 中文比英文短，四行字只占左边一格宽，
   右边 60% 全空着。环放那儿正好压住。
   选环是有出处的：它和坠子那颗玻璃胶囊、以及 App 里的「浮岛」是同一个意象，
   比随手撒几个点更像本来就在那儿。
   三层（外环 / 内环 / 环上一点）全部只用描边、不用实色，
   所以压在壁纸上也只是一点淡淡的痕迹，不会变成一块盖住壁纸的补丁。 */
.w-hdr-orn{
  position:absolute;
  right:calc(var(--dt-cell) * .95);
  top:50%;
  transform:translateY(-50%);
  width:calc(var(--dt-cell) * 1.02);
  height:calc(var(--dt-cell) * 1.02);
  opacity:.55;
  pointer-events:none;
  /* 这里原本挂了一圈白晕来保深色壁纸上的可见度。
     第六轮一起去掉了：用户在抱怨「不要加光」，而且夜灯主题下
     白晕会让整块装饰糊成一圈。--g-ink-3 本身是主题感知的，
     浅底深底都读得出来，不需要额外加光。 */
}
.w-hdr-orn-ring{
  position:absolute;
  inset:0;
  border-radius:50%;
  border:1px solid var(--g-ink-3);
}
.w-hdr-orn-ring-2{inset:26%;opacity:.55;}
.w-hdr-orn-dot{
  position:absolute;
  left:50%;
  top:0;
  width:6px;
  height:6px;
  transform:translate(-50%,-50%);
  border-radius:50%;
  background:var(--g-ink-3);
}

/* ---------------- 夜间模式开关（异形） ----------------
   参考图（用户上轮给的那张 3D 渲染）里最抓眼的**不是开关本身**，
   而是左端有一块歪的、有机的软影子溢出来 —— 整个轮廓因此不是一个
   干净的圆角矩形。用户第五轮点名要的就是这个。
   第五轮第二次：形状方向定稿 ——「原本就是左边圆右边长，然后中间一个
   开关按钮，有点像麦克风一样」。所以轮廓 = **左圆 + 右长条**的并集，
   路径在 page-desktop.js 的 MODE_PATH 里（只写一份，遮罩和描边共用）。

   为什么是「玻璃层 + 描边层」两层，而不是一层加个 border：
   **border 跟不上非矩形的轮廓** —— 这条轮廓是圆和长条的并集，
   border 只会沿着元素自己的方框走（圆的左半边勉强算贴边、
   长条的上下两条边完全没有边）。
   `filter: drop-shadow` 也不行：影子跟着源图 alpha 走，而玻璃本身
   只有 .16~.40 的通明度，糊出来是一圈若有若无的灰，不是一条边。
   所以：玻璃那层用 mask 裁形状（backdrop-filter 照常透壁纸），
   描边交给一层 SVG `<path stroke>` **盖在玻璃上面** ——
   放下面的话白色描边会整个变成玻璃的 backdrop，壁纸就透不上来了。

   为什么外壳的材质全让出去（.w-mode 自己 background:none）：.widget 默认
   带玻璃底 + overflow:hidden，留着的话软影子会被裁进方块里。 */
.w-mode{
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
  overflow:visible;
  display:block;
  padding:0;
  cursor:pointer;
}
.w-mode::before{display:none;}

/* ---- 玻璃本体：用 mask 裁成话筒形，backdrop-filter 把壁纸透上来 ----
   mask 的 URL 是 JS 里拼好塞进内联样式的（见 MODE_MASK）——
   CSS 里没有这条路径的第二份，改形状只需要改 JS 那一处。

   第一层是**圆里那点暖色**：放进玻璃自己的 background 里，就会被 mask
   精确裁住，一点也不会溢到轮廓外。
   （一开始是拿一个独立的元素加 blur 去做这块暖色的 —— 不行：
   它只能靠模糊去凑，而模糊一定会往外洇，在壁纸上糊成一坨黄渍；
   和玻璃里这层叠起来还会出现块状斑。所以那层已经删掉了。）

   第六轮：上面那层 SVG 描边被用户否掉了（「最外面的线框不要」）。
   于是轮廓**只能靠填充自己定义**，所以这里的 alpha 比图标那排高一档
   （.58/.34/.42，图标是 .30/.14/.07）——
   描边一走，填充再跟图标一样淡的话，白底上这块形状就整个消失了。
   投影也从两层收到一层、颜色压淡：用户这轮同时在抱怨「黑色的阴影」，
   这里只留下让它从壁纸上浮起来的那一点。 */
.w-mode-shape{
  position:absolute;
  inset:0;
  background:
    /* 圆里那点「更实」的调子。第六轮后半：用户说这块「会透橙色的光，
       可以改成也是灰蓝色」—— 暖色整条拿掉，改用**跟图标同一支**冷灰蓝
       （--tk-c，就是图标背光面那支），两个控件才是同一个玻璃家族。
       范围 30%×62%、衰减 88%：早先收到 76% 时会在圆里缩成一小团斑，
       看着像沾了脏东西，铺开才像玻璃本身的颜色。 */
    radial-gradient(30% 62% at 22% 50%,
      var(--tk-c) 0%, rgba(255,255,255,0) 88%),
    linear-gradient(168deg,
      rgba(255,255,255,.58) 0%,
      rgba(246,249,255,.34) 46%,
      rgba(238,244,253,.42) 100%);
  backdrop-filter:blur(18px) saturate(150%) brightness(1.06);
  -webkit-backdrop-filter:blur(18px) saturate(150%) brightness(1.06);
  -webkit-mask-size:100% 100%;
  mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;
  mask-repeat:no-repeat;
  /* 投影只能靠 filter 的 drop-shadow 打 —— 形状不是方框，
     box-shadow 只会沿着元素自己的盒子走，跟轮廓完全对不上。 */
  filter:drop-shadow(0 6px 14px rgba(64,76,104,.15));
  pointer-events:none;
}

.w-mode-sw{
  position:absolute;
  /* 38%：开关的中心落在左边那个圆的右半部，和参考图一致。
     放在整盒正中（50%）的话会被圆和长条的接缝切开。 */
  left:38%;
  top:50%;
  transform:translate(-50%,-50%);
  width:46px;
  height:26px;
  border-radius:13px;
  background:var(--mode-track);
  border:1px solid var(--tk-line);
  box-shadow:
    inset 0 1.5px 3px var(--mode-track-inset),
    inset 0 -1px 1px rgba(255,255,255,.55);
  transition:background .24s var(--ease),box-shadow .24s var(--ease);
}
.w-mode-knob{
  position:absolute;
  left:2px;
  top:2px;
  width:20px;
  height:20px;
  border-radius:50%;
  background:linear-gradient(180deg,rgba(255,255,255,.94),rgba(255,255,255,.74));
  box-shadow:
    0 1px 3px rgba(46,56,80,.26),
    0 3px 8px -2px rgba(46,56,80,.28),
    inset 0 1px 1px rgba(255,255,255,.95);
  transition:transform .24s var(--ease);
}
.w-mode.is-on .w-mode-knob{transform:translateX(18px);}
/* 开启态：走 accent → accent-deep 的竖向渐变（上亮下暗＝一颗圆润的胶囊）。
   原来用的是 accent → accent-soft，而 night 主题的 accent-soft 是**深**绿，
   渐变会从亮绿直接掉到暗绿，看着脏。 */
.w-mode.is-on .w-mode-sw{
  background:linear-gradient(180deg,var(--g-accent) 0%,var(--g-accent-deep) 100%);
  border-color:rgba(255,255,255,.72);
  box-shadow:
    inset 0 1.5px 3px rgba(0,0,0,.14),
    inset 0 -1px 2px rgba(255,255,255,.42),
    0 4px 12px -4px rgba(46,56,80,.30);
}
.w-mode:active .w-mode-knob{transform:scale(.94);}
.w-mode.is-on:active .w-mode-knob{transform:translateX(18px) scale(.94);}
/* 字落在右边那根长条上，不是整个盒子的正中 —— 盒子左边一大半是圆，
   居中会被圆吃掉。左边 52% 起、右边留 5%，中间对齐。 */
.w-mode-label{
  position:absolute;
  left:52%;
  right:5%;
  top:50%;
  transform:translateY(-50%);
  text-align:center;
  font-size:13px;
  letter-spacing:.06em;
  color:var(--g-ink);
}

/* ---------------- 亚克力挂件灯（第 2 屏主件） ----------------
   这一格**不能有玻璃底** —— 它自己就是一盏会发光的 3D 物件，
   底下再垫一层玻璃只会把它压住。所以背景/边框/投影/backdrop 全部让掉，
   和 .w-app / .w-hdr / .w-mode 同一套「把 .widget 的材质关掉」的写法。 */
.w-lamp{
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
  padding:0;
  cursor:default;
  align-items:stretch;
  justify-content:stretch;
}
.w-lamp::before{display:none;}

/* 核心会把 canvas 铺满这个容器，所以它必须有确定的尺寸 */
.w-lamp-host{
  flex:1;
  min-width:0;
  min-height:0;
  position:relative;
}
.w-lamp-host canvas{display:block;}

/* 「点亮中…」/失败提示。核心接管之后会隐藏。 */
.w-lamp-note{
  position:absolute;
  left:0;right:0;bottom:16px;
  text-align:center;
  font-size:12px;
  letter-spacing:.08em;
  color:var(--g-ink-3);
  pointer-events:none;
}
.w-lamp-note.is-bad{color:#B4633A;}

/* ---- 放大态：整个浮到所有层上面 ----
   用户要求「点击之后就出现在所有层的上面」。做法是直接把它变成
   fixed 全屏，而不是把 canvas 搬到别处去（搬 canvas 会触发重取景、闪一下）。

   **为什么 fixed 只盖住手机、不会铺满整个浏览器窗口**：
   `.page` 上有 `transform:translateX(0)`，带 transform 的元素就是 fixed 后代的
   包含块 —— 于是 inset:0 等于「一块手机屏」，正好是我们要的范围。
   ⚠️ 哪天把 .page 的 transform 去掉，这里会立刻变成铺满整个浏览器窗口。

   z-index 40 是为了压过第 5 屏的底栏（.dt-dock z-index 6）和页码点（5）。 */
.w-lamp.is-focus{
  position:fixed;
  inset:0;
  z-index:40;
  border-radius:0;
}

/* ---- 触摸：**桌面态也交给灯** ----
   第一版只在放大态设 none（想让第 2 屏的手指横滑照样能翻页），用户否掉了：
   「桌面态不吃手势的话，感觉会影响 user 转这个 3d 模型」——
   这盏灯本来就是个可以扒拉着看的东西，滑到第 2 屏第一反应就是去转它，
   转不动反而更别扭。
   现在 canvas 上常驻 touch-action:none：
     · 手指落在灯上 → 转灯（拖 = 转视角；点卡 = 拿起来放大）
     · 要翻第 2 屏 → 从灯以外的空白、或下面那排 App 上划
   核心自己的承诺是不成立的（实测 canvas 上是 auto，源码里只有一行注释
   说它「设了」），所以这条必须我们写。 */
.w-lamp-host canvas{touch-action:none;}

/* ---------------- 音乐卡（第 3 屏主件） ----------------
   用户给的参考是一张深紫黑星空的横版播放卡，要求「不要这个颜色，
   但是大概长这样，做好看点」。所以**版式照抄、材质整套换成我们的**：
   封面做成一块暖色圆胶（奶油底 + 焦糖螺线），按钮和进度条都是玻璃。

   封面尺寸**只由宽度定**（36% + aspect-ratio:1），不能写 height:100%：
   格子在不同屏幕上高度会缩，height:100% 时封面会把右边那列挤成负宽度。
   宽度驱动的写法在极小屏上也只是等比缩小，撑不破。 */
/* 2026-09-18 第九版改动：**这张卡不要外框**。
   用户原话「音乐卡不要框，框住了就不好看了」—— 加了玻璃底之后，
   封面那块圆盘被框在里面，读成了「一张卡片里贴了张图」；
   去掉底之后封面和文字直接落在壁纸上，那圈螺旋才有「浮着」的感觉。
   （同 .w-hdr / .w-lamp / .w-todo 那一套：!important 压掉 .widget 的材质 +
   关掉 ::before。）
   连带后果：卡里的字现在压在壁纸上，必须挂 --ink-halo 那圈光晕。 */
.w-music{
  flex-direction:row;
  align-items:center;
  gap:calc(var(--dt-cell) * .20);
  padding:calc(var(--dt-cell) * .06) 0;
  cursor:default;
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
}
.w-music::before{display:none;}
.w-music-title,
.w-music-artist,
.w-music-state,
.w-music-time,
.w-music-mode{
  text-shadow:var(--ink-halo);
}
.w-music-cover{
  position:relative;
  flex:0 0 auto;
  width:36%;
  aspect-ratio:1;
  max-height:100%;
  border-radius:50%;
  overflow:hidden;
  /* 2026-09-18 第十一轮：把**最下面那圈棕色**拿掉。
     用户原话「这个的最下面棕色那层感觉去掉会好看些」。
     那圈棕是两样东西叠出来的，两个都要收：
       · 渐变外圈的停靠色 #E7CEAA —— 而且圆心偏在 32% 26%，
         所以右下方离圆心最远、正好落到最暗那一档，底部就糊出一片棕；
       · 底部那道 inset 阴影 rgba(150,118,78,.16)，专门往底边压暗。
     现在渐变圆心挪回中间偏上一点、外圈只到 #F7EBDC（几乎就是奶油），
     底部那道 inset 直接删掉 —— 圆盘的边交给外面那层投影去交代。 */
  background:
    radial-gradient(42% 42% at 50% 46%, rgba(255,255,255,.92) 0%, rgba(255,255,255,0) 72%),
    radial-gradient(82% 82% at 50% 44%,
      #FFFEFA 0%, #FDF8F0 46%, #FAF1E4 82%, #F7EBDC 100%);
  box-shadow:
    inset 0 1px 1px rgba(255,255,255,.95),
    0 5px 14px -6px rgba(126,112,94,.22);
}
.w-music-cover svg{position:absolute;inset:0;width:100%;height:100%;}
/* 四道螺旋臂：颜色和粗细都由 JS 内联写进去（见 MUSIC_ARMS），
   这里只定公共的描边属性。round 线帽让每道臂的两头是圆的，
   不然从圆心长出来的那一端会是方口。 */
.w-music-arm{
  fill:none;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.w-music-star{fill:rgba(255,253,247,.92);}
.w-music-hub{fill:rgba(255,252,246,.92);stroke:rgba(176,138,94,.32);stroke-width:.6;}
.w-music-hub-dot{fill:rgba(176,138,94,.55);}
/* 斜向那道高光：让它像一块有厚度的盘，而不是一张画 */
.w-music-sheen{
  position:absolute;inset:0;z-index:1;
  background:linear-gradient(145deg,
    rgba(255,255,255,.55) 0%, rgba(255,255,255,0) 44%, rgba(255,255,255,.30) 100%);
  pointer-events:none;
}
/* 播放时慢慢转 —— 唱片该有的样子。系统开了「减少动态效果」就不转。 */
.w-music.is-playing .w-music-cover svg{animation:w-music-spin 16s linear infinite;}
@keyframes w-music-spin{to{transform:rotate(360deg);}}
@media (prefers-reduced-motion: reduce){
  .w-music.is-playing .w-music-cover svg{animation:none;}
}

.w-music-main{
  flex:1;
  min-width:0;
  display:flex;
  flex-direction:column;
  justify-content:center;
}
.w-music-title{
  font-family:var(--ff-serif);
  font-size:calc(var(--dt-cell) * .205);
  font-weight:600;
  line-height:1.25;
  letter-spacing:.01em;
  color:var(--g-ink);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.w-music-artist{
  margin-top:2px;
  font-size:12px;
  letter-spacing:.10em;
  color:var(--g-ink-2);
}
.w-music-state{
  margin-top:1px;
  font-size:10.5px;
  letter-spacing:.22em;
  color:var(--g-ink-3);
}

/* 一排圆玻璃按钮。播放键那颗用主色填满，是全卡唯一的实色。 */
.w-music-ctrl{
  display:flex;
  align-items:center;
  gap:calc(var(--dt-cell) * .15);
  margin-top:calc(var(--dt-cell) * .10);
}
.w-music-btn{
  display:flex;
  align-items:center;
  justify-content:center;
  width:calc(var(--dt-cell) * .38);
  height:calc(var(--dt-cell) * .38);
  padding:0;
  border-radius:50%;
  border:1px solid var(--tk-line);
  background:linear-gradient(180deg,rgba(255,255,255,.70),rgba(244,248,255,.44));
  color:var(--g-ink);
  cursor:pointer;
  box-shadow:
    0 2px 6px -2px rgba(46,56,80,.22),
    inset 0 1px 1px rgba(255,255,255,.92);
  transition:transform .16s var(--ease);
  -webkit-tap-highlight-color:transparent;
}
.w-music-btn svg{display:block;width:17px;height:17px;}
.w-music-btn:active{transform:scale(.9);}
.w-music-play{
  width:calc(var(--dt-cell) * .48);
  height:calc(var(--dt-cell) * .48);
  color:var(--on-accent);
  border-color:rgba(255,255,255,.55);
  background:linear-gradient(180deg,var(--g-accent),var(--g-accent-deep));
  box-shadow:
    0 5px 14px -5px rgba(120,95,60,.55),
    inset 0 1px 1px rgba(255,255,255,.45);
}

.w-music-bar{
  display:flex;
  align-items:center;
  gap:9px;
  margin-top:calc(var(--dt-cell) * .09);
}
.w-music-time{
  flex:0 0 auto;
  font-size:10.5px;
  font-variant-numeric:tabular-nums;
  letter-spacing:.04em;
  color:var(--g-ink-3);
}
.w-music-track{
  position:relative;
  flex:1;
  min-width:0;
  height:4px;
  border-radius:2px;
  background:rgba(176,138,94,.18);
  box-shadow:inset 0 1px 2px rgba(120,95,60,.18);
}
.w-music-fill{
  position:absolute;
  left:0;top:0;bottom:0;
  border-radius:2px;
  background:linear-gradient(90deg,var(--g-accent),var(--g-accent-deep));
  /* 一秒走一格、过渡 0.9 秒 —— 拼起来是连续爬行，不是一格一格跳 */
  transition:width .9s linear;
}
.w-music-knob{
  position:absolute;
  top:50%;
  width:9px;
  height:9px;
  margin-left:-4.5px;
  transform:translateY(-50%);
  border-radius:50%;
  background:#fff;
  box-shadow:0 1px 3px rgba(120,95,60,.45), 0 0 0 1px rgba(176,138,94,.22);
  transition:left .9s linear;
}
.w-music-mode{
  align-self:flex-end;
  margin-top:calc(var(--dt-cell) * .04);
  font-size:10.5px;
  letter-spacing:.16em;
  color:var(--g-ink-3);
}

/* ---------------- 角色卡 ---------------- */

.w-char{
  cursor:pointer;
  text-align:center;
  padding:8px;
}
.w-char-av{
  width:54px;
  height:54px;
  border-radius:50%;
  object-fit:cover;
  margin-bottom:7px;
  border:2px solid rgba(255,255,255,.92);
  box-shadow:0 4px 12px rgba(139,108,76,.18);
  background:var(--g-glass-2);
}
.w-char-initial{
  display:flex;
  align-items:center;
  justify-content:center;
  font-size:20px;
  font-weight:700;
  color:var(--g-accent-deep);
}
.w-char-name{
  font-size:13.5px;
  font-weight:700;
  color:var(--g-ink);
  max-width:100%;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.w-char-status{
  margin-top:4px;
  font-size:10.5px;
  color:var(--g-accent-deep);
  background:rgba(255,255,255,.66);
  border-radius:10px;
  padding:2px 8px;
  max-width:100%;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

/* ---------------- 情绪印章 ---------------- */

.w-mood{
  cursor:pointer;
  text-align:center;
  padding:10px;
}
.w-label{
  font-size:10px;
  font-weight:700;
  letter-spacing:1.4px;
  color:var(--g-ink-3);
  margin-bottom:6px;
}
.w-mood-ic{line-height:0;color:var(--g-accent-deep);}
.w-mood-ic svg{display:block;width:30px;height:30px;}
.w-mood-text{
  margin-top:8px;
  font-size:12px;
  font-weight:600;
  color:var(--g-ink);
}

/* ---------------- 时间 ---------------- */

.w-clock{
  flex-direction:row;
  gap:12px;
  padding:0 16px;
}
.w-clock-time{font-size:24px;font-weight:800;letter-spacing:-1px;color:var(--g-ink);}
.w-clock-date{
  display:flex;
  flex-direction:column;
  gap:2px;
  font-size:10.5px;
  color:var(--g-ink-2);
}

/* ---------------- 思念电量 ---------------- */

.w-battery{
  justify-content:center;
  padding:0 16px;
  cursor:pointer;
  align-items:stretch;
}
.w-bat-head{
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  font-size:11px;
  font-weight:700;
  color:var(--g-ink);
  margin-bottom:6px;
}
.w-bat-hint{font-weight:400;color:var(--g-accent-deep);}
.w-bat-track{
  width:100%;
  height:12px;
  border-radius:6px;
  background:rgba(139,108,76,.13);
  overflow:hidden;
  box-shadow:inset 0 1px 3px rgba(139,108,76,.10);
}
.w-bat-fill{
  height:100%;
  border-radius:6px;
  background:linear-gradient(90deg,var(--g-accent) 0%,var(--g-accent-soft) 100%);
  transition:width .3s var(--ease);
}

/* ---------------- 双城时间 ---------------- */

.w-worldclock{
  flex-direction:row;
  align-items:center;
  justify-content:space-around;
  padding:0 12px;
}
.w-wc-inner{display:flex;flex-direction:column;align-items:center;}
.w-wc-time{font-size:26px;font-weight:300;color:var(--g-ink);letter-spacing:-.5px;}
.w-wc-city{margin-top:4px;font-size:11px;color:var(--g-ink-2);}
.w-wc-divider{width:1px;height:52%;background:var(--g-glass-line);}

/* ---------------- 播放中 ---------------- */

.w-player{gap:8px;}
.w-player-ic{line-height:0;color:var(--g-accent-deep);}
.w-player-ic svg{display:block;width:30px;height:30px;}
.w-player-text{font-size:10.5px;font-weight:700;color:var(--g-ink);}

/* ---------------- 日历 ---------------- */

.w-calendar{
  flex-direction:row;
  padding:18px;
  border-radius:28px;
  gap:14px;
}
.w-cal-left{
  flex:1;
  display:flex;
  flex-direction:column;
  justify-content:center;
  min-width:0;
}
.w-cal-lunar{font-size:10.5px;font-weight:700;color:var(--g-ink-2);margin-bottom:8px;}
.w-cal-big{font-size:42px;font-weight:800;letter-spacing:-2px;line-height:1;color:var(--g-ink);}
.w-cal-dayrow{display:flex;align-items:baseline;gap:6px;margin-top:8px;}
.w-cal-day{font-size:26px;font-weight:300;color:var(--g-ink);}
.w-cal-ym{display:flex;flex-direction:column;gap:1px;font-size:10px;color:var(--g-ink-2);}
.w-cal-ym .is-accent{color:var(--g-accent-deep);font-weight:700;}

.w-cal-grid{
  flex:1.25;
  display:grid;
  grid-template-columns:repeat(7,1fr);
  gap:3px;
  font-size:9.5px;
  text-align:center;
  font-weight:600;
  color:var(--g-ink-2);
  align-content:center;
  min-width:0;
}
.w-cal-grid > div{padding:3px 0;border-radius:50%;}
.w-cal-head{color:var(--g-ink-3);}
.w-cal-today{
  background:var(--g-accent);
  color:#fff;
  box-shadow:0 4px 8px rgba(111,184,106,.42);
}

/* ---------------- 待办 ---------------- */

/* 2026-09-18：待办不再是一张玻璃卡 —— 用户要的是「不要圆角框框，
   换成直接在页面上面的」。所以把 .widget 的整套材质关掉，
   标题和条目直接落在壁纸上（做法同 .w-hdr / .w-lamp）。
   连带后果：里面的字现在压在壁纸上，必须挂上 --ink-halo 那圈光晕，
   否则换深色壁纸会整片看不见。 */
.w-todo{
  justify-content:flex-start;
  align-items:stretch;
  padding:0;
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
}
.w-todo::before{display:none;}
.w-todo-head,
.w-todo-title,
.w-todo-count,
.w-todo-text,
.w-todo-empty-text,
.w-todo-empty-hint,
.w-todo-add{
  text-shadow:var(--ink-halo);
}
/* 条目自己的悬停底也去掉 —— 留着就是一块块小方框 */
.w-todo-item:hover{background:none;}
.w-todo-item:hover .w-todo-text{color:var(--g-accent-deep);}
/* 行内编辑时的输入框：一根下划线就够，不做成输入框的样子 */
.w-todo-input{
  flex:1;
  min-width:0;
  font:inherit;
  font-size:13px;
  color:var(--g-ink);
  background:none;
  border:0;
  border-bottom:1px solid var(--g-accent);
  outline:none;
  padding:0 0 1px;
}
.w-todo-input::selection{background:var(--g-accent-soft);}
.w-todo-head{
  display:flex;
  align-items:center;
  gap:8px;
  margin-bottom:12px;
}
.w-todo-title{
  display:flex;
  align-items:center;
  gap:6px;
  font-size:12px;
  font-weight:700;
  color:var(--g-ink);
}
.w-todo-ic{line-height:0;color:var(--g-ink-2);}
.w-todo-ic svg{display:block;width:14px;height:14px;}
.w-todo-count{
  margin-left:auto;
  font-size:10px;
  font-weight:600;
  color:var(--g-ink-3);
  font-variant-numeric:tabular-nums;
}
.w-todo-list{
  flex:1;
  min-height:0;
  overflow-y:auto;
  display:flex;
  flex-direction:column;
  gap:2px;
  /* 列表自己滚，滚出容器时不留切边毛刺 */
  overscroll-behavior:contain;
}
.w-todo-item{
  display:flex;
  align-items:center;
  gap:8px;
  font-size:11px;
  color:var(--g-ink-2);
  padding:5px 6px;
  margin:0 -6px;
  border-radius:8px;
  cursor:pointer;
  transition:background .14s var(--ease);
}
.w-todo-item:hover{background:rgba(255,255,255,.55);}
.w-todo-item.is-done{color:var(--g-ink-3);}
.w-todo-item.is-done .w-todo-text{text-decoration:line-through;}

/* 勾选框是个真按钮：单独的热区，不和「点行编辑」抢事件 */
.w-todo-box{
  flex:none;
  width:15px;height:15px;
  padding:0;
  border:1.5px solid rgba(139,108,76,.30);
  border-radius:4.5px;
  background:rgba(255,255,255,.5);
  position:relative;
  cursor:pointer;
  transition:background .14s var(--ease),border-color .14s var(--ease);
}
.w-todo-box:hover{border-color:var(--g-accent);}
.w-todo-box.is-done{background:var(--g-accent);border-color:var(--g-accent);}
.w-todo-box.is-done::after{
  content:"";
  position:absolute;
  left:3.5px;top:.5px;
  width:3.5px;height:7.5px;
  border:solid #fff;
  border-width:0 1.5px 1.5px 0;
  transform:rotate(45deg);
}
.w-todo-text{
  flex:1;min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* 删除键平时隐形，hover / 触摸时才浮出来 —— 免得列表看着像一排叉 */
.w-todo-del{
  flex:none;
  width:18px;height:18px;
  padding:0;
  border:0;
  background:none;
  color:var(--g-ink-3);
  line-height:0;
  cursor:pointer;
  opacity:0;
  transition:opacity .14s var(--ease),color .14s var(--ease);
}
.w-todo-del svg{display:block;width:14px;height:14px;}
.w-todo-item:hover .w-todo-del{opacity:1;}
.w-todo-del:hover{color:var(--g-warn);}
/* 触屏没有 hover，靠 active 兜底 */
@media (hover:none){
  .w-todo-del{opacity:.5;}
}

.w-todo-empty{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:2px;
  padding:8px 0;
}
.w-todo-empty-text{font-size:11px;color:var(--g-ink-3);margin:0;}
.w-todo-empty-hint{font-size:10px;color:var(--g-ink-3);opacity:.72;margin:0;}

/* 「加一条」原本是一个虚线圆角框。待办整块去掉外框之后，
   这个小方框反而成了整屏唯一一个框 —— 和「直接落在页面上」打架。
   现在收成一行朴素的文字 + 加号，左对齐，跟条目同一列。
   （用户第九版：「不要圆角框框，换成直接在页面上面的」） */
.w-todo-add{
  flex:none;
  margin-top:10px;
  display:flex;
  align-items:center;
  justify-content:flex-start;
  gap:6px;
  padding:3px 0;
  border:0;
  border-radius:0;
  background:none;
  color:var(--g-ink-3);
  font-family:inherit;
  font-size:11.5px;
  font-weight:600;
  letter-spacing:.04em;
  cursor:pointer;
  transition:color .14s var(--ease);
}
.w-todo-add svg{display:block;width:16px;height:16px;}
.w-todo-add:hover{
  color:var(--g-accent-deep);
  background:none;
  border-color:var(--g-accent);
}

/* ---------------- 照片墙（第 0 屏，占满整屏） ----------------
   2026-09-18 第十三版：按用户参考图重排。
   场记板放大 + 板面内框；胶片盘换成竖胶片条；
   相框改成**固定网格模板**（6 列 × 4 行写死），没有胶带、没有旋转 ——
   「贴上去的」改成「装在版式里的」。
   组件本身仍不带玻璃底：一整面海报再套圆角卡就不是海报了。 */
.w-wall{
  position:relative;
  width:100%;
  height:100%;
  display:flex;
  flex-direction:column;
  /* ⚠️ 必须显式 stretch：.widget 基类带着 align-items:center，
     不重置的话纵向 flex 的子项全部缩成内容宽 —— 空态提示
     实测缩到 12px，一个字一行竖着排。 */
  align-items:stretch;
  padding:0;
  overflow:visible;
  cursor:default;
  background:none !important;
  border:0 !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
}
.w-wall::before{display:none;}

/* ---- 顶带：场记板 + 胶片条 ---- */
.w-wall-top{
  flex:0 0 auto;
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
}

/* ---- 场记板（照参考图放大） ----
   木牌走焦糖最深的一档。它整屏只有这一块重色，是唯一的重音。
   参考图的板面里有一圈细白内框 —— 「板」的辨识度就在这圈框上。 */
.w-wall-clap{
  position:relative;
  width:62%;
}
.w-wall-clap-bar{
  position:relative;
  z-index:2;
  height:calc(var(--dt-cell) * .32);
  /* 斜纹 58° 而不是 45°：跟参考图的斜度走，也更不像警示条 */
  background:repeating-linear-gradient(58deg,
    #7A5C38 0 9px, #FBF3E7 9px 18px);
  border-radius:5px 5px 2px 2px;
  transform:rotate(-2deg);
  transform-origin:left bottom;
  box-shadow:0 2px 5px -2px rgba(120,95,60,.40);
}
.w-wall-clap-body{
  position:relative;
  margin-top:calc(var(--dt-cell) * .07);
  padding:calc(var(--dt-cell) * .15) calc(var(--dt-cell) * .17);
  border-radius:4px;
  background:linear-gradient(168deg,#6E5334 0%,#453322 100%);
  box-shadow:
    0 7px 18px -7px rgba(70,52,30,.60),
    inset 0 1px 1px rgba(255,255,255,.16);
  color:#FBF3E7;
}
.w-wall-clap-frame{
  position:absolute;
  inset:6px;
  border:1px solid rgba(251,243,231,.32);
  border-radius:2px;
  pointer-events:none;
}
.w-wall-clap-cut{
  font-family:var(--ff-serif);
  font-size:calc(var(--dt-cell) * .46);
  font-weight:700;
  line-height:1;
  letter-spacing:.03em;
  /* 印刷体的压痕感：一道下影 + 一点暖光，不要做成发光字 */
  text-shadow:0 2px 0 rgba(0,0,0,.35), 0 0 16px rgba(255,240,210,.14);
}
.w-wall-clap-scene{
  display:flex;
  align-items:center;
  gap:7px;
  margin-top:calc(var(--dt-cell) * .07);
  padding-top:calc(var(--dt-cell) * .055);
  border-top:1px solid rgba(251,243,231,.28);
  font-size:10px;
  letter-spacing:.24em;
  opacity:.88;
}
.w-wall-clap-no{margin-left:auto;letter-spacing:.10em;}

/* ---- 竖胶片条：齿孔 + 三个格，线稿 ----
   （原来那个两圈圆孔的胶片盘被用户否了：「右边那个太丑了」。） */
.w-wall-strip{
  flex:0 0 auto;
  width:calc(var(--dt-cell) * .64);
  height:calc(var(--dt-cell) * 1.5);
  margin-top:calc(var(--dt-cell) * .06);
  filter:drop-shadow(0 4px 10px -4px rgba(120,95,60,.35));
}
.w-wall-strip svg{display:block;width:100%;height:100%;}
.w-wall-strip-body{fill:rgba(255,253,247,.55);stroke:rgba(176,138,94,.58);stroke-width:2.4;}
.w-wall-strip-frame{fill:rgba(233,207,171,.32);stroke:rgba(176,138,94,.50);stroke-width:1.4;}
.w-wall-strip-perf{fill:rgba(176,138,94,.40);}

/* ---- 固定模板的相框格 ----
   6 列 × 4 行，格子的 grid-area 由 JS 写死（见 SPOTS）。
   帧是「照片纸」：奶油底 + 内衬一圈白边（padding），照片 cover 填进去。 */
.w-wall-grid{
  position:relative;
  flex:1;
  min-height:0;
  margin-top:calc(var(--dt-cell) * .18);
  display:grid;
  grid-template-columns:repeat(6,1fr);
  grid-template-rows:repeat(4,1fr);
  gap:7px;
}
.w-wall-slot{
  position:relative;
  min-width:0;
  min-height:0;
  padding:3px;
  border:0;
  border-radius:3px;
  background:linear-gradient(178deg,#FFFEFA,#FBF4E8);
  box-shadow:
    0 6px 14px -7px rgba(120,95,60,.42),
    0 1px 2px rgba(120,95,60,.12);
  font-family:inherit;
  cursor:default;
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
  -webkit-tap-highlight-color:transparent;
}
.w-wall-slot-ph{
  display:block;
  width:100%;
  height:100%;
  border-radius:2px;
  background:linear-gradient(160deg,#F0E7D9,#E1D5C1);
  background-size:cover;
  background-position:center;
  box-shadow:inset 0 0 0 1px rgba(120,95,60,.10);
}
/* 空框：淡一点的纸 + 一个加号，点了选照片填进这个格 */
.w-wall-slot.is-empty{
  cursor:pointer;
  background:linear-gradient(178deg,#FDFAF3,#F7EFE1);
  box-shadow:
    inset 0 0 0 1px rgba(176,138,94,.18),
    0 4px 10px -6px rgba(120,95,60,.28);
  color:rgba(176,138,94,.55);
}
.w-wall-slot.is-empty svg{
  position:absolute;
  left:50%;top:50%;
  transform:translate(-50%,-50%);
}
.w-wall-slot.is-empty:active{transform:scale(.96);}
.w-wall-slot.is-empty:hover{
  color:var(--g-accent);
  box-shadow:
    inset 0 0 0 1px rgba(176,138,94,.30),
    0 5px 12px -6px rgba(120,95,60,.34);
}

/* ---- 底下那截「下一镜头」纸带 ----
   参考图里它是一条撕边的纸。左右两条边保持直、上下打毛 ——
   撕纸只该发生在**没有依靠的那两条边**上，四边都毛就成了一张脏纸。 */
.w-wall-next{
  flex:0 0 auto;
  align-self:center;
  display:flex;
  align-items:center;
  justify-content:center;
  min-width:54%;
  height:calc(var(--dt-cell) * .60);
  margin-top:calc(var(--dt-cell) * .16);
  padding:0 20px;
  border:0;
  background:linear-gradient(180deg,#FFFCF5,#F5E9D8);
  color:var(--g-ink-2);
  /* 花体：Windows 走 Segoe Script / Brush Script，mac 走 Snell Roundhand /
     Apple Chancery，都没有就退 italic serif —— 斜着的手写感还在，
     不会退化成正体衬线。别加 letter-spacing：花体的连笔靠字挨着字，
     拉开就断了。 */
  font-family:"Segoe Script","Brush Script MT","Snell Roundhand","Apple Chancery",cursive;
  font-style:italic;
  font-size:15.5px;
  letter-spacing:.02em;
  cursor:pointer;
  box-shadow:0 6px 16px -7px rgba(120,95,60,.40);
  -webkit-clip-path:polygon(0.00% 2.8%, 7.14% 2.8%, 14.29% 2.0%, 21.43% 3.2%, 28.57% 2.9%, 35.71% 1.1%, 42.86% 2.6%, 50.00% 1.0%, 57.14% 0.5%, 64.29% 2.6%, 71.43% 0.4%, 78.57% 1.9%, 85.71% 0.4%, 92.86% 0.7%, 100.00% 2.8%, 100.00% 98.9%, 92.86% 99.4%, 85.71% 97.3%, 78.57% 99.1%, 71.43% 99.2%, 64.29% 98.0%, 57.14% 98.4%, 50.00% 99.1%, 42.86% 99.3%, 35.71% 98.3%, 28.57% 96.8%, 21.43% 99.8%, 14.29% 99.5%, 7.14% 99.6%, 0.00% 97.9%);
  clip-path:polygon(0.00% 2.8%, 7.14% 2.8%, 14.29% 2.0%, 21.43% 3.2%, 28.57% 2.9%, 35.71% 1.1%, 42.86% 2.6%, 50.00% 1.0%, 57.14% 0.5%, 64.29% 2.6%, 71.43% 0.4%, 78.57% 1.9%, 85.71% 0.4%, 92.86% 0.7%, 100.00% 2.8%, 100.00% 98.9%, 92.86% 99.4%, 85.71% 97.3%, 78.57% 99.1%, 71.43% 99.2%, 64.29% 98.0%, 57.14% 98.4%, 50.00% 99.1%, 42.86% 99.3%, 35.71% 98.3%, 28.57% 96.8%, 21.43% 99.8%, 14.29% 99.5%, 7.14% 99.6%, 0.00% 97.9%);
  transition:transform .16s var(--ease), box-shadow .16s var(--ease);
}
.w-wall-next:active{transform:scale(.97);}
.w-wall-next:hover{
  color:var(--g-accent-deep);
  box-shadow:0 8px 20px -8px rgba(120,95,60,.50);
}

/* ---------------- 相册 ---------------- */

.gal-wrap{padding:2px 0 20px;}
.gal-day{margin-bottom:18px;}
.gal-day-head{
  display:flex;
  align-items:baseline;
  gap:8px;
  margin-bottom:8px;
  padding:0 2px;
}
.gal-day-name{
  font-size:12px;
  font-weight:700;
  color:var(--g-ink);
  font-variant-numeric:tabular-nums;
}
.gal-day-n{font-size:10px;color:var(--g-ink-3);}

.gal-grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:4px;
}
.gal-cell{
  position:relative;
  aspect-ratio:1;
  padding:0;
  border:0;
  border-radius:6px;
  background:rgba(139,108,76,.09);
  background-size:cover;
  background-position:center;
  cursor:pointer;
  overflow:hidden;
  transition:transform .16s var(--ease);
}
.gal-cell:active{transform:scale(.96);}
.gal-cell-cap{
  position:absolute;
  left:0;right:0;bottom:0;
  padding:8px 5px 4px;
  font-size:9px;
  color:#fff;
  text-align:left;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  background:linear-gradient(transparent,rgba(0,0,0,.44));
}

/* 占用进度条 */
.gal-foot{padding:4px 2px;}
.gal-foot-bar{
  height:3px;
  border-radius:2px;
  background:rgba(139,108,76,.14);
  overflow:hidden;
}
.gal-foot-fill{
  display:block;
  height:100%;
  border-radius:2px;
  background:var(--g-accent);
  transition:width .3s var(--ease);
}
.gal-foot-text{
  font-size:10px;
  color:var(--g-ink-3);
  margin:6px 0 0;
}

/* 右下角悬浮上传键 */
.gal-fab{
  position:absolute;
  right:18px;
  bottom:calc(env(safe-area-inset-bottom) + 20px);
  width:46px;height:46px;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:0;
  border-radius:50%;
  border:1px solid rgba(255,255,255,.6);
  background:var(--g-accent);
  color:#fff;
  line-height:0;
  cursor:pointer;
  box-shadow:0 6px 18px rgba(139,108,76,.34);
  transition:transform .16s var(--ease);
  z-index:4;
}
.gal-fab svg{display:block;width:20px;height:20px;}
.gal-fab:hover{transform:scale(1.06);}

/* 空态：整块可点的上传区 */
.gal-empty{
  display:flex;
  flex-direction:column;
  align-items:center;
  padding:14px 0 0;
}
.gal-empty-drop{
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:10px;
  padding:34px 20px 30px;
  border:1.5px dashed rgba(139,108,76,.28);
  border-radius:16px;
  background:rgba(255,255,255,.3);
  font-family:inherit;
  color:inherit;
  cursor:pointer;
  transition:border-color .18s var(--ease),background .18s var(--ease);
}
.gal-empty-drop:hover{
  border-color:var(--g-accent);
  background:rgba(255,255,255,.52);
}
.gal-empty-badge{
  width:66px;height:66px;
  display:flex;
  align-items:center;
  justify-content:center;
  border-radius:16px;
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
  color:var(--g-accent);
  transform:rotate(-3deg);
  transition:transform .2s var(--ease);
}
.gal-empty-badge svg{display:block;}
.gal-empty-drop:hover .gal-empty-badge{transform:rotate(0deg) scale(1.05);}
.gal-empty-title{
  font-size:14px;
  font-weight:700;
  color:var(--g-ink);
  margin:2px 0 0;
}
.gal-empty-hint{font-size:11.5px;color:var(--g-ink-3);margin:0;}

.gal-empty-tips{
  list-style:none;
  margin:20px 0 0;
  padding:0;
  width:100%;
  display:flex;
  flex-direction:column;
  gap:9px;
}
.gal-empty-tip{
  display:flex;
  align-items:flex-start;
  gap:8px;
  font-size:11px;
  line-height:1.5;
  color:var(--g-ink-3);
}
.gal-empty-dot{
  flex:none;
  width:4px;height:4px;
  margin-top:6px;
  border-radius:50%;
  background:var(--g-accent);
  opacity:.55;
}

/* ---------------- 大图查看器 ---------------- */

.pv-mask{
  position:absolute;
  inset:0;
  background:rgba(28,38,28,.62);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
  opacity:0;
  transition:opacity .22s var(--ease);
  z-index:40;
}
.pv-mask.is-open{opacity:1;}

.pv-wrap{
  position:absolute;
  inset:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:14px;
  padding:26px 20px 20px;
  opacity:0;
  transform:scale(.96);
  transition:opacity .24s var(--ease),transform .24s var(--ease);
  z-index:41;
  pointer-events:none;
}
.pv-wrap.is-open{opacity:1;transform:scale(1);pointer-events:auto;}

.pv-img{
  max-width:100%;
  max-height:60%;
  border-radius:10px;
  object-fit:contain;
  box-shadow:0 14px 40px rgba(0,0,0,.34);
}
.pv-meta{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:4px;
  max-width:100%;
}
.pv-cap{
  font-size:12.5px;
  color:#fff;
  text-align:center;
  line-height:1.55;
  word-break:break-word;
}
.pv-date{
  font-size:10px;
  color:rgba(255,255,255,.62);
  font-variant-numeric:tabular-nums;
}
.pv-bar{display:flex;gap:10px;}
.pv-close{
  position:absolute;
  top:14px;right:14px;
  width:32px;height:32px;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:0;
  border-radius:50%;
  border:1px solid rgba(255,255,255,.24);
  background:rgba(255,255,255,.12);
  color:#fff;
  line-height:0;
  cursor:pointer;
  transition:background .16s var(--ease);
}
.pv-close svg{display:block;width:18px;height:18px;}
.pv-close:hover{background:rgba(255,255,255,.24);}

/* 页码点 + Dock ---------------- */

.dt-dots{
  position:absolute;
  left:0;right:0;
  bottom:calc(env(safe-area-inset-bottom) + 96px);
  display:flex;
  justify-content:center;
  gap:8px;
  z-index:5;
  pointer-events:none;
}
.dt-dots .dt-dot{
  width:6px;height:6px;
  border-radius:50%;
  background:rgba(139,108,76,.22);
  transition:all .28s var(--ease);
  pointer-events:auto;
  cursor:pointer;
}
.dt-dots .dt-dot.is-on{
  background:var(--g-ink);
  width:14px;
  border-radius:3px;
}

.dt-dock{
  position:absolute;
  left:20px;right:20px;
  bottom:calc(env(safe-area-inset-bottom) + 14px);
  height:74px;
  display:flex;
  align-items:center;
  justify-content:space-around;
  padding:0 10px;
  border-radius:37px;
  background:var(--g-glass);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-ring),var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
  z-index:6;
}
.dt-dock-btn{
  flex:1;
  background:none;
  border:0;
  padding:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:4px;
  cursor:pointer;
  font-family:inherit;
  color:inherit;
}
/* 底栏图标和桌面图标是同一块玻璃（共用 .w-app-ic 那一段），只是小一号。
   2026-09-17 第二轮：原来这里是一根 26px 的裸线条，
   在白底 + 玻璃条上飘着；现在收进 46px 的玻璃方块里，跟网格里那排对上。 */
.dt-dock-ic{
  --tk:46px;
  color:var(--g-ink-2);
}
.dt-dock-ic svg{position:relative;width:21px;height:21px;z-index:1;}
.dt-dock-btn:active .dt-dock-ic{transform:scale(.93);}
/* dock 不带文字（2026-09-17 用户定调）：名字藏掉不是删掉 ——
   无障碍的 aria-label 在按钮上，留 DOM 结构省得以后改回来 */
.dt-dock-name{display:none;}
.dt-dock-btn{gap:0;}
.dt-dock-ic{color:var(--g-ink-2);}

/* ============================================================
   系统级切号（switcher）+ 面具轮盘（wheel）
   两者都是全局单例浮层，挂在 #phone 上 ——
   挂页面里的话，页面自身的滚动会把它们带着跑。
   ============================================================ */

.sw-mask,.wh-mask{
  position:absolute;inset:0;
  background:var(--scrim);
  z-index:90;
  opacity:0;
  transition:opacity .22s var(--ease);
  pointer-events:none;
}
.sw-mask.is-open,.wh-mask.is-open{opacity:1;pointer-events:auto;}

.sw-panel{
  position:absolute;
  left:12px;right:12px;
  bottom:calc(env(safe-area-inset-bottom) + 12px);
  max-height:76%;
  display:flex;
  flex-direction:column;
  padding:18px 18px 20px;
  border-radius:26px;
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:blur(30px);
  -webkit-backdrop-filter:blur(30px);
  z-index:91;
  transform:translateY(14px);
  opacity:0;
  transition:transform .26s var(--ease),opacity .26s var(--ease);
  pointer-events:none;
}
.sw-panel.is-open{transform:translateY(0);opacity:1;pointer-events:auto;}

.sw-head{display:flex;align-items:center;gap:10px;}
.sw-title{
  flex:1;
  margin:0;
  font-size:16px;
  font-weight:700;
  color:var(--g-ink);
}
.sw-close{
  flex:none;
  width:30px;height:30px;
  border-radius:50%;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  color:var(--g-ink-2);
  font-size:17px;line-height:1;
  cursor:pointer;
  font-family:inherit;
}
.sw-sub{margin:6px 0 14px;font-size:11.5px;color:var(--g-ink-3);line-height:1.6;}

.sw-body{overflow-y:auto;flex:1;min-height:0;}
.sw-section{margin-bottom:18px;}
.sw-section-title{
  margin:0 0 9px;
  font-size:10.5px;
  font-weight:700;
  letter-spacing:1.2px;
  color:var(--g-ink-3);
  text-transform:uppercase;
}
/* 两层切换的分段说明（09-19：换岛 vs 岛内身份，语义分开） */
.sw-section-sub{margin:-4px 0 10px;font-size:10px;color:var(--g-ink-3);line-height:1.6;}

/* 马甲横排 */
.sw-chips{display:flex;flex-wrap:wrap;gap:8px;}
.sw-chip{
  display:flex;align-items:center;gap:7px;
  padding:7px 12px 7px 8px;
  border-radius:22px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  color:var(--g-ink);
  font-family:inherit;
  font-size:12.5px;
  cursor:pointer;
}
.sw-chip.is-on{
  background:linear-gradient(135deg,var(--g-accent) 0%,var(--g-accent-deep) 100%);
  border-color:transparent;
  color:#fff;
  box-shadow:0 6px 16px rgba(139,108,76,.30);
}
.sw-chip-av{
  display:flex;align-items:center;justify-content:center;
  width:22px;height:22px;
  border-radius:50%;
  background:rgba(255,255,255,.78);
  color:var(--g-accent-deep);
  font-size:11px;font-weight:700;
}
.sw-chip-add{border-style:dashed;color:var(--g-ink-2);}

/* 角色分组 */
.sw-group{
  margin-bottom:10px;
  border-radius:16px;
  overflow:hidden;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
}
.sw-main{
  width:100%;
  display:flex;align-items:center;gap:10px;
  padding:11px 13px;
  background:none;border:0;
  font-family:inherit;text-align:left;
  cursor:pointer;
  color:var(--g-ink);
  border-bottom:1px solid var(--g-glass-line);
}
.sw-main.is-on{background:rgba(111,184,106,.13);}
.sw-av{
  flex:none;
  display:flex;align-items:center;justify-content:center;
  width:36px;height:36px;
  border-radius:50%;
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  font-size:14px;font-weight:700;
  color:var(--g-accent-deep);
}
.sw-av-sub{width:30px;height:30px;font-size:12px;opacity:.9;}
.sw-main-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.sw-main-name{
  font-size:13.5px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sw-main-sub{font-size:11px;color:var(--g-ink-3);}
.sw-cur{
  flex:none;
  font-size:10px;
  padding:2px 8px;
  border-radius:9px;
  background:var(--g-accent);
  color:#fff;
}
.sw-sub-item{
  width:100%;
  display:flex;align-items:center;gap:10px;
  padding:9px 13px 9px 26px;
  background:none;border:0;
  border-bottom:1px solid var(--g-glass-line);
  font-family:inherit;text-align:left;
  cursor:pointer;
  color:var(--g-ink);
  position:relative;
}
.sw-sub-item:last-child{border-bottom:0;}
.sw-sub-item:active{background:var(--g-glass-2);}
/* 缩进的那道竖线：表达「这是挂在上面那个大号名下的」 */
.sw-sub-item::before{
  content:"";
  position:absolute;
  left:14px;top:0;bottom:0;
  width:1px;
  background:var(--g-glass-line);
}
.sw-note{margin:10px 0 0;font-size:11px;color:var(--g-ink-3);line-height:1.65;}

.sw-empty{
  display:flex;flex-direction:column;align-items:center;
  gap:8px;padding:28px 10px;text-align:center;
}
.sw-empty-text{margin:0;font-size:13px;color:var(--g-ink-2);}
.sw-empty-hint{margin:0;font-size:11.5px;color:var(--g-ink-3);}

/* ---------------- 面具轮盘 ---------------- */

.wh-panel{
  position:absolute;
  left:50%;
  top:50%;
  width:min(320px,84%);
  padding:18px;
  border-radius:24px;
  background:var(--g-glass-2);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:blur(30px);
  -webkit-backdrop-filter:blur(30px);
  z-index:91;
  transform:translate(-50%,-50%) scale(.94);
  opacity:0;
  transition:transform .24s var(--ease),opacity .24s var(--ease);
  pointer-events:none;
  display:flex;
  flex-direction:column;
  gap:12px;
}
.wh-panel.is-open{transform:translate(-50%,-50%) scale(1);opacity:1;pointer-events:auto;}
.wh-title{margin:0;font-size:15px;font-weight:700;color:var(--g-ink);text-align:center;}
.wh-sub{margin:0;font-size:11.5px;color:var(--g-ink-3);text-align:center;}
.wh-list{display:flex;flex-direction:column;gap:7px;max-height:52vh;overflow-y:auto;}
.wh-item{
  display:flex;align-items:center;gap:10px;
  padding:9px 11px;
  border-radius:14px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  font-family:inherit;text-align:left;
  cursor:pointer;
  color:var(--g-ink);
}
.wh-item.is-on{
  border-color:var(--g-accent);
  background:rgba(111,184,106,.14);
}
.wh-av{
  flex:none;
  display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;
  border-radius:50%;
  background:var(--g-glass-3);
  color:var(--g-accent-deep);
  font-size:13px;font-weight:700;
}
.wh-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.wh-name{font-size:13px;font-weight:600;}
.wh-desc{font-size:10.5px;color:var(--g-ink-3);}
.wh-cur{
  flex:none;font-size:10px;
  padding:2px 7px;border-radius:9px;
  background:var(--g-accent);color:#fff;
}

/* ============================================================
   名片夹树状层级 + 认知矩阵 + 记忆库
   ============================================================ */

.idc-list{padding-bottom:80px;}
.idc-tool{
  width:100%;
  display:flex;align-items:center;gap:11px;
  padding:12px 14px;
  margin-bottom:10px;
  border-radius:16px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
  font-family:inherit;text-align:left;
  cursor:pointer;color:var(--g-ink);
}
.idc-tool:active{background:var(--g-glass-2);}
.idc-tool-ic{flex:none;font-size:17px;line-height:1;}
.idc-tool-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.idc-tool-title{font-size:13.5px;font-weight:600;}
.idc-tool-sub{font-size:11px;color:var(--g-ink-3);}
.idc-tool-arrow{flex:none;font-size:17px;color:var(--g-ink-3);line-height:1;}

.idc-tree{
  margin-bottom:14px;
  padding:4px 0 8px;
  border-radius:18px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  box-shadow:var(--g-glass-shadow);
  backdrop-filter:var(--g-glass-blur);
  -webkit-backdrop-filter:var(--g-glass-blur);
  overflow:hidden;
}
.idc-main{
  display:flex;align-items:center;gap:11px;
  padding:12px 14px;
  cursor:pointer;
  border-bottom:1px solid var(--g-glass-line);
}
.idc-main.is-active{background:rgba(111,184,106,.12);}
.idc-main-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}
.idc-name-row{display:flex;align-items:center;gap:7px;}
.idc-name{
  font-size:14px;font-weight:700;color:var(--g-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.idc-kind{
  flex:none;
  font-size:9.5px;font-weight:700;
  padding:2px 7px;border-radius:8px;
}
.idc-kind-main{background:rgba(111,184,106,.20);color:var(--g-accent-deep);}
.idc-kind-sub{background:rgba(92,134,168,.16);color:var(--mist);}
.idc-kind-npc{background:rgba(185,145,63,.16);color:var(--gold);}
.idc-cur{
  flex:none;font-size:9.5px;
  padding:2px 7px;border-radius:8px;
  background:var(--g-accent);color:#fff;
}
.idc-line{
  font-size:11px;color:var(--g-ink-3);line-height:1.5;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.idc-av{
  flex:none;
  display:flex;align-items:center;justify-content:center;
  width:42px;height:42px;
  border-radius:50%;
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  font-size:15px;font-weight:700;
  color:var(--g-accent-deep);
}
.idc-av-sub{width:34px;height:34px;font-size:13px;}

.idc-branch{
  width:100%;
  display:flex;align-items:center;gap:11px;
  padding:10px 14px 10px 30px;
  background:none;border:0;
  border-bottom:1px solid var(--g-glass-line);
  font-family:inherit;text-align:left;
  cursor:pointer;color:var(--g-ink);
  position:relative;
}
.idc-branch:active{background:var(--g-glass-2);}
/* 枝干那道线：一眼看出「挂在上面那个大号名下」 */
.idc-branch-line{
  position:absolute;
  left:20px;top:0;bottom:0;
  width:1px;
  background:var(--g-glass-line);
}
.idc-branch-line::after{
  content:"";
  position:absolute;
  top:50%;left:0;
  width:7px;height:1px;
  background:var(--g-glass-line);
}
.idc-branch-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}

.idc-add-row{display:flex;gap:8px;padding:10px 14px 4px;}
.idc-add-btn{
  flex:1;
  padding:8px 10px;
  border-radius:11px;
  border:1px dashed var(--g-glass-edge);
  background:transparent;
  color:var(--g-ink-2);
  font-family:inherit;
  font-size:11.5px;
  cursor:pointer;
}
.idc-add-btn:active{background:var(--g-glass-2);}

/* 分段控件（大号/皮套/NPC） */
.seg{display:flex;gap:6px;padding:12px 14px 4px;}
.seg-btn{
  flex:1;
  padding:9px 0;
  border-radius:11px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  color:var(--g-ink-2);
  font-family:inherit;
  font-size:12.5px;
  cursor:pointer;
}
.seg-btn.is-on{
  background:linear-gradient(135deg,var(--g-accent) 0%,var(--g-accent-deep) 100%);
  border-color:transparent;color:#fff;
}
.seg-btn:disabled{opacity:.4;}

.set-select{
  width:100%;
  appearance:none;
  -webkit-appearance:none;
  background-image:none;
}

/* 认知矩阵 */
.cog-box{display:flex;flex-direction:column;gap:8px;padding:12px 14px 4px;}
.cog-opt{
  display:flex;flex-direction:column;gap:3px;
  padding:11px 13px;
  border-radius:13px;
  border:1px solid var(--g-glass-edge);
  background:var(--g-glass);
  font-family:inherit;text-align:left;
  cursor:pointer;color:var(--g-ink);
}
.cog-opt.is-on{
  border-color:var(--g-accent);
  background:rgba(111,184,106,.14);
}
.cog-opt.is-danger.is-on{
  border-color:var(--coral);
  background:rgba(217,115,107,.13);
}
.cog-opt-title{font-size:12.5px;font-weight:700;}
.cog-opt-desc{font-size:11px;color:var(--g-ink-3);line-height:1.55;}
.cog-state{
  margin:6px 0 0;padding:0 2px;
  font-size:11px;color:var(--g-ink-2);line-height:1.6;
}

/* 记忆库 */
.mem-box{max-height:280px;overflow-y:auto;padding:4px 14px 8px;}
.mem-item{
  display:flex;flex-direction:column;gap:3px;
  padding:8px 0;
  border-bottom:1px solid var(--g-glass-line);
}
.mem-tag{
  font-size:9.5px;
  font-weight:700;
  color:var(--g-accent-deep);
  letter-spacing:.2px;
}
.mem-text{font-size:12px;color:var(--g-ink-2);line-height:1.6;}
.mem-empty{margin:8px 0;font-size:11px;color:var(--g-ink-3);line-height:1.6;}

/* 挑选行（群聊勾选 / 马甲列表共用） */
.pick-line{
  width:100%;
  display:flex;align-items:center;gap:10px;
  padding:12px 14px;
  background:none;border:0;
  border-bottom:1px solid var(--g-glass-line);
  font-family:inherit;text-align:left;
  cursor:pointer;color:var(--g-ink);
}
.pick-line:last-child{border-bottom:0;}
.pick-line:active{background:var(--g-glass-2);}
.pick-line.is-on{background:rgba(111,184,106,.13);}
.pick-box{
  flex:none;
  width:17px;height:17px;
  border-radius:5px;
  border:1.5px solid rgba(139,108,76,.32);
  background:rgba(255,255,255,.55);
  position:relative;
}
.pick-line.is-on .pick-box{background:var(--g-accent);border-color:var(--g-accent);}
.pick-line.is-on .pick-box::after{
  content:"";
  position:absolute;left:4px;top:1px;
  width:4px;height:8px;
  border:solid #fff;border-width:0 1.5px 1.5px 0;
  transform:rotate(45deg);
}
.pick-box-plus{
  display:flex;align-items:center;justify-content:center;
  border-style:dashed;
  font-size:12px;color:var(--g-accent-deep);
}
.pick-av{
  flex:none;
  display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;
  border-radius:50%;
  background:var(--g-glass-3);
  color:var(--g-accent-deep);
  font-size:13px;font-weight:700;
}
.pick-name{
  flex:1;min-width:0;
  display:flex;align-items:center;gap:7px;
  font-size:13.5px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.pick-cur{
  flex:none;font-size:9.5px;
  padding:2px 7px;border-radius:8px;
  background:var(--g-accent);color:#fff;
}

/* 我（个人中心） */
.me-hero{display:flex;align-items:center;gap:13px;padding:14px;}
.me-av{
  flex:none;
  display:flex;align-items:center;justify-content:center;
  width:52px;height:52px;
  border-radius:50%;
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  font-size:20px;font-weight:700;
  color:var(--g-accent-deep);
}
.me-hero-body{flex:1;min-width:0;}
.me-name{font-size:16px;font-weight:700;color:var(--g-ink);}
.me-sub{margin-top:3px;font-size:11.5px;color:var(--g-ink-3);}

/* ---------------- 聊天页：输入框左侧的 User 头像 ---------------- */

.chat-user-ava{
  flex:none;
  width:36px;height:36px;
  border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  color:var(--g-accent-deep);
  font-size:13px;font-weight:700;
  cursor:pointer;
  position:relative;
  overflow:hidden;
  font-family:inherit;
  padding:0;
}
.chat-user-ava:active{transform:scale(.93);}
.chat-user-ava img{width:100%;height:100%;object-fit:cover;display:block;}
/* 长按提示：一个小小的面具角标，告诉用户这里能唤出轮盘 */
.chat-user-ava::after{
  content:"";
  position:absolute;
  right:-1px;bottom:-1px;
  width:13px;height:13px;
  border-radius:50%;
  background:var(--g-accent);
  border:2px solid var(--surface-solid);
}
.msg-user-label{
  font-size:10px;
  color:var(--g-ink-3);
  padding:0 4px 4px;
  text-align:right;
}

/* 掉马事件条：系统事件要有自己的长相，不能混成普通消息 */
.msg-drop .msg-text{
  background:rgba(217,115,107,.11);
  border:1px dashed rgba(217,115,107,.42);
  color:#A94F47;
}

/* ============================================================
   浮岛（造物主层）：横向云海 · 两座岛 · 存档列表 · 关系树配置台
   ------------------------------------------------------------
   名片夹的进化版。视觉上要跟「房内」明确分开：
     房内（桌面 / 聊天）= 玻璃面板压在极光上，卡片边界很硬
     浮岛               = 一整片天空，只有天光、岛影和留白

   三层结构：
     island        一屏一座岛，左右滑动；两座岛之间有飘带连着
     island-saves  某座岛的存档列表 + 新建
     island-config 横向关系树 + 加人设 + 马甲 + 认知锁 + 降落

   云海、岛、飘带都是纯 CSS / 内联 SVG 画的，项目不允许引外部图片。
   ============================================================ */

/* ---- 全局：把浏览器默认滚动条收细、去箭头 ----
   不美化的话 Windows 上会露出一条带三角箭头的灰色粗轨（很出戏）。
   只改粗细和颜色，不隐藏 —— 长页面还是需要「我还能往下滚」的提示。 */
.page{scrollbar-width:thin;scrollbar-color:rgba(139,108,76,.28) transparent;}
.page::-webkit-scrollbar{width:5px;height:5px;}
.page::-webkit-scrollbar-track{background:transparent;}
.page::-webkit-scrollbar-thumb{background:rgba(139,108,76,.26);border-radius:3px;}
.page::-webkit-scrollbar-thumb:hover{background:rgba(139,108,76,.4);}
.page::-webkit-scrollbar-button{display:none;width:0;height:0;}

/* ==================== 第一层：浮岛（左右滑动） ==================== */

.page[data-page="island"]{
  padding:0;overflow:hidden;
  /* 兜底实色：万一 .isl-sky 没铺满，也绝不能透出底下的桌面
     （页面底座透明踩过一次，见 .page 的注释） */
  background:var(--g-base);
}
/* 浮岛的内容**不留状态栏那条内边距** —— 因为天空（.isl-sky）是挂在
   .app-body 里的绝对定位元素，而 .app-body 从 page-inner 的内边距之后开始：
   一旦在这里留 padding-top，天空就铺不到状态栏那一条，顶上露出一截
   页面兜底色（用户：「怎么浮岛上面还有那个颜色，不是透明的」）。
   标题和返回键不会因此被压住 —— .app-head 是绝对定位的，它自己让了位（见下）。 */
.page[data-page="island"] .page-inner{
  padding:0;
}
/* 浮岛不要标题栏那一横条：整片天空才是标题。
   top 要给状态栏让位 —— 状态栏是 absolute 浮着的，写 top:0 的话
   「浮岛」和返回键会跟电量时间叠在一起（截图里就是这样）。 */
.page[data-page="island"] .app-head{
  position:absolute;top:calc(env(safe-area-inset-top) + 32px);left:0;right:0;z-index:4;
  padding:12px 18px 0;background:transparent;
}
.page[data-page="island"] .app-head-side{gap:6px;}
.page[data-page="island"] .app-body{position:relative;min-height:0;}

.isl-sky{
  position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;
  background:linear-gradient(180deg,#EAF6FB 0%,#E7F6EC 38%,#DCF0E6 68%,#C9E6D8 100%);
}
.isl-glow{position:absolute;border-radius:50%;filter:blur(64px);opacity:.55;}
.isl-glow-a{width:300px;height:300px;background:#EBD9BC;top:-90px;left:-80px;}
.isl-glow-b{width:340px;height:340px;background:#F0E2C8;bottom:-40px;right:-120px;}
.isl-glow-c{width:220px;height:220px;background:#CBE7FF;top:36%;left:42%;opacity:.4;}

/* 云海上方**不放任何标题和诗句**。曾经挂过一句「霓为衣兮风为马」，
   用户第一反应是「为啥上面是霓为衣兮风为马这个诗句呀」——
   因为它在说别人的事。每座岛各配一句就够了（见 .isl-poem）。 */

/* 滑动的带子：一屏一座岛 */
.isl-track{
  position:relative;z-index:1;
  display:flex;height:100%;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.isl-track::-webkit-scrollbar{display:none;}
/* 拖拽的当口必须**临时关掉 scroll-snap**：
   mandatory 会在每一帧把 scrollLeft 强行吸到整屏，鼠标拖起来像在跟人抢。 */
.isl-track.is-dragging{scroll-snap-type:none;cursor:grabbing;}

/* 两座岛之间**没有连线** —— 曾经在这里画过一条跨屏飘带，是理解错了：
   要连起来的是「我」和角色，不是这两座岛（它们只是两种房型，
   像货架上并排的两样东西，彼此没有关系）。
   红线现在只画在配置台的关系树上，见 .tree-tie。 */

.isl-page{
  position:relative;z-index:1;
  flex:0 0 100%;width:100%;height:100%;
  scroll-snap-align:start;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:120px 22px 110px;
  /* grab 而不是 pointer：先告诉人「这块能拖」。点击照样进岛 ——
     拖拽超过 8px 的那次 click 会在捕获阶段被丢掉（见 page-island.js）。 */
  cursor:grab;
}
.isl-track.is-dragging .isl-page{cursor:grabbing;}

/* 左右切岛的箭头。
   桌面浏览器里 `overflow-x:auto` 的容器**拖不动**（鼠标没有触摸那种滑动手势），
   所以只有底部的页码点能切 —— 用户根本不知道能切，反馈就是「也没能右滑」。
   补一对看得见的按钮，按需禁用（到头就淡掉）。 */
.isl-nav{
  position:absolute;left:0;right:0;top:50%;z-index:3;
  display:flex;justify-content:space-between;
  padding:0 10px;margin-top:-19px;pointer-events:none;
}
.isl-arrow{
  pointer-events:auto;
  width:38px;height:38px;padding:0 0 3px;border:0;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--ff-serif);font-size:22px;line-height:1;
  color:var(--g-accent-deep);background:rgba(255,255,255,.5);
  box-shadow:0 4px 14px rgba(139,108,76,.12);
  cursor:pointer;transition:opacity .2s var(--ease),background .2s var(--ease);
}
.isl-arrow:hover{background:rgba(255,255,255,.76);}
.isl-arrow:disabled{opacity:0;pointer-events:none;}

/* ---- 岛的视觉：横着的岛，不是竖着的卡片 ---- */
.isl-stage{
  position:relative;height:120px;width:100%;
  display:flex;align-items:flex-end;justify-content:center;
}
.isl-ground{
  position:relative;width:258px;height:46px;border-radius:50%;
  background:linear-gradient(180deg,#F7FDF7 0%,#D9EDDF 58%,#B9DCC4 100%);
  border:1px solid rgba(139,108,76,.14);
  box-shadow:0 16px 34px rgba(139,108,76,.15),inset 0 2px 6px rgba(255,255,255,.8);
}
/* 孤岛：两束光（两棵小树）—— 只站得下两个人 */
.isl-tree{
  position:absolute;bottom:34px;width:2px;height:32px;border-radius:2px;
  background:linear-gradient(180deg,#8FCF8A,#5FA05C);
}
.isl-tree::after{
  content:"";position:absolute;left:50%;top:-10px;width:20px;height:20px;margin-left:-10px;
  border-radius:50%;
  background:radial-gradient(circle at 38% 32%,#EDFAE7,#9FD79A 72%,rgba(159,215,154,0) 100%);
}
.isl-tree-a{left:108px;}
.isl-tree-b{left:148px;height:28px;}
.isl-tree-b::after{width:16px;height:16px;margin-left:-8px;top:-8px;}

/* 群岛：一串横向排开的碎片岛。
   注意**不要**底下那个大椭圆底座 —— 有底座就变成一朵云了（第一版就是这样）。
   四块大小不一、高低错落，彼此轻微咬合，才读得出「群岛」。 */
.isl-stage-archipelago .isl-ground{
  width:320px;background:none;border:0;box-shadow:none;
}
.isl-shard{
  position:absolute;border-radius:50%;
  background:linear-gradient(180deg,#F7FDF7,#D3EADA 62%,#B0D9BF);
  border:1px solid rgba(139,108,76,.13);
  box-shadow:0 10px 22px rgba(139,108,76,.13),inset 0 2px 5px rgba(255,255,255,.78);
}
.isl-shard-a{width:78px;height:30px;bottom:0;left:8px;}
.isl-shard-b{width:102px;height:42px;bottom:16px;left:74px;}
.isl-shard-c{width:66px;height:26px;bottom:2px;left:170px;}
.isl-shard-d{width:52px;height:22px;bottom:12px;left:244px;}

.isl-isle-head{display:flex;align-items:baseline;gap:8px;margin-top:14px;}
.isl-isle-name{font-family:var(--ff-serif);font-size:22px;letter-spacing:4px;color:var(--text);}
.isl-isle-badge{
  padding:1px 8px;border-radius:999px;font-size:10.5px;
  color:var(--g-accent-deep);background:rgba(111,184,106,.16);
  border:1px solid rgba(111,184,106,.28);
}
/* 岛上那句诗 —— 这一层的灵魂，别再写说明书 */
.isl-poem{margin:12px 0 0;font-family:var(--ff-serif);font-size:16px;letter-spacing:3px;color:var(--g-accent-deep);}
.isl-poem-from{margin:6px 0 0;font-size:10.5px;letter-spacing:.4px;color:var(--text-faint);}
.isl-isle-count{margin:16px 0 0;font-size:11.5px;color:var(--text-dim);}

.isl-dots{
  position:absolute;left:0;right:0;z-index:3;
  bottom:calc(env(safe-area-inset-bottom) + 30px);
  display:flex;justify-content:center;gap:7px;
}
.isl-dot{
  width:6px;height:6px;border-radius:50%;background:rgba(139,108,76,.24);
  transition:width .2s var(--ease),background .2s var(--ease);
}
.isl-dot.is-on{width:16px;border-radius:3px;background:var(--g-accent);}

/* ==================== 第二层：某座岛的存档列表 ==================== */

.page[data-page="island-saves"]{
  background:linear-gradient(180deg,#EDF7FB 0%,#E8F6ED 50%,#DDF0E5 100%);
}
.sav-head{padding:4px 0 20px;text-align:center;}
.sav-poem{margin:0;font-family:var(--ff-serif);font-size:16px;letter-spacing:2px;color:var(--g-accent-deep);}
.sav-poem-from{margin:6px 0 0;font-size:10.5px;color:var(--text-faint);}
.sav-hint{margin:12px 0 0;font-size:12px;line-height:1.7;color:var(--text-dim);}

.sav-list{display:flex;flex-direction:column;gap:14px;}
.sav-empty{margin:0;padding:26px 8px;text-align:center;font-size:12.5px;line-height:1.9;color:var(--text-faint);}
.sav-card{
  border-radius:18px;overflow:hidden;background:rgba(255,255,255,.72);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 8px 22px rgba(139,108,76,.08);
}
.sav-card.is-active{box-shadow:inset 3px 0 0 var(--g-accent),0 8px 22px rgba(139,108,76,.1);}
.sav-open{display:block;width:100%;text-align:left;padding:16px 18px 10px;background:none;border:0;font-family:inherit;cursor:pointer;}
.sav-open-head{display:flex;align-items:center;gap:8px;}
.sav-name{font-size:16px;font-weight:500;color:var(--text);}
.sav-cur{margin-left:auto;font-size:10.5px;color:var(--g-accent-deep);}
.sav-line{margin:8px 0 0;font-size:12.5px;line-height:1.6;color:var(--text-dim);}
.sav-meta{margin:5px 0 0;font-size:11.5px;color:var(--text-faint);}
.sav-tools{display:flex;justify-content:flex-end;padding:0 14px 12px;}
.sav-tool{
  padding:5px 12px;border-radius:999px;border:1px solid var(--g-glass-line);
  background:rgba(255,255,255,.6);font-family:inherit;font-size:11.5px;color:var(--text-dim);cursor:pointer;
}
.sav-tool.is-danger{color:var(--coral);border-color:rgba(217,115,107,.3);}
.sav-new{
  margin:22px auto 0;display:inline-flex;align-items:center;gap:7px;
  padding:12px 22px;border-radius:999px;border:1px dashed rgba(139,108,76,.38);
  background:rgba(255,255,255,.6);font-family:inherit;font-size:13px;
  color:var(--g-accent-deep);cursor:pointer;
}
.sav-new svg{display:block;}

/* ==================== 第三层：配置台（横向关系树） ==================== */

.cfg-head{padding:4px 0 6px;text-align:center;}
.cfg-poem{margin:0;font-family:var(--ff-serif);font-size:15px;letter-spacing:2px;color:var(--g-accent-deep);}
.cfg-poem-from{margin:6px 0 0;font-size:10.5px;color:var(--text-faint);}

/* 树可能比屏幕宽（角色多的时候），所以给它自己的横向滚动 */
.tree-scroll{
  overflow-x:auto;overflow-y:hidden;
  padding:4px 0 0;margin:0 -6px;
}
.tree-scroll::-webkit-scrollbar{height:4px;}
.tree-scroll::-webkit-scrollbar-thumb{background:rgba(139,108,76,.24);border-radius:2px;}
.tree-wrap{display:inline-block;min-width:100%;padding:0 6px;}
.tree-svg{display:block;}
.tree-svg text{font-family:var(--ff);}

.tree-line{stroke:rgba(139,108,76,.34);stroke-width:1.1;fill:none;}
.tree-line-v{stroke:rgba(139,108,76,.26);}
.tree-dash{stroke-dasharray:3 5;stroke:rgba(139,108,76,.28);}

/* ---- 红线：**只画在「我 ↔ 角色」之间** ----
   月老那种意象 —— 这一层是「我和你」，不是「谁属于谁」。
   画法是两条平行的弧（一条丝带的两边），关系文字压在正中把带子截断。
   底下那条 .tree-tie-b 故意更淡，看着像丝带的背面。

   与之相对：我 → NPC、角色 → 皮套/NPC 走上面那套淡绿细线（归属），
   于是树上「情」和「属」一眼分得开。 */
.tree-tie{stroke:#D9736B;stroke-width:1.35;fill:none;opacity:.62;}
.tree-tie-b{opacity:.3;}
.tree-tie-dash{stroke-dasharray:4 5;opacity:.42;}

.tree-disc{fill:#F5FCF5;stroke:rgba(139,108,76,.34);stroke-width:1;}
.tree-me{fill:#DCF0DE;stroke:var(--g-accent);stroke-width:1.4;}
.tree-char{fill:#EAF8E8;stroke:rgba(139,108,76,.46);}
.tree-kid{fill:#F3FAF3;}
.tree-sub{stroke-dasharray:3 3;}
.tree-npc{stroke:rgba(139,108,76,.28);}
.tree-plus{fill:rgba(255,255,255,.55);stroke:rgba(139,108,76,.42);stroke-dasharray:3 4;}

.tree-initial{font-size:13px;font-weight:500;fill:#2E4B30;}
.tree-glyph{font-size:17px;fill:var(--g-accent-deep);}
.tree-name{font-size:10px;fill:#6B806C;}
/* 写在红线上的那句话 —— 用暖色（跟线同族），跟绿色的归属线区分开 */
.tree-rel{
  font-size:11px;fill:#B45C55;
  font-family:var(--ff-serif);letter-spacing:1px;
}
.tree-rel-empty{font-size:10px;fill:rgba(217,115,107,.62);}
/* 垫在关系文字底下，把红线截断。fill 必须跟 .page 的底色一致 ——
   不然换主题时会露出一个色块。描边是那截「签条」的边。 */
.tree-rel-bg{fill:var(--bg);stroke:rgba(217,115,107,.3);stroke-width:.8;}
.tree-click{cursor:pointer;}
.tree-click:hover .tree-disc{stroke:var(--g-accent);stroke-width:1.6;}
.tree-click:hover .tree-rel-empty{fill:#B45C55;}
.tree-hint{
  margin:6px 0 20px;text-align:center;
  font-size:11.5px;line-height:1.7;color:var(--text-faint);
}

.cfg-add-row{display:flex;gap:10px;}
.cfg-add-main{
  flex:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:14px;border:0;border-radius:16px;
  background:linear-gradient(140deg,var(--g-accent),var(--g-accent-deep));
  color:#F4FCF3;font-family:inherit;font-size:14px;letter-spacing:1px;
  cursor:pointer;box-shadow:0 8px 20px rgba(139,108,76,.24);
}
.cfg-add-main svg{display:block;}
.cfg-add-sub{
  flex:none;padding:14px 16px;border-radius:16px;
  border:1px solid var(--g-glass-line);background:rgba(255,255,255,.7);
  font-family:inherit;font-size:13px;color:var(--text-dim);cursor:pointer;
}

.cfg-masks{display:flex;flex-direction:column;gap:8px;}
.cfg-mask{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:9px 10px;border-radius:12px;border:1px solid var(--g-glass-line);
  background:rgba(255,255,255,.5);font-family:inherit;text-align:left;cursor:pointer;
}
.cfg-mask.is-on{border-color:rgba(111,184,106,.5);background:rgba(111,184,106,.12);}
.cfg-check{
  flex:none;width:20px;height:20px;border-radius:6px;
  border:1px solid var(--g-glass-line);display:flex;align-items:center;
  justify-content:center;font-size:12px;color:var(--g-accent-deep);
}
.cfg-mask.is-on .cfg-check{background:var(--g-accent);border-color:var(--g-accent);color:#fff;}
.cfg-locks{display:flex;flex-direction:column;gap:12px;}
.cfg-lock{display:flex;flex-direction:column;gap:7px;}
.cfg-lock-who{font-size:12.5px;color:var(--text-dim);}
.cfg-empty{margin:0;padding:14px 4px;font-size:12px;line-height:1.8;color:var(--text-faint);}
.cfg-char-body{flex:1;min-width:0;}
.cfg-char-name{display:block;font-size:14px;color:var(--text);}
.cfg-char-line{
  display:block;margin-top:3px;font-size:11.5px;color:var(--text-faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.cfg-footer{margin-top:24px;padding-bottom:10px;}
.cfg-land{
  display:block;width:100%;padding:16px;border:0;border-radius:20px;
  font-family:inherit;cursor:pointer;
  background:linear-gradient(140deg,var(--g-accent),var(--g-accent-deep));
  color:#F4FCF3;box-shadow:0 10px 26px rgba(139,108,76,.28);
}
.cfg-land-title{display:block;font-size:17px;font-weight:500;letter-spacing:3px;}
.cfg-land-sub{display:block;margin-top:5px;font-size:11.5px;opacity:.86;}

/* ==================== 简化人设页 ==================== */

.simple-parent{
  margin:0 0 18px;padding:11px 14px;border-radius:12px;
  font-size:12px;line-height:1.7;color:var(--text-dim);
  background:rgba(111,184,106,.1);border:1px solid rgba(111,184,106,.2);
}
.simple-more{
  display:block;width:100%;margin-top:14px;padding:12px;
  border:1px dashed var(--g-glass-line);border-radius:14px;
  background:none;font-family:inherit;font-size:12px;
  color:var(--text-dim);cursor:pointer;
}
/* 「有小号吗」打开之后展开的那一段。
   左边一根浅绿的引导线 + 淡底，让人一眼看出它**从属于上面的开关**，
   不是一个独立区块。 */
.simple-sub{
  margin:2px 0 10px 6px;padding:2px 0 2px 12px;
  border-left:2px solid rgba(111,184,106,.34);
  background:linear-gradient(90deg,rgba(111,184,106,.07),rgba(111,184,106,0) 70%);
}

/* ============================================================
   聊天 App 容器（page-app.js）：微信式底栏 + 四个 Tab
   ------------------------------------------------------------
   《聊天 App · 核心架构》：「聊天 App = 当前房屋监视器，前台 4 Tab」。
   四屏共用同一个前提（当前沙盒 + 当前马甲），底栏把它们串起来，
   切完马甲消息和朋友圈一起刷。

   布局要点：**只有中间那一屏滚动**，顶栏和底栏都是固定的。
   `.page` 自己就是滚动容器，所以这里必须把它关掉、把滚动交给 .app-body ——
   不然内容一长，底栏会被顶到屏幕外去。
   ============================================================ */

.page.has-tabbar{overflow:hidden;}
.page.has-tabbar .page-inner{
  height:100%;min-height:0;
  /* 左右内边距**收掉**，改由每一屏自己管（.tab-panel 给 22px）——
     因为聊天列表要用负 margin 做「通栏」（列表贴到屏幕两边、
     行内自己留 22px 让文字跟标题对齐）。
     内边距留在 .page-inner 上的话，那个 -22px 会从 22px 一路撑到
     屏幕外 22px，浏览器就冒出一条横向滚动条。
     顶栏要单独补回来（它不在 .tab-panel 里）。 */
  padding-left:0;padding-right:0;
  padding-bottom:0;                 /* 底栏自己带 safe-area，这里别叠加 */
}
.page.has-tabbar .app-head{padding-left:22px;padding-right:22px;}
.page.has-tabbar .app-body{
  flex:1;min-height:0;overflow-y:auto;
  /* 显式写 overflow-x:hidden 当保险 —— 按规范，overflow-y 不是 visible 时
     overflow-x 的默认值 visible 会被**算成 auto**，内容宽出一点就冒出
     一条 Windows 默认样式的横向粗滚动条。 */
  overflow-x:hidden;
  padding-bottom:10px;
  scrollbar-width:thin;scrollbar-color:rgba(139,108,76,.28) transparent;
}
.page.has-tabbar .app-body::-webkit-scrollbar{width:5px;height:5px;}
.page.has-tabbar .app-body::-webkit-scrollbar-track{background:transparent;}
.page.has-tabbar .app-body::-webkit-scrollbar-thumb{
  background:rgba(139,108,76,.26);border-radius:3px;
}

/* 每一屏自己的左右内边距。想通栏的东西（聊天列表）用 margin:0 -22px 抵消。 */
.tab-panel{padding:0 22px;}

.tab-bar{
  flex:none;margin:0;                 /* 通栏靠的是一屏自己的 -22px，底栏不用负 margin */
  display:flex;gap:2px;
  padding:6px 6px calc(env(safe-area-inset-bottom) + 6px);
  background:var(--surface-solid);
  border-top:1px solid var(--line);
  z-index:6;
}
.tab-btn{
  flex:1;min-width:0;
  display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:7px 2px;border:0;border-radius:12px;background:none;
  font-family:inherit;color:var(--text-faint);cursor:pointer;
  transition:color .18s var(--ease),background .18s var(--ease);
}
.tab-btn.is-on{color:var(--g-accent-deep);}
.tab-btn:active{background:rgba(111,184,106,.1);}
.tab-ic{display:block;width:23px;height:23px;}
.tab-ic svg{display:block;width:100%;height:100%;}
.tab-tx{font-size:10.5px;letter-spacing:.4px;}

/* ---------------- 通讯录（平铺列表 · 决策 7） ----------------
   树（谁挂在谁名下）是造物主层的事，归浮岛的配置台。
   这里是「人在房间里抬头能看见谁」，所以**一律平铺**，
   皮套 / NPC 也只加一个角标，绝不缩进 —— 缩进就又变树了。 */

.addr-group{margin-bottom:18px;}
.addr-group:first-child{margin-top:6px;}   /* 别贴着顶栏那根分隔线 */
.addr-group-title{
  margin:0 0 8px;padding-left:2px;
  font-size:11.5px;letter-spacing:.6px;color:var(--text-faint);
}
.addr-empty{margin:0;padding:10px 2px;font-size:12px;line-height:1.7;color:var(--text-faint);}
.addr-row{
  display:flex;align-items:center;gap:12px;width:100%;
  padding:11px 12px;margin-bottom:8px;
  border:1px solid var(--g-glass-line);border-radius:14px;
  background:rgba(255,255,255,.5);
  font-family:inherit;text-align:left;cursor:pointer;
  transition:background .18s var(--ease);
}
.addr-row:active{background:rgba(111,184,106,.12);}
.addr-av{
  flex:none;width:38px;height:38px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:15px;font-weight:500;color:#2E4B30;
  background:linear-gradient(140deg,#E9F7E6,#BFE3C4);
  border:1px solid rgba(139,108,76,.2);
  background-size:cover;background-position:center;
}
.addr-av.has-img{color:transparent;}   /* 有头像图时别让首字压在上面 */
.addr-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}
.addr-name-line{display:flex;align-items:center;gap:7px;}
.addr-name{font-size:14.5px;color:var(--text);}
.addr-badge{
  flex:none;padding:0 7px;border-radius:999px;
  font-size:10px;letter-spacing:.3px;
  color:var(--g-accent-deep);background:rgba(111,184,106,.14);
  border:1px solid rgba(111,184,106,.26);
}
.addr-sub{
  font-size:11.5px;color:var(--text-faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ---------------- 朋友圈的空态 ----------------
   数据是真的（读 store 的 moments 并按房过滤），只是还没有地方往里写 ——
   「角色自己发动态」是后面那一批。所以现在大概率是这一屏。 */

.moment-empty{
  margin-top:10px;padding:30px 18px;text-align:center;
  border-radius:16px;border:1px dashed var(--g-glass-line);
  background:rgba(255,255,255,.4);
}
.moment-empty-title{margin:0;font-size:13.5px;color:var(--text-dim);}
.moment-empty-hint{margin:8px 0 0;font-size:11.5px;line-height:1.7;color:var(--text-faint);}

/* 头像改成用首字兜底（原来写死一个 img 占位图） */
.moment-avatar{
  flex:none;width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:12px;color:#2E4B30;
  background:linear-gradient(140deg,#E9F7E6,#BFE3C4);
  background-size:cover;background-position:center;
}
.moment-avatar.has-img{color:transparent;}

/* ---------------- 「我」那一屏 ---------------- */

/* 当前身份现在直接挂在面板上（原来是塞在 group 卡片里），
   所以自己要有一张卡的样子 */
.me-hero{
  display:flex;align-items:center;gap:13px;padding:14px;margin-bottom:22px;
  border-radius:18px;background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow),var(--g-inset);
}
.me-switch{
  flex:none;padding:6px 14px;border-radius:999px;
  border:1px solid var(--g-glass-line);background:rgba(255,255,255,.62);
  font-family:inherit;font-size:12px;color:var(--g-accent-deep);cursor:pointer;
}
.me-switch:active{background:rgba(111,184,106,.16);}

/* ---- 「我」页 v2（09-19 照 demo 重排）----
   demo 的配色没搬（主题色归外观管），只搬结构与交互；
   我的小手机是折叠抽屉，mtb-phone.is-open 才露出工具列表。 */
.mtb-hero{margin-bottom:20px;}
.mtb-label{font-size:9.5px;letter-spacing:.14em;color:var(--g-accent-deep);}
.mtb-current{
  display:flex;align-items:center;gap:13px;margin-top:10px;padding:14px 13px;
  border-radius:18px;background:var(--g-glass-3);
  border:1px solid var(--g-glass-edge);
  box-shadow:var(--g-glass-shadow),var(--g-inset);
}
.mtb-copy{flex:1;min-width:0;}
.mtb-copy b{font-size:15.5px;font-weight:600;color:var(--g-ink);}
.mtb-copy small{display:block;margin-top:5px;font-size:10px;color:var(--g-ink-3);line-height:1.55;}
.mtb-sec{margin-top:20px;}
.mtb-sec-head{
  display:flex;align-items:baseline;justify-content:space-between;
  padding:0 2px 8px;border-bottom:1px solid var(--g-glass-line);
}
.mtb-sec-head h2{margin:0;font-size:12.5px;font-weight:600;letter-spacing:.08em;color:var(--g-ink);}
.mtb-sec-head small{font-size:9.5px;color:var(--g-ink-3);}
/* 折叠抽屉头：整行可点，自带 › 指示。
   注意是 button —— 不写 border:0 会带着浏览器默认框
   （用户 09-19 点名：这里不要加框，圆角和框都要谨慎用）。 */
.mtb-sec-head.is-tap{
  width:100%;border:0;background:none;cursor:pointer;
  text-align:left;font-family:inherit;padding:8px 2px;
}
.mtb-chev{font-size:14px;color:var(--g-ink-3);transition:transform .2s;}
.mtb-phone .mtb-tools{display:none;}
.mtb-phone.is-open .mtb-tools{display:block;}
.mtb-phone.is-open .mtb-chev{transform:rotate(90deg);}
.mtb-room-status{padding:12px 2px 8px;}
.mtb-room-status strong{display:block;font-size:13.5px;font-weight:600;color:var(--g-ink);}
.mtb-room-status span{display:block;margin-top:5px;font-size:10px;color:var(--g-ink-3);line-height:1.7;}
.mtb-room-actions{display:flex;gap:9px;padding:5px 2px 2px;}
.mtb-btn{
  flex:1;padding:10px 8px;border-radius:12px 5px 12px 5px;
  border:1px solid var(--g-glass-line);background:var(--g-glass-3);
  font-family:inherit;font-size:11px;color:var(--g-ink-2);cursor:pointer;
}
.mtb-btn.is-accent{background:rgba(161,129,87,.14);color:var(--g-accent-deep);}
.mtb-idents{display:grid;gap:8px;padding-top:11px;}
.mtb-ident{
  display:grid;grid-template-columns:35px 1fr auto;align-items:center;gap:10px;
  padding:11px 10px;border-radius:13px 5px 13px 5px;
  background:var(--g-glass-3);border:1px solid var(--g-glass-edge);
  text-align:left;cursor:pointer;font-family:inherit;
  box-shadow:0 6px 16px rgba(84,104,89,.06);
}
.mtb-ident.is-current{border-color:rgba(161,129,87,.38);background:rgba(161,129,87,.1);}
.mtb-mini{
  width:35px;height:35px;display:grid;place-items:center;border-radius:50%;
  background:var(--g-glass-2);font-size:11px;color:var(--g-accent-deep);
}
.mtb-ident-copy{min-width:0;}
.mtb-ident-copy b{display:block;font-size:11.5px;font-weight:600;color:var(--g-ink);}
.mtb-ident-copy small{
  display:block;margin-top:4px;font-size:9px;color:var(--g-ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.mtb-side{font-size:9.5px;color:var(--g-accent-deep);flex:none;}
.mtb-arrow{font-size:13px;color:var(--g-ink-3);flex:none;}
.mtb-add{
  width:100%;margin-top:8px;padding:11px;
  border:1px dashed rgba(161,129,87,.4);border-radius:12px 5px 12px 5px;
  background:none;color:var(--g-accent-deep);
  font-size:11px;font-family:inherit;cursor:pointer;
}
.mtb-tool{
  width:100%;display:grid;grid-template-columns:1fr auto;align-items:center;gap:10px;
  padding:13px 2px;border:0;border-bottom:1px solid var(--g-glass-line);
  background:none;text-align:left;cursor:pointer;font-family:inherit;
}
.mtb-tool:last-child{border-bottom:0;}
.mtb-tool b{display:block;font-size:12.5px;font-weight:600;color:var(--g-ink);}
.mtb-tool small{display:block;margin-top:4px;font-size:9.5px;color:var(--g-ink-3);}

/* ============================================================
   转账消息 · 钱包 · 表情包（T5 的补完）
   ============================================================ */

/* ---- 转账气泡：橙金色，跟照片/文件的灰卡片一眼分开 ----
   钱是这一屏里最该被立刻认出来的东西，不配色它就混在附件里了。 */
.msg-transfer{
  display:flex;align-items:center;gap:10px;
  min-width:150px;padding:12px 14px;
  border-radius:12px;
  background:linear-gradient(140deg,#F5E7C8,#EFD6A2);
  border:1px solid rgba(180,140,60,.28);
  color:#6B4E17;
}
.msg-user .msg-transfer{border-top-right-radius:4px;}
.msg-assistant .msg-transfer{border-top-left-radius:4px;}
.msg-transfer-ic{flex:none;display:flex;color:#8A6A25;}
.msg-transfer-main{display:flex;flex-direction:column;gap:2px;min-width:0;}
.msg-transfer-amt{font-size:16px;font-weight:700;}
.msg-transfer-sub{
  font-size:11px;color:#8A6A25;
  max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ---- 钱包 ---- */
.wallet-hero{
  display:flex;flex-direction:column;gap:4px;
  margin-bottom:22px;padding:18px 16px;
  border-radius:18px;
  background:linear-gradient(140deg,var(--g-accent),var(--g-accent-deep));
  box-shadow:0 10px 26px rgba(139,108,76,.24);
  color:#F4FCF3;
}
.wallet-lab{font-size:11.5px;opacity:.85;}
.wallet-amt{font-size:30px;font-weight:700;letter-spacing:.5px;}
.wallet-edit{
  align-self:flex-start;margin-top:10px;
  padding:6px 14px;border-radius:999px;border:0;
  background:rgba(255,255,255,.22);color:#F4FCF3;
  font-family:inherit;font-size:12px;cursor:pointer;
}
.wallet-edit:active{background:rgba(255,255,255,.34);}

/* ---- 表情包管理 ---- */
.stk-list{display:flex;flex-direction:column;gap:8px;}
/* 表情包原来的「一行一张」样式（stk-row / stk-av / stk-ops…）整套删了 ——
   现在是**格子墙**（一个组一片网格，组里第一格是「+」），见下面那段。 */


/* 多字段弹层（转账的金额 + 备注）。每个字段自带标签，
   跟单输入框那个 .dl-input 是同一种框，视觉上是一家人。 */
.dl-fields{display:flex;flex-direction:column;gap:10px;margin-bottom:14px;}
.dl-field{display:flex;flex-direction:column;gap:6px;}
.dl-field-label{font-size:11.5px;letter-spacing:.4px;color:var(--text-faint);}

/* ============================================================
   朋友圈 —— 照着微信抄的：**白底**，不做卡片。
   条目 = 左侧小方头像 + 右侧一列（名字蓝灰 / 正文黑 / 时间灰+两个点）；
   赞和评论收在正文下面那块**浅灰**（#F7F7F7）里；
   顶上是通栏封面（壁纸可换），自己的头像压在封面右下角。

   之前第一版满屏青提绿圆角卡片 —— 用户原话「不要再用全绿色啦，
   会有种很土的感觉」，直接拿微信截图对着的。**别再往回改。**
   ============================================================ */

/* 朋友圈这一屏是白底（其他 tab 还是玻璃风） */
.tab-panel.is-moments{background:#fff;padding:0;}
.page[data-page="moments"] .app-body,.page.has-tabbar .app-body:has(.is-moments){background:#fff;}

/* ---- 封面：通栏、无圆角，高约屏 1/4；壁纸没设时给一片蓝天 ---- */
.mo-cover{
  position:relative;height:236px;
  background-image:
    radial-gradient(120% 80% at 82% 8%, rgba(255,255,255,.42) 0%, transparent 48%),
    radial-gradient(100% 70% at 8% 100%, rgba(255,255,255,.22) 0%, transparent 46%),
    linear-gradient(180deg,
      var(--mo-wall-1) 0%, var(--mo-wall-2) 50%, var(--mo-wall-3) 100%);
  background-size:cover;background-position:center;
  /* **不能 overflow:hidden** —— 右下角那个头像要探出封面半格，
     裁掉就只剩半边（用户：「这个头像你没发现只有一半么」）。
     壁纸本身是 background，画的时候就被元素框裁住了，不需要这层。 */
  overflow:visible;
}
.mo-cover.has-img{background-size:cover;background-position:center;}
.mo-cover-tip{
  position:absolute;right:12px;top:10px;
  padding:3px 10px;border-radius:999px;
  font-size:10.5px;letter-spacing:.4px;
  color:#fff;background:rgba(0,0,0,.26);
  opacity:0;transition:opacity .2s var(--ease);
}
.mo-cover:hover .mo-cover-tip{opacity:1;}

/* 自己的名字 + 头像：压在封面右下角，头像一半探出封面 */
.mo-me{
  position:absolute;right:14px;bottom:-22px;
  display:flex;align-items:flex-start;gap:10px;
}
.mo-me-name{
  margin-top:14px;
  font-size:14px;font-weight:600;color:#fff;
  text-shadow:0 1px 4px rgba(0,0,0,.45);
}
.mo-me-av{
  flex:none;width:58px;height:58px;border-radius:8px;
  display:flex;align-items:center;justify-content:center;
  font-size:21px;font-weight:500;color:#2E4B30;
  background:linear-gradient(140deg,#E9F7E6,#BFE3C4);
  border:2px solid #fff;
  background-size:cover;background-position:center;
  box-shadow:0 3px 10px rgba(0,0,0,.16);
}
.mo-me-av.has-img{color:transparent;}

/* ---- 动态列表 ---- */
.mo-feed{padding:30px 16px 30px;}
.moment-item{
  /* 干掉第一版的卡片壳：微信的条目没有边框和圆角，白底 + 一条浅分隔线 */
  background:#fff;border:0;border-radius:0;
  padding:14px 0 6px;margin:0;
}
.moment-avatar{width:42px;height:42px;border-radius:6px;font-size:17px;}
.moment-text{font-size:15px;line-height:1.55;color:#1A1A1A;}
.moment-empty{
  margin-top:8px;padding:34px 18px;text-align:center;
  border-radius:12px;background:#F7F7F7;
}
.moment-empty-title{margin:0;font-size:14px;color:#576B95;}
.moment-empty-hint{margin:8px 0 0;font-size:11.5px;line-height:1.7;color:#B2B2B2;}

/* 一条动态 = 左头像 + 右一列；不是卡片，只有一条极浅的分隔线 */
.moment-item{
  display:flex;gap:11px;
  padding:16px 0 4px;
  border-bottom:1px solid #F0F0F0;
}
.mo-avatar{
  flex:none;width:42px;height:42px;border-radius:6px;
  display:flex;align-items:center;justify-content:center;
  font-size:17px;font-weight:500;color:#fff;
  background:#C8CDD4;
  background-size:cover;background-position:center;
}
.mo-avatar.has-img{color:transparent;}
.mo-main{flex:1;min-width:0;}

/* 名字：微信朋友圈的那个蓝灰 */
.mo-name{
  font-size:15px;font-weight:500;color:#576B95;
  margin-bottom:5px;
}
.mo-text{
  margin:0 0 8px;
  font-size:calc(15px * var(--fs-scale, 1));line-height:1.55;color:#1A1A1A;
  word-break:break-word;
}

/* 时间 + 两个点：一行，两端对齐 */
.mo-foot{display:flex;align-items:center;justify-content:space-between;margin-top:2px;}
.mo-time{font-size:11.5px;color:#B2B2B2;}
.mo-more{
  border:0;background:none;cursor:pointer;
  color:#68768F;padding:4px 6px;border-radius:6px;
  display:flex;align-items:center;
}
.mo-more:active{background:#F2F2F2;}

/* ---- 点「两个点」弹出的快捷条：赞 | 评论 ---- */
.mo-quick{
  display:none;gap:0;margin-bottom:9px;
  border:1px solid #ECECEC;border-radius:6px;overflow:hidden;
}
.mo-quick.is-open{display:flex;}
.mo-quick-btn{
  flex:1;padding:9px 0;border:0;background:#FAFAFA;
  font-family:inherit;font-size:13px;color:#576B95;cursor:pointer;
}
.mo-quick-btn + .mo-quick-btn{border-left:1px solid #ECECEC;}
.mo-quick-btn:active{background:#F0F0F0;}

/* 展开的身份 chips + 评论输入（依旧素色，不抢戏） */
.mo-detail{margin:0 0 9px;}
.mo-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;}
.mo-chip{
  padding:4px 11px;border-radius:999px;border:1px solid #E3E3E3;
  background:#FAFAFA;color:#68768F;
  font-family:inherit;font-size:11.5px;cursor:pointer;
}
.mo-chip.is-on{
  color:#fff;background:#576B95;
  border-color:#576B95;
}
.mo-cform{display:flex;gap:7px;}
.mo-cinput{
  flex:1;min-width:0;padding:8px 11px;
  border:1px solid #E3E3E3;border-radius:8px;
  background:#FAFAFA;color:#1A1A1A;
  font-family:inherit;font-size:13px;outline:none;
}
.mo-cinput:focus{border-color:#576B95;background:#fff;}
.mo-csend{
  flex:none;padding:8px 14px;border:0;border-radius:8px;
  background:#07C160;color:#fff;
  font-family:inherit;font-size:12.5px;cursor:pointer;
}

/* ---- 已有的赞和评论：一块 #F7F7F7，赞一行、评论若干行 ---- */
.mo-grey{
  margin:2px 0 4px;padding:8px 10px;border-radius:4px;
  background:#F7F7F7;
}
.mo-grey-likes{
  display:flex;align-items:flex-start;gap:6px;
  padding:3px 0;font-size:12.5px;line-height:1.6;color:#576B95;
}
.mo-grey-likes svg{
  flex:none;width:15px;height:15px;margin-top:2px;color:#576B95;
}
/* 评论之间**不画分隔线** —— 微信就是紧挨着的，画线反而像表格 */
.mo-grey-comment{
  position:relative;
  display:flex;align-items:baseline;gap:0;
  padding:4px 0;font-size:12.5px;line-height:1.6;color:#1A1A1A;
}
.mo-grey-name{color:#576B95;}
.mo-grey-text{flex:1;min-width:0;word-break:break-word;}

/* ---- 发布弹层（白卡，跟微信的发动态页一个气质）---- */
.mo-composer{
  background:#fff;color:#1A1A1A;
  padding:16px 16px calc(env(safe-area-inset-bottom) + 16px);
}
.mo-composer .mo-chip{
  background:#F7F7F7;border-color:#E3E3E3;color:#68768F;
}
.mo-composer .mo-chip.is-on{
  color:#fff;background:#07C160;border-color:#07C160;
}
.mo-composer-text{
  width:100%;resize:none;
  border:0;border-bottom:1px solid #ECECEC;border-radius:0;
  background:#fff;color:#1A1A1A;
  font-family:inherit;font-size:15px;line-height:1.6;
  padding:6px 0 10px;outline:none;margin-bottom:14px;
}
.mo-composer-text:focus{border-color:#07C160;}
.mo-composer-acts{display:flex;gap:10px;margin-top:14px;}
.mo-composer-acts .mo-btn{flex:1;}
.mo-composer-acts .mo-csend{flex:1;padding:10px;}


/* 桌面页不显示滚动条。
   子页面打开时桌面会被推到屏幕左边，它的滚动条 thumb（绿色那根）
   正好从屏幕左缘探出一小截 —— 各个页面的截图里都有，就是这个。 */
.page[data-page="home"]{scrollbar-width:none;}
.page[data-page="home"]::-webkit-scrollbar{width:0;height:0;display:none;}

/* 朋友圈：状态栏 + 顶栏**都是透明的**，页面底色刷白。
   判断方式是 **CSS 自己看 DOM**（:has），不由 JS 打类 ——
   JS 打类踩过坑：页面实例被复用、或者点的是当前 tab 时 paint 会提前 return，
   类就打不上了，状态栏又绿回去。
   限定 .page.is-active:not(.is-behind) = 栈顶那一页，
   不然被推出去的旧页面里若也留着 is-moments，会隔着好几层影响栈顶。
   状态栏**一个字都不改背景**（用户：「所有的屏幕的显示都改成透明底」）——
   它本来就是 absolute 浮在页面上，透明就能看见封面自己顶上来。 */
/* 朋友圈那一屏**没有底栏** —— 底栏是「聊天 App」的，微信里朋友圈是独立一屏。
   用户：「tab 点到朋友圈的时候去掉底栏吧」。藏掉之后 .app-body 自动撑满，
   内容区正好多出一截。 */
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .tab-bar{display:none;}
/* 封面要顶到**屏幕最上边**（含状态栏那一条）—— 所以这一屏的 page-inner
   不要那段「补状态栏高度」的 padding-top。 */
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .page.has-tabbar .page-inner{
  position:relative;padding-top:0;
}
/* 状态栏文字压在封面（深色渐变 / 用户自己贴的图）上，换成白字 + 一点阴影，
   不然深灰糊在深底上看不见。背景保持透明。 */
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) #statusbar{
  color:#fff;text-shadow:0 1px 4px rgba(0,0,0,.42);
}
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .page.has-tabbar{background:#fff;}
/* 顶栏**透明浮在封面上**。微信的朋友圈就是这样：封面从屏幕顶长下来，
   只有返回箭头和相机浮在图上（用户：「顶栏应该是透明的才对喔」）。所以：
     ① absolute 脱离文档流 —— 不然它会把封面挤到下面去，顶上留一条白带；
     ② 底色 / 毛玻璃 / 底部分隔线全撤掉；
     ③ 里面的按钮压在图上看不清，给一层淡黑底 + 白字；
     ④ top 要**让开状态栏那一条**（状态栏现在不占布局了，顶栏得自己避让）。 */
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .app-head{
  position:absolute;top:calc(env(safe-area-inset-top) + 32px);left:0;right:0;
  background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;
  z-index:6;
}
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .app-head::after{display:none;}
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .back-btn{
  background:rgba(0,0,0,.18);border-color:transparent;color:#fff;
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .head-act{background:rgba(0,0,0,.18);color:#fff;}
#phone:has(.page.is-active:not(.is-behind) .tab-panel.is-moments) .head-act svg{stroke:#fff;}

/* ---------------- 聊天里的照片（本体在 IndexedDB） ----------------
   以前发照片只存了个文件名，气泡里永远是一张灰卡。
   现在真能看见图了；图取不到时退化成一句「这张图找不到了」。 */
.msg-photo{
  max-width:210px;border-radius:12px;overflow:hidden;
  background:rgba(0,0,0,.06);line-height:0;
  cursor:pointer;
}
.msg-photo-img{display:block;width:100%;height:auto;}
.msg-photo.is-missing{
  line-height:1.6;padding:14px 12px;text-align:center;cursor:default;
  font-size:12px;color:var(--text-faint);
  border:1px dashed var(--g-glass-line);background:transparent;
}

/* ============================================================
   表情包：分组 + 批量导入
   ------------------------------------------------------------
   用户要的三件事：能导入各种文件、URL 要配文字解释、能分组
   （「小熊」「小猫」）。解释就是 stk-name，分组是 stk-group。
   ============================================================ */

.stk-group{margin-bottom:16px;}
.stk-group:not(.is-open){margin-bottom:10px;}
.stk-group:last-child{margin-bottom:0;}
.stk-group-head{display:flex;align-items:center;gap:8px;margin:0 0 10px;}
/* 组头整块可点（展开/收起）。注意**不能把 button 嵌进 button** ——
   所以左边是 toggle 按钮、右边「改名」是另一个，靠 flex 排开。 */
.stk-group-toggle{
  flex:1;min-width:0;display:flex;align-items:center;gap:7px;
  padding:6px 8px;margin:-6px -8px;border:0;border-radius:11px;
  background:none;font-family:inherit;text-align:left;cursor:pointer;
}
.stk-group-toggle:active{background:rgba(111,184,106,.12);}
.stk-group-arrow{
  flex:none;display:block;width:15px;height:15px;color:var(--text-faint);
  transition:transform .18s var(--ease);
}
.stk-group-arrow svg{display:block;width:15px;height:15px;}
.stk-group.is-open .stk-group-arrow{transform:rotate(90deg);}
.stk-group-name{
  font-size:12.5px;font-weight:600;color:var(--g-accent-deep);
  letter-spacing:.3px;
}
.stk-group-n{font-size:10.5px;color:var(--text-faint);}
.stk-group-op{
  margin-left:auto;padding:2px 8px;border:0;border-radius:8px;
  background:none;font-family:inherit;font-size:11px;
  color:var(--text-faint);cursor:pointer;
}
.stk-group-op:active{background:rgba(111,184,106,.14);}

/* 本地图取不到时的占位（图库清过、或者记录来自别的设备） */
.stk-av.is-missing{
  background:repeating-linear-gradient(45deg,#EFEFEF 0 6px,#F7F7F7 6px 12px);
}

/* 行内的「改」（文字的），比挪/删那两个图标宽一点 */
.stk-op-word{width:auto;padding:0 7px;font-size:11.5px;}

/* ---- 导入浮层 ---- */
.stk-import .dl-card{max-height:86vh;overflow-y:auto;}
.stk-import .dl-note{margin-bottom:12px;}
.stk-import .btn-row{margin:4px 0 0;}
.stk-import .set-field{margin-bottom:12px;}

/* ---- 表情墙：一格一张图 ----
   为什么是网格不是列表：表情包本来就是「一堆图」，一格一张才看得清；
   点开一格进详情（改解释 / 同步到全局 / 删）。
   组里**第一格是「+」** —— 单独往这一组加图片
   （用户：「加入单张图片可以在每个组的最前面加一个这样的」）。 */
.stk-grid{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:11px 9px;
}
.stk-item{display:flex;flex-direction:column;gap:5px;min-width:0;}
.stk-cell{
  position:relative;width:100%;aspect-ratio:1/1;padding:0;
  border:1px solid var(--g-glass-line);border-radius:13px;
  background:#fff center/cover no-repeat;
  cursor:pointer;
  transition:transform .14s var(--ease),box-shadow .14s var(--ease);
}
.stk-cell:active{transform:scale(.94);}
.stk-cell.is-missing{
  background:repeating-linear-gradient(45deg,#EFEFEF 0 6px,#F7F7F7 6px 12px);
}
.stk-cell-add{
  display:flex;align-items:center;justify-content:center;
  border:1.5px dashed rgba(139,108,76,.42);
  background:rgba(255,255,255,.45);
  color:var(--g-accent-deep);
}
.stk-cell-add:active{background:rgba(111,184,106,.14);}
.stk-cell-add svg{display:block;width:22px;height:22px;}
.stk-cell-name{
  font-size:10.5px;line-height:1.3;text-align:center;
  color:var(--text-faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ---- 单张的详情 ---- */
.stk-detail-img{
  width:100%;height:150px;margin:2px 0 14px;border-radius:14px;
  border:1px solid var(--g-glass-line);
  background:#F4F4F4 center/contain no-repeat;
}
.stk-detail-sw{margin-bottom:2px;}
.stk-detail-hint{margin:4px 0 12px;font-size:11px;color:var(--text-faint);}
.stk-file-note{
  margin:8px 0 0;min-height:14px;
  font-size:11px;color:var(--text-faint);
}

/* ============================================================
   聊天里的表情：推荐条 / 表情气泡 / 表情面板
   ------------------------------------------------------------
   用户要的：「输入某个文字之后可以匹配上对应的推荐表情包，
   并且推荐的表情包可以左右滑动显示，以防显示不完整」。
   ============================================================ */

/* ---- 输入框上面的推荐条 ----
   **横向可滑**是刚需：命中十几张的时候一行放不下，不能让它被裁掉。 */
.stk-suggest{
  display:none;gap:8px;
  padding:8px 0 7px;
  overflow-x:auto;overflow-y:hidden;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.stk-suggest::-webkit-scrollbar{display:none;}
.stk-suggest.is-on{display:flex;}
.stk-sg-cell{
  flex:none;width:54px;height:54px;padding:0;
  border:1px solid var(--g-glass-line);border-radius:12px;
  background:#fff center/cover no-repeat;cursor:pointer;
  transition:transform .14s var(--ease);
}
.stk-sg-cell:active{transform:scale(.92);}

/* ---- 表情消息：贴图本身，没有气泡框（微信那样） ---- */
.msg-sticker{max-width:132px;line-height:0;}
.msg-sticker-img{display:block;width:100%;height:auto;}
/* 图挂了也要**保持大图的样子**（跟正常表情一样的方块），
   只是中间写一句 —— 用户：「外链挂了也是发表情包的那种大图的样子？
   但是上面写的是「表情包丢失了qwq」」。别缩成一行小字。 */
.msg-sticker.is-missing{
  width:132px;height:132px;
  display:flex;align-items:center;justify-content:center;
  padding:10px;text-align:center;line-height:1.7;
  font-size:12px;color:var(--text-faint);
  border:1px dashed var(--g-glass-line);border-radius:14px;
  background:rgba(255,255,255,.42);
}

/* ---- 表情面板（加号 → 表情包）：底部弹一层 ---- */
.stk-panel-mask{
  position:absolute;inset:0;z-index:70;
  display:flex;align-items:flex-end;
  background:rgba(44,62,45,.28);
  opacity:0;transition:opacity .2s var(--ease);
}
.stk-panel-mask.is-open{opacity:1;}
.stk-panel{
  width:100%;max-height:56vh;
  display:flex;flex-direction:column;gap:10px;
  padding:14px 16px calc(env(safe-area-inset-bottom) + 14px);
  background:var(--surface-solid);
  border-radius:20px 20px 0 0;
  box-shadow:0 -8px 30px rgba(44,62,45,.16);
  transform:translateY(14px);
  transition:transform .22s var(--ease);
}
.stk-panel-mask.is-open .stk-panel{transform:translateY(0);}
.stk-panel-tabs{
  flex:none;display:flex;gap:7px;
  overflow-x:auto;scrollbar-width:none;
}
.stk-panel-tabs::-webkit-scrollbar{display:none;}
.stk-panel-chip{
  flex:none;padding:5px 13px;border-radius:999px;
  border:1px solid var(--g-glass-line);background:rgba(255,255,255,.62);
  font-family:inherit;font-size:12px;color:var(--text-dim);cursor:pointer;
}
.stk-panel-chip.is-on{
  background:var(--g-accent);border-color:var(--g-accent-deep);color:#F4FCF3;
}
.stk-panel-grid{
  flex:1;min-height:0;overflow-y:auto;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:10px 9px;align-content:start;
}
.stk-panel-cell{
  width:100%;aspect-ratio:1/1;padding:0;
  border:1px solid var(--g-glass-line);border-radius:13px;
  background:#fff center/cover no-repeat;cursor:pointer;
  transition:transform .14s var(--ease);
}
.stk-panel-cell:active{transform:scale(.92);}

/* 表情面板底部的「管理表情包 ›」—— 从聊天直接去管理页，不用绕「我」*/
.stk-panel-foot{
  flex:none;display:flex;justify-content:flex-end;
  padding-top:2px;
}
.stk-panel-mgr{
  padding:6px 10px;border:0;border-radius:10px;background:none;
  font-family:inherit;font-size:12px;color:var(--g-accent-deep);cursor:pointer;
}
.stk-panel-mgr:active{background:rgba(111,184,106,.14);}

/* ============================================================
   朋友圈：带图 · 表情评论 · 回复 · 删除
   ============================================================ */

/* ---- 动态里的图（本体在图库，现取 objectURL） ---- */
.mo-pic{
  width:100%;max-width:220px;aspect-ratio:4/3;
  margin:8px 0 2px;border-radius:10px;
  background:#F2F2F2 center/cover no-repeat;
  border:1px solid var(--g-glass-line);
}

/* ---- 评论里的小表情 ---- */
.mo-grey-sticker{
  display:inline-block;vertical-align:middle;
  width:44px;height:44px;margin:2px 4px 2px 0;border-radius:8px;
  background:#F4F4F4 center/cover no-repeat;
  border:1px solid var(--g-glass-line);
}

/* ---- 「回复 某某：」 ---- */


/* ---- 评论行上的按钮（回复 / 删）---- */

/* ---- 「正在回复 某某」那一行 ---- */
.mo-replying{
  display:flex;align-items:center;gap:8px;
  margin-bottom:8px;padding:5px 9px;border-radius:9px;
  background:rgba(111,184,106,.12);
  font-size:11.5px;color:var(--g-accent-deep);
}
.mo-replying-x{
  margin-left:auto;padding:2px 7px;border:0;border-radius:7px;
  background:rgba(255,255,255,.6);cursor:pointer;
  font-family:inherit;font-size:11px;color:var(--text-dim);
}

/* ---- 评论输入区里的「表情」按钮 ---- */
.mo-cstk{
  flex:none;width:34px;height:34px;padding:0;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--g-glass-line);border-radius:10px;
  background:rgba(255,255,255,.6);color:var(--g-accent-deep);
  cursor:pointer;
}
.mo-cstk svg{display:block;width:19px;height:19px;}
.mo-cstk:active{background:rgba(111,184,106,.16);}

/* 快捷条里的「删除」——红色（跟赞/评论区分开） */
.mo-quick-btn.is-danger{color:var(--coral);}

/* ---- 发布弹层里的「带一张图」 ---- */
.mo-pic-ops{display:flex;gap:8px;}
/* 「带一张图」不藏起来 —— 有图时它就是「换一张」（文案由 JS 换） */

/* ============================================================
   朋友圈：评论点按菜单 · 回复样式 · 可见范围
   ============================================================ */

/* ---- 评论行：整行可点（点一下才弹「回复 / 删除」）----
   用户：「点击某个人的评论就可以选择是要删除还是回复，
   所以那个回复和 × 的按钮可以变成点一下选择」。 */
.mo-grey-comment{
  cursor:pointer;border-radius:7px;
  padding:2px 5px;margin:0 -5px;
  transition:background .14s var(--ease);
}
.mo-grey-comment:active{background:rgba(0,0,0,.06);}

/* 「甲 回复 乙：」—— 两个名字都是蓝灰，中间那个「回复」是正文色 */
.mo-grey-rep2{color:#1A1A1A;}

/* ---- 点评论弹出的小菜单 ---- */
.mo-cmenu{
  position:absolute;z-index:80;min-width:134px;
  display:flex;flex-direction:column;gap:1px;
  padding:5px;border-radius:13px;
  background:rgba(255,255,255,.985);
  border:1px solid var(--g-glass-line);
  box-shadow:0 10px 28px rgba(44,62,45,.2);
  opacity:0;transform:translateY(-5px) scale(.95);
  transform-origin:top left;
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.mo-cmenu.is-open{opacity:1;transform:translateY(0) scale(1);}
.mo-cmenu-item{
  padding:9px 12px;border:0;border-radius:9px;background:none;
  font-family:inherit;font-size:13px;color:var(--text);cursor:pointer;
  text-align:left;white-space:nowrap;
}
.mo-cmenu-item:active{background:rgba(111,184,106,.14);}
.mo-cmenu-item.is-danger{color:var(--coral);}

/* ---- 「另有 N 条没让你看」 ---- */
.mo-hidden-note{
  margin:16px 0 4px;padding:11px 13px;border-radius:12px;
  font-size:11.5px;line-height:1.7;color:var(--text-faint);text-align:center;
  border:1px dashed var(--g-glass-line);background:rgba(255,255,255,.42);
}

/* ---- 发布弹层里的「谁可以看」 ---- */

/* 相册 / 表情浮层里的空态 */
.stk-panel-empty{
  margin:0;padding:26px 16px;text-align:center;
  font-size:12px;line-height:1.8;color:var(--text-faint);
}

/* 「让他自己想一条发」那一块删了 —— 并进顶栏的刷新键（用户：
   「这个直接点我们上面那个刷新键不行嘛」）。 */

/* ============================================================
   桌面编辑态：每个组件角上的「拿掉」小叉叉
   ------------------------------------------------------------
   用户：「桌面进入编辑模式后，所有的组件都加上一个小叉叉，
   就是把这个组件删掉的意思，因为以后打算做个组件商城~」

   位置在**组件内部**的左上角，不能挂在角外面 —— .widget 是
   overflow:hidden，挂出去会被裁掉（那样看着像按钮没渲染出来）。
   ============================================================ */
.dt-kill{
  position:absolute;left:6px;top:6px;z-index:7;
  width:19px;height:19px;padding:0;border:0;border-radius:50%;
  display:none;align-items:center;justify-content:center;
  background:rgba(58,70,60,.62);color:#fff;
  box-shadow:0 2px 6px rgba(20,40,25,.26);
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  transition:background .14s var(--ease),transform .14s var(--ease);
}
.dt-kill svg{display:block;pointer-events:none;}
.dt-screen.is-editing .dt-kill{display:flex;}
.dt-kill:active{background:var(--coral);transform:scale(.88);}

/* ============================================================
   外观：配色 / 字号 / 动效（page-appearance.js 落数据，这里落样式）
   ------------------------------------------------------------
   为什么挂在 #phone 上而不是 :root：手机壳就是这一整套样式的
   作用域，挂在它上面换主题不会漏到 body 的极光背景上。
   别名（`--bg:var(--g-base)` 那一批）会在**使用处**解析，
   所以只覆盖 `--g-*` 这组就够，不用把别名再抄一遍。
   ============================================================ */

/* ---------------- 夜灯（深色） ---------------- */
#phone[data-theme="night"]{
  --g-base:#1B231D;
  --g-base-2:#212B23;
  --g-base-3:#28332A;
  --g-glass:rgba(255,255,255,.06);
  --g-glass-2:rgba(255,255,255,.09);
  --g-glass-3:rgba(255,255,255,.13);
  --g-glass-edge:rgba(255,255,255,.14);
  --g-glass-line:rgba(255,255,255,.10);
  --g-glass-shadow:0 8px 32px rgba(0,0,0,.42);
  --g-inset:inset 0 1px 4px rgba(255,255,255,.05);
  /* 深色底上「白玻璃三件套」全部要反过来：轮廓线是**亮**的、
     镜面反光要弱（深底上太亮会像一块白斑）、投影更重。 */
  --g-ring:0 0 0 1px rgba(255,255,255,.09);
  --g-spec:radial-gradient(130% 78% at 16% 4%,rgba(255,255,255,.10) 0%,rgba(255,255,255,0) 62%);
  /* 透镜层在深色底上必须整体压掉 —— 浅色那支是 rgba(255,255,255,.58)，
     直接沿用会在夜灯下糊出一片灰白墙（实测：头图和开关像不锈钢板）。 */
  --g-lens:linear-gradient(178deg,
    rgba(255,255,255,.10) 0%,
    rgba(255,255,255,.03) 34%,
    rgba(255,255,255,0) 54%,
    rgba(255,255,255,.04) 100%);
  /* 图标玻璃方块：**第五轮起不再整套翻面了**。
     上一版要在深底上把填充反过来（不然是白灯泡），但那是因为填充太实
     （alpha .84）。现在填充只有 .07~.30，本来就是透明的 ——
     亮边和高光在深色底上同样成立，翻面反而会把它压没。
     只剩投影要加重：浅色那支 rgba(46,56,80,.20) 在深底上等于没有。 */
  --tk-shadow:
    0 8px 20px rgba(0,0,0,.42),
    0 2px 5px rgba(0,0,0,.28),
    0 18px 30px -16px rgba(0,0,0,.55);
  --mode-track:rgba(255,255,255,.09);
  --mode-track-inset:rgba(0,0,0,.50);
  /* 深色主题下设置页的织物：同一张布的暗夜版本 */
  --g-fabric:#20281F;
  --g-fabric-2:#1B231C;
  /* 深色底上「强调文字」要用**浅**色才看得清 —— 直接沿用浅色主题那个
     压暗的 deep 会在深底上糊成一片。

     2026-09-17 第五轮：用户看了主屏那颗开关之后给的评价是
     「这个颜色还可以，但是要亮一些」—— 所以只提亮度、不动色相。
     accent 从 #6FB86A 提到 #8FE08A（更接近薄荷），deep 同步提亮。 */
  --g-accent:#8FE08A;
  --g-accent-deep:#BDF5B6;
  --g-accent-soft:#3E5C42;
  --g-accent-pale:#2C3B2F;
  --on-accent:#15240F;
  --ink-halo:0 1px 3px rgba(0,0,0,.62),0 0 2px rgba(0,0,0,.45);
  --g-ink:#E7EFE8;
  --g-ink-2:#A9B9AB;
  --g-ink-3:#7D8E7E;
  --surface:rgba(255,255,255,.08);
  --surface-solid:#1F2921;
  --scrim:rgba(0,0,0,.56);
  --mo-wall-1:#3B4A5C;
  --mo-wall-2:#6D7A8C;
  --mo-wall-3:#9AA6B2;
  --coral:#E88279;
}
/* 夜灯的光晕：同一套「四角打光」的结构，只是光的色温压到冷绿蓝，
   并且整体压暗 —— 深色下光一强就变成脏兮兮的雾。 */
#phone[data-theme="night"] .ambient{
  background:
    radial-gradient(120% 78% at 6% -14%,#1E2C26 0%,rgba(30,44,38,0) 60%),
    radial-gradient(110% 66% at 104% 2%,#232A38 0%,rgba(35,42,56,0) 58%),
    radial-gradient(132% 88% at 50% 118%,#16241F 0%,rgba(22,36,31,0) 64%),
    linear-gradient(180deg,#131B16 0%,#17211C 56%,#141D18 100%);
}
#phone[data-theme="night"] .ambient::before{background:#2C4A3E;opacity:.30;}
#phone[data-theme="night"] .ambient::after{background:#2A3350;opacity:.26;}
#phone[data-theme="night"] .ambient .ambient-3{background:#3A4A32;opacity:.16;}

/* ---------------- 蜜桃 ---------------- */
#phone[data-theme="peach"]{
  --g-accent:#E8846B;
  --g-accent-deep:#B85C46;
  --g-accent-soft:#FFC7B4;
  --g-accent-pale:#FFE4D8;
  --g-base:#FDF0EA;
  --g-base-2:#FBE5DC;
  --g-base-3:#F6D8CD;
  --g-ink:#3E2F2A;
  --g-ink-2:#806A62;
  --g-ink-3:#A89089;
  --g-glass:rgba(255,255,255,.48);
  --g-glass-2:rgba(255,255,255,.68);
  --g-glass-3:rgba(255,255,255,.86);
  --g-glass-edge:rgba(255,255,255,.72);
  --g-glass-line:rgba(184,92,70,.16);
  --g-glass-shadow:0 8px 32px rgba(184,92,70,.14);
  --g-inset:inset 0 2px 6px rgba(255,255,255,.78);
  /* 白玻璃三件套里「轮廓线」和「镜面反光」是全局新增的两支变量，
     旧主题里没有 —— 不补的话会继承到默认那支冷灰 / 冷白，
     在暖粉底上会脏。所以每个配色都得自己声明一遍。 */
  --g-ring:0 0 0 1px rgba(184,92,70,.10);
  --g-spec:radial-gradient(130% 78% at 16% 4%,rgba(255,255,255,.94) 0%,rgba(255,255,255,0) 64%);
  --g-lens:linear-gradient(178deg,
    rgba(255,255,255,.58) 0%,
    rgba(255,255,255,.16) 34%,
    rgba(255,255,255,0) 54%,
    rgba(244,226,218,.30) 100%);
  --g-fabric:#FDF2EC;
  --g-fabric-2:#F9E7DE;
  --mo-wall-1:#A9767A;
  --mo-wall-2:#C9A2A0;
  --mo-wall-3:#F0DED8;
}
#phone[data-theme="peach"] .ambient{
  background:
    radial-gradient(120% 78% at 6% -14%,#FFE6DC 0%,rgba(255,230,220,0) 60%),
    radial-gradient(110% 66% at 104% 2%,#FFEFF2 0%,rgba(255,239,242,0) 58%),
    radial-gradient(132% 88% at 50% 118%,#FFE2D6 0%,rgba(255,226,214,0) 64%),
    linear-gradient(180deg,#FFF8F4 0%,#FEF3EC 56%,#FDEBE2 100%);
}
#phone[data-theme="peach"] .ambient::before{background:#FFC9B4;}
#phone[data-theme="peach"] .ambient::after{background:#FFD9E4;}
#phone[data-theme="peach"] .ambient .ambient-3{background:#FFDCC2;}

/* ---------------- 海盐 ---------------- */
#phone[data-theme="sea"]{
  --g-accent:#5B93C4;
  --g-accent-deep:#3F719E;
  --g-accent-soft:#B9D8EE;
  --g-accent-pale:#DDEBF7;
  --g-base:#EDF4FA;
  --g-base-2:#E1EDF7;
  --g-base-3:#D3E4F1;
  --g-ink:#28394A;
  --g-ink-2:#5F7A92;
  --g-ink-3:#8CA4B8;
  --g-glass-line:rgba(63,113,158,.16);
  --g-glass-shadow:0 8px 32px rgba(63,113,158,.14);
  --g-ring:0 0 0 1px rgba(63,113,158,.10);
  --g-spec:radial-gradient(130% 78% at 16% 4%,rgba(255,255,255,.94) 0%,rgba(255,255,255,0) 64%);
  --g-lens:linear-gradient(178deg,
    rgba(255,255,255,.58) 0%,
    rgba(255,255,255,.16) 34%,
    rgba(255,255,255,0) 54%,
    rgba(220,232,244,.30) 100%);
  --g-fabric:#EFF4F9;
  --g-fabric-2:#E6EFF7;
  --mo-wall-1:#4E6B85;
  --mo-wall-2:#8FA7BC;
  --mo-wall-3:#DCE6EE;
}
#phone[data-theme="sea"] .ambient{
  background:
    radial-gradient(120% 78% at 6% -14%,#DCEBFA 0%,rgba(220,235,250,0) 60%),
    radial-gradient(110% 66% at 104% 2%,#E7F0FF 0%,rgba(231,240,255,0) 58%),
    radial-gradient(132% 88% at 50% 118%,#D8EBF8 0%,rgba(216,235,248,0) 64%),
    linear-gradient(180deg,#F7FBFF 0%,#F2F8FD 56%,#E9F3FB 100%);
}
#phone[data-theme="sea"] .ambient::before{background:#B6D3F0;}
#phone[data-theme="sea"] .ambient::after{background:#C6D8FA;}
#phone[data-theme="sea"] .ambient .ambient-3{background:#C9E6F5;}

/* ---------------- 减少动效 ----------------
   一刀切，不逐个组件去停 —— 逐个改一定会漏，漏掉那个就是「关不干净」。 */
#phone[data-motion="off"] *,
#phone[data-motion="off"] *::before,
#phone[data-motion="off"] *::after{
  transition:none !important;
  animation:none !important;
}

/* ============================================================
   外观页自己的样式
   ============================================================ */

.look-grid{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:11px;padding:13px 13px 15px;
}
.look-card{
  display:flex;flex-direction:column;gap:3px;
  padding:10px;border-radius:15px;
  border:1px solid var(--g-glass-line);background:var(--g-glass-2);
  font-family:inherit;text-align:left;cursor:pointer;
  transition:border-color .16s var(--ease),background .16s var(--ease);
}
.look-card:active{background:rgba(111,184,106,.12);}
.look-card.is-on{border-color:var(--g-accent);background:rgba(111,184,106,.14);}
.look-sw{
  display:block;height:40px;border-radius:11px;margin-bottom:8px;
  border:1px solid rgba(0,0,0,.06);
}
.look-card-name{font-size:13.5px;color:var(--text);}
.look-card-hint{font-size:10.5px;line-height:1.4;color:var(--text-faint);}

.look-seg{display:flex;gap:8px;padding:13px 13px 4px;}
.look-seg-btn{
  flex:1;padding:9px;border-radius:11px;
  border:1px solid var(--g-glass-line);background:var(--g-glass-2);
  font-family:inherit;font-size:13px;color:var(--text-dim);cursor:pointer;
}
.look-seg-btn:active{background:rgba(111,184,106,.12);}
.look-seg-btn.is-on{
  background:var(--g-accent);border-color:var(--g-accent-deep);color:#F4FCF3;
}

.look-demo{
  margin:10px 13px 15px;padding:12px 13px;border-radius:13px;
  border:1px dashed var(--g-glass-line);background:var(--g-glass);
}
.look-demo-tag{
  font-size:10.5px;letter-spacing:.5px;color:var(--text-faint);margin-bottom:7px;
}
.look-demo-text{
  margin:0;font-size:calc(14px * var(--fs-scale, 1));line-height:1.6;
  color:var(--text);
}

/* ============================================================
   朋友圈：发布弹层微信化（2026-09-17）
   ------------------------------------------------------------
   用户：「解释的太多了，而且绿色很丑」「仿照微信的页面」。
   老的那堆绿按钮 / 虚线绿框 / 解释文字全部退场。
   ============================================================ */

/* ---- 身份 chips（紧凑一行）---- */
.mo-who{margin-bottom:12px;}
.mo-who .mo-chip{padding:4px 12px;font-size:12px;}

/* ---- 配图行：缩略图 + 右上角小叉 ---- */
.mo-pic-row{display:none;position:relative;margin:0 0 10px;}
.mo-pic-row.has-pic{display:block;}
.mo-pic-thumb{
  display:block;width:110px;height:110px;border-radius:10px;
  background:#F4F4F4 center/cover no-repeat;
  border:1px solid #E5E5E5;
}
.mo-pic-x{
  position:absolute;right:-8px;top:-8px;width:20px;height:20px;
  border:0;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;
  font-size:13px;line-height:1;cursor:pointer;font-family:inherit;
  display:flex;align-items:center;justify-content:center;
}

/* ---- 表情按钮（选一张表情当配图）---- */
.mo-emoji-row{display:flex;margin:2px 0 12px;}
.mo-emoji-btn{
  width:36px;height:36px;padding:0;border:0;border-radius:9px;
  background:none;color:#8A8A8A;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
.mo-emoji-btn:active{background:#F2F2F2;}
.mo-emoji-btn svg{display:block;}

/* ---- 设置行（谁可以看 / 提醒谁看）—— 微信那种列表行 ---- */
.mo-set-group{
  margin:2px -16px calc(env(safe-area-inset-bottom) + 8px);
  border-top:1px solid #F0F0F0;
}
.mo-set-row{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:13px 16px;border:0;background:none;
  font-family:inherit;font-size:14.5px;color:#1A1A1A;
  text-align:left;cursor:pointer;
}
.mo-set-row + .mo-set-row{border-top:1px solid #F0F0F0;}
.mo-set-row:active{background:#F7F7F7;}
.mo-set-row svg{flex:none;color:#5B5B5B;}
.mo-set-label{flex:none;}
.mo-set-val{
  margin-left:auto;font-size:13.5px;color:#9A9A9A;
  max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.mo-set-arrow{flex:none;color:#C8C8C8;font-size:15px;}

/* ---- 微信式大按钮：白底黑字 / 灰底黑字，不再有大绿块 ---- */
.mo-btn{
  flex:1;padding:11px;border-radius:8px;border:0;
  font-family:inherit;font-size:15px;cursor:pointer;
  transition:opacity .15s var(--ease);
}
.mo-btn-main{background:#fff;color:#1A1A1A;border:1px solid #E5E5E5;}
.mo-btn-main.is-idle{color:#C0C0C0;}
.mo-btn-alt{background:#F7F7F7;color:#1A1A1A;}
.mo-btn:active{opacity:.7;}

/* ---- 「谁可以看」选择页 ---- */
.mo-privacy .mo-composer-title{margin-bottom:12px;}
.mo-radio-list{display:flex;flex-direction:column;}
.mo-radio{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:13px 2px;border:0;background:none;
  font-family:inherit;text-align:left;cursor:pointer;
}
.mo-radio + .mo-radio{border-top:1px solid #F2F2F2;}
.mo-radio-dot{
  flex:none;width:18px;height:18px;border-radius:50%;
  border:1.6px solid #C8C8C8;background:#fff;
}
.mo-radio.is-on .mo-radio-dot{
  border-color:var(--g-accent);
  background:radial-gradient(circle at center, var(--g-accent) 0 5px, #fff 5.5px);
}
.mo-radio-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.mo-radio-name{font-size:14.5px;color:#1A1A1A;}
.mo-radio-hint{font-size:11.5px;color:#9A9A9A;}
.mo-radio-arrow{flex:none;color:#C8C8C8;}
.mo-pick-people{padding:4px 2px 6px;}
.mo-pick-people .mo-composer-label{margin-bottom:8px;}
.mo-pick-chips{max-height:150px;overflow-y:auto;margin-bottom:10px;}

/* ============================================================
   预设（预设注入系统配置 app）—— page-presets.js
   UI 硬要求：不得太多圆角框。所以这页走「列表 + 分隔线」的扁平结构：
   没有卡片容器，行与行用一条分隔线隔开，圆角只留给开关和胶囊。
   ============================================================ */
.pp-engine{
  display:flex;align-items:center;gap:12px;
  padding:14px 4px 16px;
  border-bottom:1px solid var(--line);
  margin-bottom:18px;
}
.pp-engine.is-off{opacity:.75;}
.pp-engine-main{flex:1;min-width:0;}
.pp-engine-title{margin:0 0 3px;font-size:14px;color:var(--text);}
.pp-engine-sub{margin:0;font-size:11px;color:var(--text-faint);line-height:1.5;}

.pp-sec{margin-bottom:22px;}
.pp-sec-head{display:flex;align-items:baseline;justify-content:space-between;}
.pp-sec-title{
  margin:0 0 6px 4px;
  font-size:11px;letter-spacing:1.4px;
  color:var(--text-faint);text-transform:uppercase;
}
.pp-sec-note{margin:0 4px 10px;font-size:11px;line-height:1.6;color:var(--text-faint);}

.pp-row{
  width:100%;display:flex;align-items:center;gap:9px;
  padding:12px 4px;background:none;border:0;
  border-bottom:1px solid var(--line);
  font-family:inherit;text-align:left;cursor:pointer;color:inherit;
}
.pp-row:last-child{border-bottom:0;}
.pp-row:active{background:var(--bg-3);}
/* 程序槽在注入序列里是 div（不可点），别给手型 */
div.pp-row{cursor:default;}
div.pp-row:active{background:none;}
.pp-row.is-off{opacity:.42;}
.pp-row.is-soon{cursor:default;opacity:.42;}
.pp-row.is-soon:active{background:none;}
.pp-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}
.pp-row-label{font-size:calc(14px * var(--fs-scale, 1));color:var(--text);}
.pp-row-hint{font-size:11px;color:var(--text-faint);line-height:1.5;}
.pp-row-arrow{flex:none;font-size:17px;color:var(--text-faint);line-height:1;}
.pp-row-tag{
  flex:none;font-size:9.5px;letter-spacing:.5px;
  color:var(--text-faint);
  border:1px solid var(--line);border-radius:7px;
  padding:2px 6px;
}
.pp-row-tok{flex:none;font-size:10.5px;color:var(--text-dim);}
.pp-row-req{flex:none;font-size:9.5px;color:var(--text-faint);opacity:.8;}
/* 上锁标（第三梯队 7）：无框小字，跟行尾其他标区分开 */
.pp-row-lock{
  flex:none;font-size:9.5px;letter-spacing:.5px;
  color:var(--g-accent-deep,#967346);opacity:.85;
}

.pp-add{
  flex:none;border:0;background:none;font-family:inherit;
  font-size:12.5px;color:var(--g-accent);cursor:pointer;padding:2px 6px;
}
.pp-empty{margin:6px 4px 0;font-size:12px;color:var(--text-faint);}

.pp-foot{margin:6px 4px 0;font-size:11px;color:var(--text-faint);line-height:1.6;}
.pp-plain{margin:4px 4px 0;font-size:12px;line-height:1.7;color:var(--text-dim);}
.pp-locked{
  margin:10px 4px 0;padding:10px 12px;
  font-size:12px;color:var(--text-dim);
  border-left:2px solid var(--g-accent);
  background:var(--bg-2);
}

/* 调试预览 */
/* 预览对象切换（线上对话 / 线下场景）：文字页签，不加重框 */
.pp-mode-row{display:flex;gap:16px;margin:0 2px 10px;}
.pp-mode-btn{
  border:0;background:none;font-family:inherit;
  font-size:13px;color:var(--text-faint);
  padding:2px 0 6px;cursor:pointer;
  border-bottom:2px solid transparent;
}
.pp-mode-btn.active{color:var(--text);border-bottom-color:var(--g-accent);}
.pp-select{
  width:100%;appearance:none;-webkit-appearance:none;
  background:var(--surface);border:1px solid var(--g-glass-line);
  border-radius:10px;padding:10px 12px;
  color:var(--text);font-family:inherit;font-size:13px;
  margin-bottom:14px;
}
.pp-sum{margin-bottom:12px;}
.pp-sum-table{border-bottom:1px solid var(--line);}
.pp-sum-line{
  display:flex;align-items:baseline;gap:9px;
  padding:7px 2px;border-bottom:1px dashed var(--line);
  font-size:11.5px;
}
.pp-sum-line:last-child{border-bottom:0;}
.pp-sum-line.is-off{opacity:.42;}
.pp-sum-slot{flex:none;width:64px;color:var(--g-accent);font-size:10px;letter-spacing:.5px;}
.pp-sum-name{flex:1;min-width:0;color:var(--text-dim);}
.pp-sum-tok{flex:none;color:var(--text-faint);}
.pp-sum-total{margin:10px 2px 0;font-size:12px;color:var(--text-dim);}
.pp-sum-total.is-ok{color:#8FAE84;}
.pp-sum-total.is-warn{color:#C2A45C;}
.pp-sum-total.is-over{color:#C07A6B;}
.pp-pre{
  margin:0;padding:12px;
  background:var(--surface);border:1px solid var(--g-glass-line);
  border-radius:10px;
  font-size:11px;line-height:1.7;white-space:pre-wrap;word-break:break-word;
  color:var(--text-dim);max-height:60vh;overflow-y:auto;
}

/* ============================================================
   线下模式（page-offline.js）—— 从场景空间 Demo 逐值移植。
   配色变量与 Demo 完全一致（一个值都没动）；类名加 off- 前缀
   避免和现有页面撞名。demo 的 body 级主题类改成 .off-root 上的类。
   ============================================================ */
.page.is-bleed .page-inner{padding:0;}
/* 状态栏区域透明：线下自己的顶栏背景直接顶到最上沿，
   时间电量浮在页面配色上（用户：「直接透出下面的背景」） */
.off-header{padding-top:calc(env(safe-area-inset-top) + 32px);}
.page.is-bleed .app-head{display:none;}

.off-root{
  --bg: #f5f0e8;
  --bg-header: #f0ebe0;
  --bg-scroll: #f7f2ea;
  --bg-bottom: #f0ebe0;
  --warm: #8a6640;
  --warm-mid: #b08050;
  --warm-dim: #c4a878;
  --warm-faint: rgba(138,102,64,0.07);
  --text: #2a2018;
  --text-dim: #6b5a46;
  --text-faint: #b09a80;
  --char-text: #2e1f10;
  --scene-text: #7a6650;
  --border: rgba(138,102,64,0.14);
  --border-soft: rgba(138,102,64,0.1);
  --tag-bg: rgba(138,102,64,0.08);
  --tag-border: rgba(138,102,64,0.2);
  --input-bg: rgba(255,255,255,0.7);
  --sheet-bg: #ede7db;
  --suggest-line: rgba(138,102,64,0.12);
  --off-scrim: rgba(58,46,32,.20);

  flex:1;
  display:flex;
  flex-direction:column;
  overflow:hidden;
  background:var(--bg);
  color:var(--text);
  font-family:'PingFang SC','Hiragino Sans GB','Noto Sans SC',sans-serif;
  transition:background 0.4s, color 0.4s;
  min-height:0;
}
.off-root.theme-dusk{
  --bg:#1c1714; --bg-header:#181410; --bg-scroll:#1a1511; --bg-bottom:#181410;
  --warm:#c9a97a; --warm-mid:#a07848; --warm-dim:#8a6f4e;
  --warm-faint:rgba(201,169,122,0.08);
  --text:#ede4d8; --text-dim:#a8998a; --text-faint:#635648;
  --char-text:#dfc9a8; --scene-text:#a89888;
  --border:rgba(201,169,122,0.13); --border-soft:rgba(255,255,255,0.07);
  --tag-bg:rgba(201,169,122,0.09); --tag-border:rgba(201,169,122,0.22);
  --input-bg:rgba(255,255,255,0.05); --sheet-bg:#201c18;
  --suggest-line:rgba(201,169,122,0.13);
  --off-scrim: rgba(0,0,0,.42);
}
.off-root.theme-mist{
  --bg:#eef2f5; --bg-header:#e8ecf0; --bg-scroll:#f0f4f7; --bg-bottom:#e8ecf0;
  --warm:#5a7a96; --warm-mid:#7a9ab6; --warm-dim:#9ab4c8;
  --warm-faint:rgba(90,122,150,0.07);
  --text:#1a2530; --text-dim:#5a7080; --text-faint:#9ab0c0;
  --char-text:#1e2e3a; --scene-text:#6a8090;
  --border:rgba(90,122,150,0.14); --border-soft:rgba(90,122,150,0.1);
  --tag-bg:rgba(90,122,150,0.08); --tag-border:rgba(90,122,150,0.2);
  --input-bg:rgba(255,255,255,0.7); --sheet-bg:#e4e8ed;
  --suggest-line:rgba(90,122,150,0.12);
  --off-scrim: rgba(30,44,58,.18);
}
.off-root.theme-rose{
  --bg:#f7f0f2; --bg-header:#f0e8ec; --bg-scroll:#f9f2f5; --bg-bottom:#f0e8ec;
  --warm:#9a6070; --warm-mid:#b88090; --warm-dim:#d0a0b0;
  --warm-faint:rgba(154,96,112,0.07);
  --text:#2a1820; --text-dim:#7a5060; --text-faint:#c0a0a8;
  --char-text:#2e1820; --scene-text:#8a6070;
  --border:rgba(154,96,112,0.14); --border-soft:rgba(154,96,112,0.1);
  --tag-bg:rgba(154,96,112,0.08); --tag-border:rgba(154,96,112,0.2);
  --input-bg:rgba(255,255,255,0.7); --sheet-bg:#ede4e8;
  --suggest-line:rgba(154,96,112,0.12);
  --off-scrim: rgba(58,32,42,.18);
}

/* ══ 固定顶部 ══ */
.off-header{
  flex-shrink:0;
  background:var(--bg-header);
  border-bottom:1px solid var(--border);
  transition:background 0.4s;
}
.off-topbar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:11px 14px 10px;
  gap:8px;
}
.off-topbar-left{display:flex;align-items:center;gap:8px;flex-shrink:0;}
.off-back-btn{
  width:28px;height:28px;border-radius:50%;
  border:1px solid var(--border);
  background:rgba(255,255,255,0.4);
  cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;transition:background 0.18s;
  padding:0;
}
.off-back-btn:hover{background:rgba(255,255,255,0.7);}
.off-back-btn svg{width:13px;height:13px;stroke:var(--warm);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
.off-scene-title{display:flex;flex-direction:column;gap:1px;}
.off-scene-name{font-size:13px;font-weight:500;color:var(--text);letter-spacing:0.02em;line-height:1.3;white-space:nowrap;}
.off-scene-sub{font-size:10px;color:var(--text-faint);letter-spacing:0.04em;white-space:nowrap;}
.off-topbar-right{display:flex;align-items:center;gap:7px;flex-shrink:0;}
.off-api-pill{
  display:flex;align-items:center;gap:5px;
  padding:4px 10px;border-radius:20px;
  border:1px solid var(--tag-border);
  background:var(--tag-bg);
  cursor:pointer;transition:background 0.18s;white-space:nowrap;
  font-family:inherit;
}
.off-api-pill:hover{background:rgba(138,102,64,0.14);}
.off-api-dot{width:5px;height:5px;border-radius:50%;background:#6ab880;box-shadow:0 0 5px #6ab880;flex-shrink:0;}
.off-api-label{font-size:10px;color:var(--warm);letter-spacing:0.03em;}
.off-settings-btn{
  width:28px;height:28px;border-radius:50%;
  border:1px solid var(--border);
  background:rgba(255,255,255,0.4);
  cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;transition:background 0.18s;
  padding:0;
}
.off-settings-btn:hover{background:rgba(255,255,255,0.7);}
.off-settings-btn svg{width:13px;height:13px;stroke:var(--warm);fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;}

/* 环境条 */
.off-env-strip{
  display:flex;align-items:center;
  padding:6px 14px 7px;
  border-top:1px solid var(--border);
  gap:0;overflow:hidden;
}
.off-env-item{
  display:flex;align-items:center;gap:4px;
  font-size:11px;color:var(--text-faint);
  letter-spacing:0.02em;white-space:nowrap;flex-shrink:0;
}
.off-env-item svg{width:11px;height:11px;stroke:var(--warm-mid);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;opacity:0.75;flex-shrink:0;}
.off-env-sep{width:1px;height:10px;background:var(--border);margin:0 10px;flex-shrink:0;}
.off-env-spacer{flex:1;}
.off-time-capsule{
  display:inline-flex;align-items:center;gap:5px;
  padding:2px 8px;border-radius:20px;
  background:var(--warm-faint);border:1px solid var(--border);flex-shrink:0;
}
.off-time-bar{display:flex;gap:2px;align-items:flex-end;}
.off-time-bar span{display:block;width:2.5px;border-radius:2px;background:var(--warm-mid);}
.off-time-bar span:nth-child(1){height:5px;opacity:0.35;}
.off-time-bar span:nth-child(2){height:7px;opacity:0.55;}
.off-time-bar span:nth-child(3){height:9px;opacity:0.75;}
.off-time-bar span:nth-child(4){height:6px;opacity:0.5;}
.off-time-bar span:nth-child(5){height:4px;opacity:0.3;}
.off-time-label{font-size:10px;color:var(--warm);letter-spacing:0.04em;}

/* ══ 滚动区 ══ */
.off-chat-scroll{
  flex:1;overflow-y:auto;
  padding:20px 18px 16px;
  display:flex;flex-direction:column;gap:24px;
  scrollbar-width:none;
  background:var(--bg-scroll);
  transition:background 0.4s;
  min-height:0;
}
.off-chat-scroll::-webkit-scrollbar{display:none;}

/* 开场场景块 */
.off-scene-block{border-bottom:1px solid var(--border);padding-bottom:18px;}
.off-scene-prose{
  font-size:12.5px;line-height:2;
  color:var(--scene-text);
  font-style:italic;letter-spacing:0.03em;
  padding-left:12px;
  border-left:1.5px solid var(--warm-dim);
  margin:0;
}

/* 用户行动 */
.off-user-action{
  align-self:flex-end;max-width:80%;
  display:flex;flex-direction:column;align-items:flex-end;gap:3px;
}
.off-user-tag{font-size:9.5px;color:var(--text-faint);letter-spacing:0.05em;}
.off-user-action-text{
  font-size:13px;color:var(--text-dim);line-height:1.75;
  text-align:right;letter-spacing:0.015em;font-style:italic;
}

/* Char 输出块 */
.off-char-block{
  display:flex;flex-direction:column;gap:0;
  padding-left:13px;position:relative;
}
.off-char-block::before{
  content:'';position:absolute;
  left:0;top:4px;bottom:4px;width:1.5px;
  background:linear-gradient(to bottom,var(--warm-mid) 0%,rgba(138,102,64,0.1) 100%);
  border-radius:2px;
}
.off-char-name{
  font-size:9.5px;color:var(--warm);letter-spacing:0.07em;
  font-weight:500;margin-bottom:8px;text-transform:uppercase;
}
.off-char-body{display:flex;flex-direction:column;gap:10px;}
.off-char-p{
  font-size:13px;line-height:2;
  color:var(--scene-text);
  font-style:italic;letter-spacing:0.025em;
  margin:0;
}
.off-char-q{
  font-size:14px;line-height:1.8;
  color:var(--char-text);
  letter-spacing:0.02em;font-style:normal;
  font-weight:450;
  margin:0;
}

/* ══ 建议选项 ══ */
.off-suggest-block{
  display:flex;flex-direction:column;gap:0;
  padding-left:13px;position:relative;
  margin-top:-10px;
}
.off-suggest-block::before{
  content:'';position:absolute;
  left:0;top:0;bottom:0;width:1.5px;
  background:var(--suggest-line);
  border-radius:2px;
}
.off-suggest-label{
  font-size:9.5px;color:var(--text-faint);
  letter-spacing:0.06em;margin-bottom:7px;
  padding-top:12px;
  border-top:1px solid var(--suggest-line);
}
.off-suggest-list{display:flex;flex-direction:column;gap:6px;}
.off-suggest-item{
  padding:7px 13px;
  border-radius:4px;
  border:1px solid var(--tag-border);
  background:var(--tag-bg);
  font-size:12.5px;color:var(--warm);
  cursor:pointer;letter-spacing:0.02em;line-height:1.5;
  transition:all 0.18s;
  text-align:left;
  font-family:inherit;
}
.off-suggest-item:hover{
  background:rgba(138,102,64,0.14);
  border-color:rgba(138,102,64,0.35);
  transform:translateX(2px);
}

/* ══ 底部输入区 ══ */
.off-input-area{
  flex-shrink:0;
  padding:8px 14px 18px;
  background:var(--bg-bottom);
  border-top:1px solid var(--border);
  transition:background 0.4s;
}
.off-input-row{
  display:flex;align-items:flex-end;gap:9px;
  background:var(--input-bg);
  border:1px solid var(--border-soft);
  border-radius:14px;
  padding:9px 9px 9px 14px;
  transition:border-color 0.2s,background 0.4s;
  box-shadow:0 1px 4px rgba(0,0,0,0.06);
}
.off-input-row:focus-within{border-color:var(--warm-dim);}
.off-input-field{
  flex:1;background:none;border:none;outline:none;
  color:var(--text);font-size:13px;line-height:1.6;
  resize:none;font-family:inherit;
  letter-spacing:0.02em;max-height:80px;
  overflow-y:auto;scrollbar-width:none;
  padding:0;
}
.off-input-field::placeholder{color:var(--text-faint);}
.off-input-field::-webkit-scrollbar{display:none;}
.off-send-btn{
  width:30px;height:30px;border-radius:50%;
  background:linear-gradient(135deg,var(--warm-mid),var(--warm));
  border:none;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;transition:opacity 0.18s,transform 0.15s;
  padding:0;
}
.off-send-btn:hover{opacity:0.82;transform:scale(1.05);}
.off-send-btn:active{transform:scale(0.94);}
.off-send-btn:disabled{opacity:0.4;cursor:default;}
.off-send-btn svg{width:13px;height:13px;stroke:white;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;margin-left:1px;}

/* ══ 底部抽屉通用 ══ */
.off-overlay{
  position:fixed;inset:0;
  /* 遮罩色跟主题走：浅色主题用暖灰薄纱，不再是压一整块的纯黑
     （用户：「背景是黑的」→ 不要）。 */
  background:var(--off-scrim,rgba(58,46,32,.22));
  z-index:100;
  display:flex;align-items:flex-end;
  opacity:0;pointer-events:none;
  transition:opacity 0.22s;
  max-width:420px;margin:0 auto;
}
.off-overlay.show{opacity:1;pointer-events:all;}
.off-sheet{
  width:100%;background:var(--sheet-bg);
  border-top:1px solid var(--border);
  border-radius:18px 18px 0 0;
  padding:18px 18px 32px;
  transform:translateY(100%);
  transition:transform 0.28s cubic-bezier(0.32,0.72,0,1),background 0.4s;
}
.off-overlay.show .off-sheet{transform:translateY(0);}
.off-sheet-handle{width:32px;height:3px;background:var(--border);border-radius:2px;margin:0 auto 18px;}
.off-sheet-title{font-size:12px;color:var(--text-dim);letter-spacing:0.04em;margin-bottom:14px;}

/* 离开选项 */
.off-leave-options{display:flex;flex-direction:column;gap:8px;}
.off-leave-option{
  display:flex;flex-direction:column;gap:3px;
  padding:12px 15px;border-radius:9px;
  border:1px solid var(--border-soft);
  background:rgba(255,255,255,0.5);
  cursor:pointer;transition:background 0.18s,border-color 0.18s;
  font-family:inherit;text-align:left;
}
.off-leave-option:hover{background:rgba(255,255,255,0.8);border-color:var(--tag-border);}
.off-leave-option.primary .off-opt-name{color:var(--warm);}
.off-opt-main{display:flex;flex-direction:column;gap:3px;}
.off-opt-name{font-size:13px;color:var(--text);letter-spacing:0.02em;font-weight:500;}
.off-opt-desc{font-size:10.5px;color:var(--text-faint);letter-spacing:0.02em;line-height:1.5;}
.off-sheet-cancel{
  margin-top:10px;width:100%;padding:10px;
  background:none;border:1px solid var(--border);
  border-radius:9px;color:var(--text-dim);font-size:12.5px;
  cursor:pointer;letter-spacing:0.03em;
  transition:background 0.18s;font-family:inherit;
}
.off-sheet-cancel:hover{background:rgba(255,255,255,0.5);}
.off-ok-btn{background:rgba(255,255,255,0.55);border-color:var(--tag-border);color:var(--warm);}

/* API 选项 */
.off-api-wrap{display:flex;flex-direction:column;}
.off-api-list{display:flex;flex-direction:column;gap:7px;margin-top:2px;}
.off-api-option{
  display:flex;align-items:center;justify-content:space-between;
  padding:10px 13px;border-radius:9px;
  border:1px solid var(--border-soft);
  background:rgba(255,255,255,0.5);
  cursor:pointer;transition:all 0.18s;
  font-family:inherit;text-align:left;
}
.off-api-option.active{border-color:var(--tag-border);background:rgba(255,255,255,0.8);}
.off-api-option:hover{background:rgba(255,255,255,0.7);}
.off-api-opt-left{display:flex;flex-direction:column;gap:2px;}
.off-api-opt-name{font-size:12.5px;color:var(--text);letter-spacing:0.02em;font-weight:500;}
.off-api-opt-desc{font-size:10px;color:var(--text-faint);letter-spacing:0.02em;}
.off-api-check{width:17px;height:17px;border-radius:50%;border:1.5px solid var(--border);display:flex;align-items:center;justify-content:center;transition:all 0.18s;}
.off-api-option.active .off-api-check{background:var(--warm);border-color:var(--warm);}
.off-api-check-dot{width:6px;height:6px;border-radius:50%;background:white;opacity:0;transition:opacity 0.18s;}
.off-api-option.active .off-api-check-dot{opacity:1;}
.off-api-scope{display:flex;gap:7px;margin-top:12px;}
.off-scope-btn{
  flex:1;padding:7px;border-radius:7px;
  border:1px solid var(--border);background:none;
  color:var(--text-dim);font-size:10.5px;
  cursor:pointer;font-family:inherit;letter-spacing:0.02em;transition:all 0.18s;
}
.off-scope-btn.active{border-color:var(--tag-border);background:rgba(255,255,255,0.6);color:var(--warm);}
.off-scope-btn:hover{background:rgba(255,255,255,0.4);}

/* ══ 设置面板 ══ */
.off-settings-tabs{
  display:flex;gap:0;
  border-bottom:1px solid var(--border);
  margin-bottom:18px;
}
.off-settings-tab{
  flex:1;padding:9px 0;text-align:center;
  font-size:12px;letter-spacing:0.04em;
  color:var(--text-faint);cursor:pointer;
  border-bottom:2px solid transparent;
  transition:color 0.18s,border-color 0.18s;
  background:none;border-top:none;border-left:none;border-right:none;
  font-family:inherit;
  margin-bottom:-1px;
}
.off-settings-tab.active{color:var(--warm);border-bottom-color:var(--warm);}
.off-settings-panel{display:none;}
.off-settings-panel.active{display:block;}
.off-settings-section{margin-bottom:20px;}
.off-settings-section-title{
  font-size:9.5px;color:var(--text-faint);
  letter-spacing:0.08em;text-transform:uppercase;
  margin-bottom:10px;padding-left:2px;
}
.off-settings-row{
  display:flex;align-items:center;justify-content:space-between;
  padding:10px 2px;
  border-bottom:1px solid var(--border);
}
.off-settings-row:last-child{border-bottom:none;}
.off-settings-row-label{font-size:13px;color:var(--text);letter-spacing:0.02em;}
.off-settings-row-desc{font-size:10.5px;color:var(--text-faint);letter-spacing:0.02em;margin-top:2px;line-height:1.4;}
.off-settings-row-left{display:flex;flex-direction:column;gap:0;}
.off-settings-row-col{
  display:flex;flex-direction:column;gap:8px;
  padding:10px 2px;
  border-bottom:1px solid var(--border);
}
.off-settings-row-col:last-child{border-bottom:none;}

/* 壁纸选择 */
.off-wallpaper-grid{display:flex;gap:8px;flex-wrap:wrap;}
.off-wallpaper-item{
  width:64px;height:64px;border-radius:10px;
  border:2px solid transparent;
  cursor:pointer;transition:border-color 0.18s,transform 0.15s;
  position:relative;overflow:hidden;
  flex-shrink:0;
  padding:0;
}
.off-wallpaper-item:hover{transform:scale(1.04);}
.off-wallpaper-item.active{border-color:var(--warm);}
.off-wp-preview{
  width:100%;height:100%;
  display:flex;flex-direction:column;
  justify-content:flex-end;padding:5px;
  position:absolute;inset:0;
}
.off-wp-name{font-size:9px;letter-spacing:0.04em;font-weight:500;line-height:1.2;}
.off-wp-paper{background:linear-gradient(135deg,#f5f0e8,#e8e0d0);}
.off-wp-paper .off-wp-name{color:#8a6640;}
.off-wp-dusk{background:linear-gradient(135deg,#1c1714,#2a2018);}
.off-wp-dusk .off-wp-name{color:#c9a97a;}
.off-wp-mist{background:linear-gradient(135deg,#eef2f5,#dce4ea);}
.off-wp-mist .off-wp-name{color:#5a7a96;}
.off-wp-rose{background:linear-gradient(135deg,#f7f0f2,#ede0e4);}
.off-wp-rose .off-wp-name{color:#9a6070;}
.off-wp-custom{
  background:var(--tag-bg);
  border:1.5px dashed var(--tag-border) !important;
  display:flex;align-items:center;justify-content:center;
}
.off-wp-plus{display:flex;flex-direction:column;align-items:center;gap:3px;}
.off-wp-plus svg{width:18px;height:18px;stroke:var(--warm-dim);fill:none;stroke-width:1.5;stroke-linecap:round;}
.off-wp-plus span{font-size:9px;color:var(--text-faint);letter-spacing:0.04em;}
.off-chat-scroll.has-wallpaper{
  background-size:cover;
  background-position:center;
  background-attachment:local;
}
.off-chat-scroll.has-wallpaper::before{
  content:'';
  position:fixed;
  inset:0;
  background:inherit;
  filter:brightness(0.92);
  z-index:-1;
}

/* 相机按钮 */
.off-cam-wrap{position:relative;flex-shrink:0;}
.off-camera-btn{
  width:28px;height:28px;border-radius:50%;
  border:1px solid var(--border-soft);
  background:rgba(255,255,255,0.35);
  cursor:pointer;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  transition:background 0.18s;
  padding:0;
}
.off-camera-btn:hover{background:rgba(255,255,255,0.6);}
.off-camera-btn:disabled{opacity:0.4;cursor:default;}
.off-camera-btn svg{width:13px;height:13px;stroke:var(--warm-dim);fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;}
.off-camera-menu{
  position:absolute;
  bottom:calc(100% + 8px);
  left:0;
  background:var(--sheet-bg);
  border:1px solid var(--border);
  border-radius:12px;
  padding:6px;
  display:flex;flex-direction:column;gap:2px;
  min-width:180px;
  box-shadow:0 4px 20px rgba(0,0,0,0.12);
  opacity:0;pointer-events:none;
  transform:translateY(6px);
  transition:opacity 0.18s,transform 0.18s;
  z-index:50;
}
.off-camera-menu.show{opacity:1;pointer-events:all;transform:translateY(0);}
.off-camera-menu-item{
  padding:8px 12px;border-radius:7px;
  font-size:12px;color:var(--text-dim);
  cursor:pointer;letter-spacing:0.02em;
  transition:background 0.15s;
  white-space:nowrap;
  font-family:inherit;text-align:left;
  border:none;background:none;
}
.off-camera-menu-item:hover{background:rgba(255,255,255,0.6);color:var(--warm);}

/* 对话流里的生图卡片 */
.off-photo-card{
  align-self:flex-start;
  max-width:75%;
  border-radius:12px;
  overflow:hidden;
  border:1px solid var(--border);
  box-shadow:0 2px 12px rgba(0,0,0,0.1);
}
.off-photo-card img{width:100%;display:block;}
.off-photo-caption{
  padding:7px 10px;
  font-size:10.5px;color:var(--text-faint);
  letter-spacing:0.03em;
  background:var(--tag-bg);
  font-style:italic;
}

/* 切换开关 */
.off-toggle{
  width:36px;height:20px;border-radius:20px;
  background:var(--border);position:relative;
  cursor:pointer;transition:background 0.22s;flex-shrink:0;
}
.off-toggle.on{background:var(--warm);}
.off-toggle::after{
  content:'';position:absolute;
  width:16px;height:16px;border-radius:50%;
  background:white;top:2px;left:2px;
  transition:transform 0.22s;
  box-shadow:0 1px 3px rgba(0,0,0,0.2);
}
.off-toggle.on::after{transform:translateX(16px);}

/* 分段控件 */
.off-seg-ctrl{display:flex;flex-wrap:wrap;gap:5px;width:100%;}
.off-seg-btn{
  padding:5px 12px;border-radius:6px;
  border:1px solid var(--border);
  background:rgba(255,255,255,0.35);
  color:var(--text-dim);font-size:11.5px;
  cursor:pointer;font-family:inherit;
  letter-spacing:0.02em;line-height:1.4;
  transition:all 0.18s;white-space:nowrap;
}
.off-seg-btn.active{
  border-color:var(--warm);
  background:rgba(255,255,255,0.7);
  color:var(--warm);font-weight:500;
}
.off-seg-btn:hover:not(.active){background:rgba(255,255,255,0.55);}

/* 设置里的文字输入框 */
.off-settings-input{
  width:100%;padding:8px 12px;
  border-radius:8px;
  border:1px solid var(--border-soft);
  background:rgba(255,255,255,0.5);
  color:var(--text);font-size:12.5px;
  font-family:inherit;letter-spacing:0.02em;
  outline:none;transition:border-color 0.18s;
}
.off-settings-input::placeholder{color:var(--text-faint);}
.off-settings-input:focus{border-color:var(--warm-dim);background:rgba(255,255,255,0.8);}
.off-custom-len{padding:0 2px 4px;}

/* 淡入动画 */
@keyframes offFadeUp{
  from{opacity:0;transform:translateY(5px);}
  to{opacity:1;transform:translateY(0);}
}
.off-char-block,.off-user-action,.off-suggest-block{animation:offFadeUp 0.25s ease forwards;}

/* ══ 入口页（Demo 没画，沿用同一套配色与质感） ══ */
.off-entry-sec{margin-bottom:24px;}
.off-entry-title{
  margin:0 0 10px 2px;
  font-size:11px;letter-spacing:1.4px;
  color:var(--text-faint);text-transform:uppercase;
}
.off-entry-form{display:flex;flex-direction:column;gap:10px;}
.off-entry-form .set-field{padding:8px 2px;border-bottom:1px solid var(--border-soft);}
.off-entry-form .set-label{color:var(--text-dim);}
.off-entry-form .set-input{
  background:rgba(255,255,255,0.5);
  border:1px solid var(--border-soft);
  border-radius:9px;color:var(--text);
}
.off-entry-form .set-input:focus{border-color:var(--warm-dim);}
.off-field-col{display:flex;flex-direction:column;gap:7px;padding:2px;}
.off-field-label{font-size:12px;color:var(--text-dim);letter-spacing:0.3px;}
.off-seg{display:flex;flex-wrap:wrap;gap:5px;}
.off-entry-btn{padding-top:4px;}
.off-entry-btn .btn{width:100%;}
.off-entry-empty{margin:4px 2px 0;font-size:12px;color:var(--text-faint);}
.off-entry-row{
  width:100%;display:flex;align-items:center;gap:10px;
  padding:12px 4px;background:none;border:0;
  border-bottom:1px solid var(--border);
  font-family:inherit;text-align:left;cursor:pointer;color:inherit;
}
.off-entry-row:last-child{border-bottom:0;}
.off-entry-row:active{background:var(--warm-faint);}
.off-entry-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;}
.off-entry-name{font-size:calc(14px * var(--fs-scale, 1));color:var(--text);}
.off-entry-hint{font-size:11px;color:var(--text-faint);}
.off-entry-preview{font-size:11.5px;color:var(--text-dim);line-height:1.5;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;}
.off-entry-tag{
  flex:none;font-size:9.5px;letter-spacing:0.5px;
  color:var(--warm);
  border:1px solid var(--tag-border);border-radius:7px;
  padding:2px 6px;background:var(--tag-bg);
}
.off-entry-tag.is-ended{color:var(--text-faint);background:none;}

/* 结束态横幅 + 总结摘录 */
.off-ended-bar{
  margin-bottom:8px;
  font-size:11px;color:var(--text-faint);
  letter-spacing:0.03em;text-align:center;
}
.off-summary-retry{
  display:block;margin:0 auto 8px;
  border:1px solid var(--line);border-radius:8px;
  background:none;font-family:inherit;
  font-size:11.5px;color:var(--text-dim);
  padding:5px 14px;cursor:pointer;
}
.off-summary-retry:active{background:var(--bg-3);}
.off-summary-note{
  margin-top:6px;padding:9px 12px;
  font-size:11.5px;line-height:1.8;font-style:italic;
  color:var(--scene-text);
  border-left:1.5px solid var(--warm-dim);
  background:var(--warm-faint);
  border-radius:0 8px 8px 0;
}

/* ---- 线下入口页：AI 开场按钮 + 手动折叠 ---- */
.off-entry-body{padding:6px 0 20px;overflow-y:auto;flex:1;min-height:0;}
.off-entry-go{
  width:100%;padding:14px 16px;
  border:1px solid var(--tag-border);
  background:linear-gradient(135deg,var(--warm-mid),var(--warm));
  border-radius:12px;cursor:pointer;
  display:flex;flex-direction:column;gap:3px;
  font-family:inherit;text-align:left;
  transition:opacity 0.18s,transform 0.15s;
  box-shadow:0 2px 10px rgba(0,0,0,0.08);
}
.off-entry-go:hover{opacity:0.9;transform:translateY(-1px);}
.off-entry-go:active{transform:scale(0.985);}
.off-entry-go.is-pending{opacity:0.55;pointer-events:none;}
.off-entry-go-name{font-size:14px;font-weight:600;color:#fff;letter-spacing:0.04em;}
.off-entry-go-sub{font-size:10.5px;color:rgba(255,255,255,0.75);letter-spacing:0.02em;}
.off-entry-manual-hint{
  margin-top:10px;padding:0 2px;
  border:0;background:none;font-family:inherit;
  font-size:11px;color:var(--text-faint);cursor:pointer;
  letter-spacing:0.03em;
}
.off-entry-manual{margin-top:10px;}

/* ---- 门弹窗（点门直接选，不经过入口页）+ 入口页 hero ---- */
/* off-vars 只当变量载体：display:contents 不参与布局，
   位置固定的弹窗照常相对页面定位 */
.off-vars{display:contents;}
.off-door-overlay{z-index:120;}
.off-door-title{display:flex;flex-direction:column;gap:3px;margin-bottom:14px;}
.off-door-title-main{font-size:15px;font-weight:600;color:var(--text);letter-spacing:0.03em;}
.off-door-title-sub{font-size:10.5px;color:var(--text-faint);letter-spacing:0.03em;}
.off-door-sec{
  font-size:9.5px;color:var(--text-faint);
  letter-spacing:0.08em;text-transform:uppercase;
  margin:4px 2px 8px;
}
.off-door-row{
  width:100%;display:flex;align-items:center;gap:10px;
  padding:10px 13px;margin-bottom:6px;
  border:1px solid var(--border-soft);border-radius:9px;
  background:rgba(255,255,255,0.5);
  font-family:inherit;text-align:left;cursor:pointer;color:inherit;
  transition:background 0.18s,border-color 0.18s;
}
.off-door-row:hover{background:rgba(255,255,255,0.8);border-color:var(--tag-border);}
.off-door-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;}
.off-door-row-name{font-size:12.5px;color:var(--text);letter-spacing:0.02em;font-weight:500;}
.off-door-row-sub{
  font-size:10px;color:var(--text-faint);letter-spacing:0.02em;
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;
}
.off-door-row-tag{
  flex:none;font-size:9.5px;letter-spacing:0.5px;
  color:var(--warm);
  border:1px solid var(--tag-border);border-radius:7px;
  padding:2px 6px;background:var(--tag-bg);
}
.off-door-row-tag.is-ended{color:var(--text-faint);background:none;}
.off-entry-go.in-sheet{margin:4px 0 2px;}
.off-door-manual-hint{
  margin-top:10px;padding:0 2px;
  border:0;background:none;font-family:inherit;
  font-size:11px;color:var(--text-faint);cursor:pointer;
  letter-spacing:0.03em;text-align:left;
}
.off-door-manual{margin-top:10px;}

/* 入口页 hero */
.off-entry-hero{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:26px 0 22px;
}
.off-entry-hero-door{
  width:64px;height:64px;border-radius:18px;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,var(--warm-mid),var(--warm));
  box-shadow:0 4px 18px rgba(138,102,64,0.28);
}
.off-entry-hero-door svg{
  width:30px;height:30px;
  stroke:#fff;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
}
.off-entry-hero-name{margin:6px 0 0;font-size:16px;font-weight:600;color:var(--text);letter-spacing:0.04em;}
.off-entry-hero-sub{margin:0;font-size:11px;color:var(--text-faint);letter-spacing:0.04em;}

/* ---- 线下模式 · 第二批反馈 ---- */
/* 门弹窗居中（不再是底部抽屉） */
.off-door-overlay{
  align-items:center;
  padding:28px 20px;
}
.off-door-overlay .off-sheet{
  border-radius:18px;
  max-width:340px;margin:0 auto;
}
/* 系统设置抽屉全屏（否则顶部露一条黑遮罩） */
.off-sheet-full{
  height:100%;
  max-height:none;
  border-radius:0;
  width:100%;
  /* 整块自己滚动：内容超长在页面内滑，不露出底下的白 */
  overflow-y:auto;
  scrollbar-width:none;
  /* 顶部让开浮着的状态栏 */
  padding-top:calc(env(safe-area-inset-top) + 44px);
}
.off-sheet-full::-webkit-scrollbar{display:none;}
.off-sheet-full .off-sheet-handle{margin-bottom:12px;}
/* 线下 ApiSheet 的模型行 */
.off-model-line{display:flex;align-items:center;gap:8px;}
.off-model-line .off-settings-input{flex:1;min-width:0;}
.off-model-line .set-mini-ic{flex-shrink:0;}

/* 全屏设置铺满整个设备宽（设备比 420 宽时左右不再露遮罩） */
.off-overlay:has(.off-sheet-full){max-width:none;}

/* ============================================================
   角色设置首页（chat-settings，demo v1）+ 角色聊天外观编辑页
   （char-appearance）。扁平行 + 分隔线，颜色走主题变量。
   ============================================================ */

/* ---- 角色设置首页 ---- */
.cs-head{
  display:flex;align-items:center;gap:12px;
  padding:14px 2px 18px;
  border-bottom:1px solid var(--line);
  margin-bottom:6px;
}
.cs-ava{
  width:46px;height:46px;border-radius:50%;
  background:linear-gradient(145deg,var(--g-glass-hi,rgba(255,255,255,.5)),var(--g-accent));
  color:#fff;font-size:19px;font-weight:600;
  display:flex;align-items:center;justify-content:center;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.4);
  flex:none;
}
.cs-head-main{min-width:0;}
.cs-head-name{margin:0;font-size:16px;font-weight:600;color:var(--text);}
.cs-head-sub{margin:2px 0 0;font-size:11px;color:var(--text-faint);}
.cs-section{margin-top:20px;}
.cs-sec-label{
  margin:0 0 4px 4px;
  font-size:11px;font-weight:600;letter-spacing:2.4px;
  color:var(--text-faint);
}
/* demo 行比默认 set-row 高一档，小注一行截断 */
.cs-row{min-height:56px;}
.cs-row .set-row-hint{
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  margin-top:3px;
}
.cs-inline-switch{margin-right:2px;}
.cs-danger .set-row-label{color:#C07A6B;}

/* ---- 外观编辑页 ---- */
.cap-preview{
  margin:4px 0 0;
  height:160px;border-radius:16px;overflow:hidden;position:relative;
  background:#eef0ec;
  box-shadow:0 4px 18px rgba(40,55,50,.09);
}
.cap-pv-bg{position:absolute;inset:0;background-size:cover;background-position:center;transition:background .24s,filter .2s,opacity .2s;}
.cap-pv-inner{position:relative;z-index:1;padding:14px;display:flex;flex-direction:column;gap:9px;}
.cap-pv-row{display:flex;gap:8px;align-items:flex-end;}
.cap-pv-row.is-out{justify-content:flex-end;}
.cap-pv-ava{width:26px;height:26px;border-radius:50%;flex:0 0 26px;background:linear-gradient(145deg,#b8cdc8,#6f8983);}
.cap-pv-bubble{
  max-width:68%;padding:7px 10px;font-size:12px;line-height:1.4;
  border-radius:3px 13px 13px 13px;
  background:#fff;color:#293330;position:relative;transition:all .22s;
}
.cap-pv-row.is-out .cap-pv-bubble{color:#fff;}
.cap-presets{display:flex;gap:7px;padding:14px 0 0;}
.cap-preset{
  flex:1;padding:8px 0;border-radius:10px;font-size:12px;font-weight:600;
  border:1.2px solid var(--line);color:var(--text-faint);background:none;
  font-family:inherit;transition:all .18s;cursor:pointer;
}
.cap-preset.active{background:var(--g-accent);color:#fff;border-color:transparent;}
.cap-editor{padding:8px 0 50px;display:flex;flex-direction:column;gap:22px;}
.cap-group-title{
  margin:0 0 10px;
  font-size:11px;font-weight:600;letter-spacing:2px;
  color:var(--text-faint);
}
.cap-group-title.cap-sub{margin:12px 0 8px;font-size:10px;}
.cap-ctrl{
  display:grid;grid-template-columns:76px 1fr auto;align-items:center;gap:10px;
  min-height:44px;border-bottom:1px solid var(--line);
}
.cap-ctrl:last-child{border-bottom:0;}
.cap-ctrl label{font-size:13px;color:var(--text);}
.cap-ctrl output{font-size:11px;color:var(--text-faint);min-width:26px;text-align:right;}
.cap-ctrl input[type=range]{width:100%;accent-color:var(--g-accent);}
.cap-chips{display:flex;gap:7px;flex-wrap:wrap;}
.cap-chip{
  padding:6px 12px;border-radius:99px;font-size:11.5px;
  border:1.2px solid var(--line);color:var(--text-faint);background:none;
  font-family:inherit;transition:all .16s;cursor:pointer;
}
.cap-chip.active{background:var(--g-accent-soft,#dce8e4);color:var(--text);border-color:var(--g-accent);}
.cap-wp-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;}
.cap-wp{
  width:44px;height:44px;border-radius:10px;cursor:pointer;
  box-shadow:0 0 0 1px var(--line);border:0;padding:0;
  transition:box-shadow .16s;
}
.cap-wp.active{box-shadow:0 0 0 2.5px var(--g-accent);}
.cap-wp-upload{
  width:44px;height:44px;border-radius:10px;
  border:1.5px dashed var(--line);background:none;
  display:grid;place-items:center;color:var(--text-faint);
  cursor:pointer;font-size:18px;font-family:inherit;
}
.cap-wp-upload.active{box-shadow:0 0 0 2.5px var(--g-accent);}
.cap-tex-row{display:flex;gap:8px;}
.cap-tex{
  width:50px;height:36px;border-radius:8px;border:1.5px solid var(--line);
  cursor:pointer;display:grid;place-items:center;font-size:10px;
  color:var(--text-faint);background:rgba(255,255,255,.6);
  font-family:inherit;transition:all .16s;padding:0;
}
.cap-tex.active{border-color:var(--g-accent);box-shadow:0 0 0 1px var(--g-accent);}
.cap-tex-grid{background:repeating-linear-gradient(0deg,transparent,transparent 5px,rgba(100,120,110,.12) 5px,rgba(100,120,110,.12) 6px),repeating-linear-gradient(90deg,transparent,transparent 5px,rgba(100,120,110,.12) 5px,rgba(100,120,110,.12) 6px),#fff;}
.cap-tex-dot{background:radial-gradient(circle,rgba(100,120,110,.2) 1px,transparent 1.5px) 0 0/8px 8px,#fff;}
.cap-tex-paper{background:repeating-linear-gradient(90deg,rgba(100,120,110,.05) 0,rgba(100,120,110,.05) 1px,transparent 1px,transparent 4px),linear-gradient(180deg,rgba(200,210,200,.08) 0,transparent 100%),#faf8f4;}
.cap-swatches{display:flex;gap:8px;flex-wrap:wrap;}
.cap-swatch{
  width:30px;height:30px;border-radius:50%;padding:0;
  border:2px solid rgba(255,255,255,.7);
  box-shadow:0 0 0 1px var(--line);cursor:pointer;
  transition:box-shadow .16s;
}
.cap-swatch.active{box-shadow:0 0 0 2.5px var(--g-accent);}
.cap-css-area{
  width:100%;height:90px;padding:10px 12px;
  border-radius:10px;border:1.2px solid var(--line);
  background:var(--surface);resize:none;outline:none;
  font-size:11px;line-height:1.5;font-family:"SF Mono","Menlo","Consolas",monospace;
  color:var(--text);transition:border-color .16s;
}
.cap-css-area:focus{border-color:var(--g-accent);}
.cap-hint{font-size:10.5px;color:var(--text-faint);margin:6px 0 0;}
.cap-reset{
  width:100%;padding:16px 0;border:0;border-top:1px solid var(--line);
  background:none;color:var(--text-faint);font-size:13px;
  font-family:inherit;cursor:pointer;
}

/* 外观编辑页：皮肤模式提示条 */
.cap-mode-hint{
  margin:8px 0 0;
  font-size:11px;line-height:1.6;color:var(--text-faint);
  padding:0 2px;
}
.cap-mode-hint:empty{display:none;}

/* ---- 聊天页：时间分隔线 + 气泡头像光点 + 捡手机昵称标 ---- */
/* 居中的时间分隔线（隔 5 分钟以上插一条；企微/捡手机的时间只在分隔线） */
.msg-time-sep{
  text-align:center;
  font-size:11px;color:var(--text-faint);
  letter-spacing:.04em;
  margin:2px 0 4px;
}
/* char 气泡旁的头像包一层：未读心声光点的家（位置听用户的，不在顶栏） */
.msg-ava-wrap{
  position:relative;flex:0 0 32px;
  margin-right:8px;cursor:pointer;
}
.msg-ava-wrap .msg-avatar{margin-right:0;display:block;}
.msg-user .msg-ava-wrap{margin-right:0;margin-left:8px;}
.msg-ava-wrap .hb-dot{top:-2px;right:-2px;}
.msg-ava-wrap.has-unread .hb-dot{display:block;}
/* 捡手机：头像旁的小昵称标；企微/捡手机不显示气泡下的时间（分隔线够用） */
.msg-nick{display:none;}
.msg-wrap.mode-phone .msg-nick{
  display:block;
  font-size:10px;color:#8b939c;
  margin:0 0 2px 2px;letter-spacing:.03em;
}
.msg-wrap.mode-wecom .msg-time,.msg-wrap.mode-phone .msg-time{display:none;}

/* 未读心声光点：小而柔的自然呼吸（不要大圈扩散那种） */
.msg-ava-wrap .hb-dot{
  width:7px;height:7px;
  box-shadow:0 0 0 1.5px rgba(255,255,255,.8);
}
.msg-ava-wrap.has-unread .hb-dot{animation:hb-soft 2.8s ease-in-out infinite;}
.msg-ava-wrap.has-unread .hb-dot::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  background:var(--coral);
  animation:hb-soft-halo 2.8s ease-in-out infinite;
}
@keyframes hb-soft{
  0%,100%{opacity:.55;}
  50%{opacity:1;}
}
@keyframes hb-soft-halo{
  0%,100%{transform:scale(1);opacity:0;}
  50%{transform:scale(1.8);opacity:.28;}
}
@media (prefers-reduced-motion: reduce){
  .msg-ava-wrap.has-unread .hb-dot,.msg-ava-wrap.has-unread .hb-dot::after{animation:none;}
}

/* ============================================================
   留痕 App（page-memory.js）—— Demo v4 逐值移植，lh- 前缀。
   暖米底 + 冷蓝绿强调；圆角框基本不用，走行 + 分隔线。
   ============================================================ */
.lh-app-sub{margin:2px 4px 10px;font-size:10px;color:var(--text-faint);letter-spacing:.08em;}
.lh-sec{margin-bottom:14px;}
.lh-empty{margin:10px 4px;font-size:12px;color:var(--text-faint);line-height:1.7;}

.lh-island-row{
  padding:13px 4px 12px;display:flex;align-items:baseline;justify-content:space-between;
  border-bottom:1px solid var(--line);
}
.lh-island-name{font-size:13px;font-weight:500;color:#4a8a92;letter-spacing:.06em;}
.lh-island-meta{font-size:10px;color:var(--text-faint);letter-spacing:.05em;}

.lh-section-label{
  margin:17px 0 8px 2px;
  font-size:9.5px;color:var(--text-faint);
  letter-spacing:.1em;text-transform:uppercase;
}

.lh-char-row{
  padding:13px 4px 14px;border-bottom:1px solid var(--line);
  cursor:pointer;position:relative;
  display:flex;flex-direction:column;gap:9px;
}
.lh-char-row:active{background:var(--bg-2);}
.lh-char-row-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;}
.lh-char-row-left{display:flex;flex-direction:column;gap:4px;}
.lh-char-name{font-size:15px;font-weight:500;color:var(--text);letter-spacing:.04em;}
.lh-char-tags{display:flex;}
.lh-char-tag{font-size:9.5px;color:#a08870;letter-spacing:.04em;}
.lh-char-tag + .lh-char-tag::before{content:'·';margin:0 5px;color:#c8b49a;}
.lh-char-row-right{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex-shrink:0;}
.lh-mem-state{font-size:9px;color:var(--text-faint);letter-spacing:.05em;}
.lh-mem-state.on{color:#4a8a92;}
.lh-char-toggle-row{display:flex;align-items:center;gap:5px;}
.lh-char-toggle-label{font-size:9.5px;color:var(--text-faint);letter-spacing:.03em;}
.lh-char-excerpt{
  font-size:12px;color:var(--text-dim);
  line-height:1.8;letter-spacing:.025em;font-style:italic;
  padding-left:11px;border-left:1.5px solid #a8cdd0;
}
.lh-char-row-foot{display:flex;align-items:center;justify-content:space-between;}
.lh-char-row-time{font-size:10px;color:var(--text-faint);letter-spacing:.03em;}
.lh-char-enter{font-size:10px;color:#72aab0;letter-spacing:.04em;}
.lh-pending-pip{
  width:6px;height:6px;border-radius:50%;
  background:#4a8a92;
  position:absolute;top:15px;left:-6px;
  box-shadow:0 0 0 2px var(--bg);
}

.lh-mini-toggle{
  width:28px;height:16px;border-radius:16px;
  background:rgba(120,100,75,.18);position:relative;
  cursor:pointer;transition:background .2s;flex-shrink:0;
}
.lh-mini-toggle.on{background:#72aab0;}
.lh-mini-toggle::after{
  content:'';position:absolute;
  width:12px;height:12px;border-radius:50%;
  background:white;top:2px;left:2px;
  transition:transform .2s;
  box-shadow:0 1px 3px rgba(0,0,0,.18);
}
.lh-mini-toggle.on::after{transform:translateX(12px);}

.lh-npc-toggle{
  width:100%;padding:11px 4px;
  background:none;border:none;border-top:1px solid var(--line);
  display:flex;align-items:center;gap:8px;
  cursor:pointer;font-family:inherit;color:var(--text-dim);
}
.lh-npc-toggle-label{font-size:11px;letter-spacing:.04em;flex:1;text-align:left;}
.lh-npc-toggle-count{font-size:10px;color:var(--text-faint);letter-spacing:.03em;}
.lh-npc-toggle svg{width:11px;height:11px;stroke:#c8b49a;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .2s;flex-shrink:0;}
.lh-npc-toggle.open svg{transform:rotate(180deg);}
.lh-npc-list{overflow:hidden;max-height:0;transition:max-height .28s cubic-bezier(.32,.72,0,1);}
.lh-npc-list.open{max-height:420px;}
.lh-npc-row{
  padding:10px 4px 10px 12px;
  border-bottom:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  cursor:pointer;background:rgba(238,244,245,.45);
}
.lh-npc-row-left{display:flex;flex-direction:column;gap:2px;}
.lh-npc-name{font-size:12.5px;color:var(--text);letter-spacing:.03em;}
.lh-npc-rel{font-size:10px;color:var(--text-faint);letter-spacing:.03em;}
.lh-npc-row-right{display:flex;align-items:center;gap:7px;flex-shrink:0;}
.lh-scroll-pad{height:36px;}

/* ---- 内页 ---- */
.lh-understanding-zone{
  background:#eef4f5;
  border-bottom:1px solid rgba(74,138,146,.14);
  padding:20px 14px;position:relative;
  margin:0 -22px;
}
.lh-understanding-zone::before{
  content:'';position:absolute;inset:0;
  background-image:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(74,138,146,.045) 23px,rgba(74,138,146,.045) 24px);
  pointer-events:none;
}
.lh-uz-title{
  font-size:9.5px;color:#4a8a92;
  letter-spacing:.1em;text-transform:uppercase;
  margin:0 0 15px;position:relative;
}
.lh-uz-items{display:flex;flex-direction:column;gap:14px;position:relative;}
.lh-uz-item{display:flex;flex-direction:column;gap:5px;}
.lh-uz-text{font-size:13px;color:var(--text-dim);line-height:1.85;letter-spacing:.025em;font-style:italic;}
.lh-uz-meta{display:flex;align-items:center;gap:8px;}
.lh-uz-badge{font-size:9px;letter-spacing:.04em;}
.lh-uz-badge::before{content:'·';margin-right:3px;opacity:.45;}
.lh-uz-badge.infer{color:#7868a0;}
.lh-uz-badge.recent{color:#4a9068;}
.lh-uz-badge.confirm{color:#4a8a92;}
.lh-uz-edit{
  font-size:9px;color:var(--text-faint);cursor:pointer;
  letter-spacing:.03em;border-bottom:1px dotted #a8cdd0;
}

.lh-entries-grid{
  display:grid;grid-template-columns:1fr 1fr;
  border-top:1px solid var(--line);
  margin:0 -22px;
}
.lh-entry-cell{
  padding:15px 14px 14px;
  border-bottom:1px solid var(--line);
  border-right:1px solid var(--line);
  cursor:pointer;transition:background .15s;
  display:flex;flex-direction:column;gap:4px;
}
.lh-entry-cell:nth-child(even){border-right:none;}
.lh-entry-cell:nth-last-child(-n+2){border-bottom:none;}
.lh-entry-cell:active{background:var(--bg-2);}
.lh-entry-num{font-size:24px;font-weight:600;color:#72aab0;line-height:1;letter-spacing:-.01em;}
.lh-entry-name{font-size:11.5px;color:var(--text);letter-spacing:.03em;font-weight:500;line-height:1.3;}
.lh-entry-unit{font-size:10px;color:var(--text-faint);letter-spacing:.03em;}

.lh-triage-section{
  display:flex;align-items:stretch;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,rgba(238,244,245,.7) 0%,var(--bg) 100%);
  margin:0 -22px;
}
.lh-triage-item{
  flex:1;display:flex;flex-direction:column;gap:3px;align-items:center;
  cursor:pointer;padding:14px 8px;position:relative;
}
.lh-triage-item + .lh-triage-item::before{
  content:'';position:absolute;left:0;top:10px;bottom:10px;
  width:1px;background:var(--line);
}
.lh-triage-num{font-size:22px;font-weight:600;color:var(--text);letter-spacing:-.01em;line-height:1;}
.lh-triage-num.alert{color:#4a8a92;}
.lh-triage-label{font-size:10px;color:var(--text-faint);letter-spacing:.04em;margin-top:1px;}

.lh-source-bar{
  padding:10px 0;
  border-bottom:1px solid var(--line);
  display:flex;gap:16px;overflow-x:auto;scrollbar-width:none;
}
.lh-source-bar::-webkit-scrollbar{display:none;}
.lh-source-btn{
  flex-shrink:0;background:none;border:none;
  font-size:11px;color:var(--text-faint);
  cursor:pointer;letter-spacing:.03em;font-family:inherit;
  padding:2px 0;white-space:nowrap;
  border-bottom:1.5px solid transparent;
  transition:color .15s,border-color .15s;
}
.lh-source-btn.active{color:#4a8a92;border-bottom-color:#4a8a92;}

.lh-mem-list{padding:0;}
.lh-mem-row{
  padding:12px 2px;
  border-bottom:1px solid var(--line);
  display:flex;flex-direction:column;gap:5px;
  cursor:pointer;
}
.lh-mem-row:last-child{border-bottom:none;}
.lh-mem-row-top{display:flex;align-items:center;justify-content:space-between;gap:8px;}
.lh-mem-kind{font-size:9px;letter-spacing:.05em;font-weight:500;}
.lh-mk-like{color:#4a9068;}
.lh-mk-dislike,.lh-mk-red{color:#a85840;}
.lh-mk-fact,.lh-mk-blue{color:#3a6898;}
.lh-mk-shared,.lh-mk-teal{color:#4a8a92;}
.lh-mk-pending,.lh-mk-gold{color:#9a7828;}
.lh-mk-mauve{color:#7868a0;}
.lh-mk-boundary{color:#a85840;}
.lh-mk-habit,.lh-mk-warm{color:#a08870;}
.lh-mk-dim{color:var(--text-faint);}
.lh-mem-time{font-size:9.5px;color:var(--text-faint);letter-spacing:.03em;}
.lh-mem-text{font-size:12.5px;color:var(--text-dim);line-height:1.7;letter-spacing:.02em;}
.lh-mem-src{font-size:10px;color:var(--text-faint);letter-spacing:.03em;}

/* ---- 详情页 ---- */
.lh-detail-head{display:flex;align-items:center;gap:8px;margin:4px 0 12px;}
.lh-anchor-tag{
  font-size:9px;color:#4a8a92;letter-spacing:.05em;
  border:1px solid rgba(74,138,146,.35);border-radius:7px;
  padding:1px 6px;background:rgba(74,138,146,.08);
}
.lh-detail-content{cursor:text;}
.lh-detail-text{font-size:14px;color:var(--text);line-height:1.9;letter-spacing:.02em;}
.lh-detail-textarea{
  width:100%;min-height:110px;padding:10px 12px;
  border-radius:10px;border:1px solid var(--line);
  background:var(--surface);color:var(--text);
  font-size:13.5px;line-height:1.8;font-family:inherit;
  resize:vertical;outline:none;
}
.lh-detail-textarea:focus{border-color:#72aab0;}
.lh-detail-editbtns{display:flex;gap:8px;margin-top:8px;}
.lh-btn{
  padding:7px 14px;border-radius:9px;
  border:1px solid var(--line);background:none;
  font-size:12px;color:var(--text-dim);cursor:pointer;
  font-family:inherit;letter-spacing:.03em;
}
.lh-btn-primary{background:#4a8a92;border-color:#4a8a92;color:#fff;}
.lh-btn-danger{color:#a85840;border-color:rgba(168,88,64,.35);}
.lh-btn-wide{width:100%;margin:14px 0 4px;padding:10px;}
.lh-detail-meta{
  margin:16px 0 6px;padding:4px 0;
  border-top:1px solid var(--line);
}
.lh-meta-row{
  display:flex;justify-content:space-between;gap:14px;
  padding:8px 2px;border-bottom:1px solid var(--line);
}
.lh-meta-row:last-child{border-bottom:none;}
.lh-meta-k{font-size:11px;color:var(--text-faint);letter-spacing:.04em;flex:none;}
.lh-meta-v{font-size:12px;color:var(--text-dim);text-align:right;line-height:1.5;}
/* 版本链 / 搜索（第三梯队 5）。链接不加框不加底色，下划线示意可点 */
.lh-meta-v.is-link{text-decoration:underline;text-decoration-color:rgba(161,129,87,.45);text-underline-offset:3px;}
.lh-search-bar{margin:12px 0 4px;}
.lh-search-input{
  width:100%;padding:9px 12px;
  border:0;border-bottom:1px solid var(--line);outline:none;
  background:transparent;color:var(--text);
  font-family:inherit;font-size:12px;letter-spacing:.02em;
}
.lh-search-input:focus{border-bottom-color:rgba(161,129,87,.5);}
/* 从留痕跳进聊天的气泡定位高亮：不遮内容，只描一圈焦糖边再淡出 */
.msg-flash{animation:msg-flash 2.4s ease;}
@keyframes msg-flash{
  0%,55%{box-shadow:0 0 0 2px rgba(176,138,94,.75);}
  100%{box-shadow:none;}
}
.lh-detail-ops{
  display:flex;flex-wrap:wrap;gap:8px;
  margin-top:16px;padding-top:14px;
  border-top:1px solid var(--line);
}

/* ============================================================
   浮岛 v2（page-island.js 追加页）—— 总览 / 认知地图 / 角色档案。
   风格对齐「角色档案与人设」：暖纸底、衬线字、细线分隔、
   圆角只在卡上（17/6 不对称圆角），字号全部收敛在 22px 以下。
   ============================================================ */
.page[data-page^="island"] .app-body{font-family:var(--ff-serif);}

.iol-head{margin:6px 2px 4px;}
.iol-title{
  margin:0;display:inline-block;
  font-family:var(--ff-serif);
  font-size:20px;font-weight:400;letter-spacing:.08em;color:var(--text);
}
.iol-tag{
  display:inline-block;margin-left:7px;vertical-align:3px;
  padding:2px 8px;border-radius:99px;
  background:rgba(161,129,87,.16);color:#967346;font-size:10px;
}
.iol-sub{margin:7px 0 0;font-size:11px;color:var(--text-faint);letter-spacing:.03em;}

.iol-sec-label{
  display:flex;align-items:baseline;justify-content:space-between;
  margin:20px 2px 9px;
}
.iol-sec-label b{font-size:12px;font-weight:500;letter-spacing:.08em;color:var(--text);}
.iol-sec-label span{font-size:9.5px;color:var(--text-faint);letter-spacing:.04em;}

/* 核心成员：孤岛=双人+虚线；群岛=横排 */
.iol-core{
  display:flex;align-items:center;justify-content:center;gap:22px;
  padding:20px 12px 18px;
  background:rgba(255,255,255,.55);
  border-radius:17px 6px 17px 6px;
  border-top:1px solid rgba(255,255,255,.7);
  border-bottom:1px solid var(--line);
  box-shadow:0 10px 24px rgba(82,103,87,.08);
}
.iol-core.is-archi{justify-content:flex-start;overflow-x:auto;scrollbar-width:none;padding:16px 12px;}
.iol-core.is-archi::-webkit-scrollbar{display:none;}
.iol-person{text-align:center;flex:none;}
.iol-ava{
  width:46px;height:46px;margin:0 auto 7px;
  display:grid;place-items:center;border-radius:50%;
  border:1.5px solid #c4a878;background:#e3f2e7;
  color:#6a806d;font-size:15px;
}
.iol-person.is-me .iol-ava{border-color:#b9c6aa;background:#eef1dd;}
.iol-person b{font-size:12.5px;font-weight:400;color:var(--text);}
.iol-person small{display:block;margin-top:3px;font-size:9.5px;color:var(--text-faint);}
.iol-line{
  width:34px;height:1px;flex:none;
  background:repeating-linear-gradient(90deg,#dbb8ae 0 5px,transparent 5px 9px);
}

.iol-strip{display:flex;gap:9px;overflow-x:auto;padding:2px 2px 10px;scrollbar-width:none;}
.iol-strip::-webkit-scrollbar{display:none;}
.iol-empty{margin:6px 2px;font-size:11px;color:var(--text-faint);}
.iol-member{
  min-width:98px;flex:none;padding:12px 11px;text-align:left;
  background:rgba(255,255,255,.57);
  border:1px solid rgba(255,255,255,.66);
  border-radius:14px 5px 14px 5px;
  font-family:inherit;color:var(--text);
}
.iol-member-ava{
  width:32px;height:32px;margin-bottom:7px;
  display:grid;place-items:center;border-radius:50%;
  border:1px solid rgba(128,151,132,.28);background:#eef1dd;
  font-size:12px;color:#6a806d;
}
.iol-member strong{display:block;font-size:12px;font-weight:400;}
.iol-member small{display:block;margin-top:3px;font-size:9px;color:var(--text-faint);line-height:1.6;}
.iol-member.is-add{
  display:grid;place-items:center;gap:4px;
  border-style:dashed;border-color:rgba(157,136,105,.4);
  background:transparent;color:#9d8869;
}
.iol-add-mark{font-size:20px;font-weight:200;}

.iol-prof-list{display:flex;flex-direction:column;}
.iol-prof-row{
  display:grid;grid-template-columns:1fr auto;align-items:center;gap:10px;
  padding:12px 3px;border:0;border-bottom:1px solid var(--line);
  background:none;text-align:left;font-family:inherit;cursor:pointer;color:inherit;
}
.iol-prof-left{display:flex;flex-direction:column;gap:3px;min-width:0;}
.iol-prof-left b{font-size:12.5px;font-weight:500;color:var(--text);}
.iol-prof-left small{
  font-size:9.5px;color:var(--text-faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.iol-prof-side{font-size:9.5px;color:#b29267;flex:none;}

.iol-rel-box{display:flex;flex-direction:column;gap:9px;}
.iol-rel-row{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 12px;
  background:rgba(255,255,255,.55);
  border-radius:14px 5px 14px 5px;
}
.iol-rel-who{font-size:12px;color:var(--text);letter-spacing:.02em;flex:none;}
.iol-seg{display:flex;gap:4px;flex:none;}
.iol-seg.is-col{flex-direction:column;gap:6px;}
.iol-seg-btn{
  padding:5px 10px;border-radius:12px;
  border:1px solid var(--line);background:rgba(255,255,255,.4);
  font-size:10px;color:var(--text-faint);font-family:inherit;
  cursor:pointer;letter-spacing:.02em;transition:all .15s;
}
.iol-seg-btn.is-on{
  border-color:rgba(159,125,82,.4);
  background:rgba(248,244,228,.74);color:#8b6940;
}

.iol-info{display:flex;flex-direction:column;}
.iol-info-row{
  display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:13px 3px;border-bottom:1px solid var(--line);
  font-size:12px;color:var(--text);
}
.iol-info-row small{color:var(--text-faint);font-size:10.5px;text-align:right;line-height:1.6;}
.iol-info-row small button{
  border:0;background:none;color:#a18157;font-size:11px;
  cursor:pointer;font-family:inherit;padding:0;
}

.iol-foot{display:flex;flex-direction:column;gap:10px;margin-top:24px;}
.iol-primary{
  width:100%;padding:14px;border:0;cursor:pointer;
  border-radius:15px 15px 4px 15px;
  background:#a98458;color:#fff;
  font-family:var(--ff-serif);font-size:13px;letter-spacing:.12em;
  box-shadow:0 8px 18px rgba(147,110,69,.2);
}
.iol-ghost{
  width:100%;padding:11px;border:0;cursor:pointer;
  background:transparent;color:var(--text-faint);
  font-size:11px;font-family:inherit;letter-spacing:.04em;
}

/* 认知地图 */
.iol-obs-sw{display:flex;gap:6px;margin:6px 0 14px;flex-wrap:wrap;}
.iol-obs-btn{
  padding:6px 13px;border-radius:14px;
  border:1px solid var(--line);background:rgba(255,255,255,.4);
  font-size:10.5px;color:var(--text-faint);font-family:inherit;cursor:pointer;
}
.iol-obs-btn.is-on{background:rgba(248,244,228,.78);color:#8b6940;border-color:rgba(159,125,82,.38);}
.iol-cog-title{margin:0;font-size:17px;font-weight:400;letter-spacing:.06em;color:var(--text);}
.iol-cog-sub{margin:7px 0 0;font-size:10.5px;color:var(--text-faint);line-height:1.7;}
.iol-matrix{display:flex;flex-direction:column;}
.iol-matrix-row{
  display:flex;justify-content:space-between;align-items:center;gap:12px;
  padding:11px 3px;border-bottom:1px solid var(--line);
}
.iol-matrix-row span{font-size:12.5px;color:var(--text);}
.iol-matrix-row small{font-size:10px;color:var(--text-faint);text-align:right;}
.iol-judge{margin:4px 0 16px;}
.iol-judge-q{margin:0 0 8px;font-size:12px;color:var(--text);}
.iol-choice{
  width:100%;text-align:left;padding:10px 12px;margin-bottom:6px;
  border:1px solid var(--line);border-radius:12px 4px 12px 4px;
  background:rgba(255,255,255,.34);font-family:inherit;cursor:pointer;
}
.iol-choice.is-on{border-color:rgba(159,125,82,.38);background:rgba(248,244,228,.74);}
.iol-choice b{display:block;font-size:11px;font-weight:500;color:var(--text);}
.iol-choice small{display:block;margin-top:3px;font-size:9px;color:var(--text-faint);line-height:1.5;}
.iol-note{margin:18px 3px 0;font-size:9.5px;color:var(--text-faint);line-height:1.8;}

/* 角色档案（ipro-） */
.ipro-hero{text-align:center;padding:18px 4px 14px;}
.ipro-ava{
  width:58px;height:58px;margin:0 auto 9px;
  display:grid;place-items:center;border-radius:50%;
  background:linear-gradient(145deg,#e4f1e6,#f2ecdc);
  border:1.5px solid rgba(158,127,82,.5);
  font-size:17px;color:#6d7d6d;
}
.ipro-hero h2{
  margin:0;font-size:17px;font-weight:500;letter-spacing:.08em;color:var(--text);
}
.ipro-pill{
  display:inline-block;margin-left:5px;padding:2px 6px;border-radius:20px;
  background:rgba(222,208,178,.58);color:#8b6940;font-size:8.5px;vertical-align:2px;
}
.ipro-hero p{margin:6px 0 0;font-size:9.5px;color:var(--text-faint);}
.ipro-quote{
  margin:0 3px 6px;padding:10px 12px;
  border-left:2px solid rgba(159,125,82,.4);
  background:linear-gradient(90deg,rgba(255,255,255,.45),transparent);
  font-size:11px;line-height:1.75;color:#746d63;
}
.ipro-sec-head{
  display:flex;justify-content:space-between;align-items:baseline;
  margin:18px 0 8px;padding:0 2px 6px;
  border-bottom:1px solid var(--line);
}
.ipro-sec-head h3{margin:0;font-size:11.5px;font-weight:500;letter-spacing:.08em;color:var(--text);}
.ipro-sec-head small{font-size:8.5px;color:var(--text-faint);}
.ipro-preview p{
  margin:0;font-size:11px;line-height:1.85;color:#69645c;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden;
}
.ipro-preview-foot{display:flex;justify-content:space-between;margin-top:8px;font-size:9px;color:var(--text-faint);}
.ipro-link{border:0;background:none;color:#9f7d52;font-size:9px;cursor:pointer;font-family:inherit;padding:0;}
.ipro-identities{display:flex;gap:9px;overflow-x:auto;padding:10px 2px 5px;scrollbar-width:none;}
.ipro-identities::-webkit-scrollbar{display:none;}
.ipro-identity{
  min-width:96px;flex:none;padding:10px;text-align:left;
  border-radius:14px 5px 14px 5px;
  background:rgba(255,255,255,.55);
  border:1px solid rgba(255,255,255,.68);
  box-shadow:0 5px 14px rgba(84,104,89,.07);
  font-family:inherit;color:var(--text);cursor:pointer;
}
.ipro-mini{
  width:28px;height:28px;margin-bottom:7px;
  display:grid;place-items:center;border-radius:50%;
  background:#dcece1;font-size:10px;color:#6a806d;
}
.ipro-identity b{display:block;font-size:10px;font-weight:500;}
.ipro-identity small{display:block;margin-top:3px;font-size:8px;color:var(--text-faint);}
.ipro-identity.is-add{
  display:grid;place-items:center;gap:5px;
  border-style:dashed;border-color:rgba(159,125,82,.4);
  background:transparent;box-shadow:none;color:#9f7d52;
}
.ipro-plus{width:18px;height:18px;position:relative;}
.ipro-plus::before,.ipro-plus::after{content:'';position:absolute;background:currentColor;}
.ipro-plus::before{left:3px;right:3px;top:8px;height:1px;}
.ipro-plus::after{top:3px;bottom:3px;left:8px;width:1px;}
.ipro-row{
  width:100%;min-height:44px;
  display:grid;grid-template-columns:1fr auto;align-items:center;gap:10px;
  padding:10px 3px;border:0;border-bottom:1px solid var(--line);
  background:none;text-align:left;font-family:inherit;cursor:pointer;color:inherit;
}
.ipro-row b{display:block;font-size:11px;font-weight:500;color:var(--text);}
.ipro-row small{display:block;margin-top:3px;font-size:9px;color:var(--text-faint);line-height:1.55;}
.ipro-side{font-size:9px;color:#a19687;flex:none;}
.ipro-note{margin:12px 3px 0;font-size:9px;color:var(--text-faint);line-height:1.7;}

.ipro-lead-sub{margin:6px 2px 12px;font-size:10px;color:var(--text-faint);line-height:1.7;}
.ipro-editor{
  margin-top:4px;padding:14px 13px 10px;
  background:rgba(255,255,255,.5);
  border-top:1px solid rgba(255,255,255,.8);
  border-bottom:1px solid var(--line);
  box-shadow:0 10px 24px rgba(82,103,87,.09);
}
.ipro-editor textarea{
  width:100%;min-height:300px;padding:0;border:0;resize:none;outline:none;
  background:transparent;font-size:11.5px;line-height:1.9;
  font-family:inherit;color:var(--text);
}
.ipro-editor-foot{display:flex;justify-content:space-between;margin-top:8px;font-size:8.5px;color:var(--text-faint);}
.ipro-guide{
  margin-top:15px;padding:11px 13px;
  background:rgba(222,236,224,.5);
  border-radius:14px 5px 14px 5px;
  color:#716b62;font-size:9px;line-height:1.75;
}
.ipro-guide b{display:block;margin-bottom:4px;font-size:10px;font-weight:500;}
.ipro-guide p{margin:0;}
.ipro-save{
  width:100%;margin-top:16px;padding:13px;
  border:0;border-radius:15px 15px 4px 15px;
  background:#a98458;color:#fff;cursor:pointer;
  font-family:var(--ff-serif);font-size:13px;letter-spacing:.12em;
  box-shadow:0 8px 18px rgba(147,110,69,.2);
}

/* 添加 NPC 抽屉（v2 风格，浮岛总览） */
.iol-drawer{
  position:fixed;inset:0;z-index:110;
  display:flex;align-items:flex-end;
  background:rgba(67,79,70,.2);
  opacity:0;pointer-events:none;transition:opacity .22s;
  max-width:420px;margin:0 auto;
}
.iol-drawer.show{opacity:1;pointer-events:all;}
.iol-drawer-panel{
  width:100%;max-height:82vh;overflow-y:auto;
  padding:22px 20px 30px;
  border-radius:22px 22px 0 0;
  background:#fbfbf4;
  box-shadow:0 -10px 34px rgba(71,94,77,.18);
  transform:translateY(100%);
  transition:transform .28s cubic-bezier(.32,.72,0,1);
}
.iol-drawer.show .iol-drawer-panel{transform:translateY(0);}
.iol-drawer-panel h2{margin:0 0 6px;font-size:17px;font-weight:400;letter-spacing:.06em;color:#514c43;}
.iol-drawer-desc{margin:0 0 4px;font-size:10.5px;color:#988f82;line-height:1.7;}
.iol-field{margin-top:15px;}
.iol-field label{display:block;margin-bottom:7px;font-size:11px;color:#988f82;}
.iol-field input,.iol-field textarea{
  width:100%;border:1px solid rgba(125,148,130,.22);outline:none;
  border-radius:12px;padding:11px 12px;color:#514c43;background:#fff;
  font-size:12.5px;line-height:1.7;font-family:inherit;
}
.iol-field textarea{min-height:84px;resize:vertical;}
.iol-field input:focus,.iol-field textarea:focus{border-color:#a98458;}
.iol-drawer-actions{display:flex;gap:10px;margin-top:20px;}
.iol-drawer-actions button{flex:1;padding:12px;border-radius:13px;font-family:inherit;font-size:12.5px;cursor:pointer;}
.iol-drawer-cancel{background:#eef2eb;color:#988f82;border:0;}
.iol-drawer-save{background:#a98458;color:#fff;border:0;letter-spacing:.08em;}

/* NPC 抽屉 · 照 demo 加的部分（09-19）：分区小标 / 勾选人 / 可见性开关 */
.iol-drawer-sec{
  margin:19px 0 2px;font-size:12.5px;font-weight:500;
  letter-spacing:.08em;color:#514c43;
}
.iol-drawer textarea.is-short{min-height:56px;}
.iol-people{display:grid;gap:7px;margin-top:11px;}
.iol-person-pick{
  display:grid;grid-template-columns:30px 1fr 22px;align-items:center;gap:9px;
  padding:10px 9px;border:1px solid rgba(125,148,130,.22);
  border-radius:13px 5px 13px 5px;background:rgba(255,255,255,.4);
  text-align:left;cursor:pointer;font-family:inherit;
}
.iol-person-pick.is-on{background:rgba(232,242,232,.72);border-color:rgba(117,153,124,.35);}
.iol-pick-ava{
  width:30px;height:30px;display:grid;place-items:center;border-radius:50%;
  background:#eef1dd;font-size:10px;color:#6a806d;
}
.iol-pick-body b{display:block;font-size:10.5px;font-weight:500;color:#514c43;}
.iol-pick-body small{display:block;margin-top:3px;font-size:8.5px;color:#988f82;}
.iol-check{
  width:18px;height:18px;border:1px solid rgba(126,147,129,.32);
  border-radius:50%;position:relative;
}
.iol-person-pick.is-on .iol-check{border-color:#8fa98f;background:#8fa98f;}
.iol-person-pick.is-on .iol-check:after{
  content:"";position:absolute;width:7px;height:4px;left:4px;top:5px;
  border-left:1px solid #fff;border-bottom:1px solid #fff;transform:rotate(-45deg);
}
.iol-opt{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:46px;padding:9px 2px;
  border-bottom:1px solid rgba(125,148,130,.16);
}
.iol-opt-body b{display:block;font-size:11.5px;font-weight:500;color:#514c43;}
.iol-opt-body small{display:block;margin-top:3px;font-size:8.5px;color:#988f82;}
.iol-switch{
  width:34px;height:20px;flex:none;border:0;border-radius:20px;
  background:#d4ddd5;padding:2px;cursor:pointer;position:relative;
  transition:background .15s;
}
.iol-switch:after{
  content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;
  border-radius:50%;background:#fff;box-shadow:0 1px 4px rgba(0,0,0,.12);
  transition:transform .15s;
}
.iol-switch.on{background:#9cbba3;}
.iol-switch.on:after{transform:translateX(14px);}
.iol-drawer-hint{
  margin:12px 0 0;text-align:center;
  font-size:8.5px;color:#988f82;line-height:1.7;
}

/* 添加 NPC · 全屏页面（09-19 从抽屉改成页面：全屏 + 页面内滑动） */
.iol-npc-context{display:flex;align-items:center;gap:10px;padding:16px 2px 2px;}
.iol-npc-isle{
  width:40px;height:25px;flex:none;border-radius:50%;
  background:linear-gradient(#eff9ef,#bdddc5);position:relative;
  box-shadow:inset 0 -5px 8px rgba(116,159,126,.13);
}
.iol-npc-isle:after{
  content:"";position:absolute;width:2px;height:14px;left:19px;top:-10px;
  background:#78a184;
}
.iol-npc-context-copy b{display:block;font-size:12px;font-weight:500;color:#514c43;}
.iol-npc-context-copy small{display:block;margin-top:4px;font-size:9px;color:#988f82;}
.iol-npc-lead{padding:14px 2px 4px;}
.iol-npc-lead h2{margin:0;font-size:19px;font-weight:500;letter-spacing:.06em;color:#514c43;}
.iol-npc-lead p{margin:7px 0 0;font-size:10px;color:#988f82;line-height:1.7;white-space:pre-line;}
.iol-npc-note{margin:8px 2px;font-size:9.5px;color:#988f82;line-height:1.7;}
.iol-opts{display:flex;flex-direction:column;margin-top:4px;}
.iol-npc-hint{
  margin:12px 2px 0;text-align:center;
  font-size:8.5px;color:#988f82;line-height:1.7;
}
/* 新建岛抽屉的房型选项（复用勾选件，整行选中靠暖底，不加多余的框） */
.iol-kind-list{display:grid;gap:7px;margin-top:12px;}
.iol-kind{
  display:flex;align-items:center;justify-content:space-between;gap:9px;
  padding:11px;border:1px solid rgba(125,148,130,.22);
  border-radius:13px 5px 13px 5px;background:rgba(255,255,255,.4);
  text-align:left;cursor:pointer;font-family:inherit;
}
.iol-kind.is-on{background:rgba(232,242,232,.72);border-color:rgba(117,153,124,.35);}
.iol-kind b{display:block;font-size:11.5px;font-weight:500;color:#514c43;}
.iol-kind small{display:block;margin-top:3px;font-size:8.5px;color:#988f82;}
/* 角色档案底部的危险操作：一行小字，不加框 */
.ipro-danger-zone{margin-top:26px;display:flex;justify-content:center;}
.ipro-danger-btn{
  border:0;background:none;cursor:pointer;
  color:#b46a5e;font-family:inherit;font-size:11.5px;
  letter-spacing:.04em;padding:8px;
}

/* ============================================================
   日记（dia-*，2026-09-19 重做）
   灵魂是「纸」：花字只花在日期头，信纸靠线纹撑质感。
   壁纸全部浅色纸纹，跟焦糖主色同一族；hairline 边 + 带色浅影。
   ============================================================ */
.dia-page{position:relative;min-height:100%;padding-bottom:8px;}
.dia-gear{
  position:absolute;top:16px;right:14px;z-index:3;
  width:36px;height:36px;border:0;border-radius:50%;
  background:none;cursor:pointer;color:var(--text-faint);
  display:flex;align-items:center;justify-content:center;
}
.dia-gear svg{width:20px;height:20px;}
.dia-gear:active{background:var(--bg-3);}

/* ---- 日期头（花字区）---- */
.dia-head{position:relative;padding:26px 22px 4px;}
.dia-head-month{
  margin:0 0 2px;font-size:11.5px;letter-spacing:.32em;
  color:var(--g-accent-deep,#967346);
}
.dia-head-day{
  margin:0;
  font-family:Georgia,'Times New Roman','Songti SC',SimSun,serif;
  font-style:italic;font-weight:400;
  font-size:64px;line-height:.95;letter-spacing:-.03em;
  color:var(--text);
  text-shadow:2px 2px 0 rgba(176,138,94,.16);
}
.dia-head-wave{width:96px;color:var(--g-accent);opacity:.75;margin:6px 0 8px;}
.dia-head-wave svg{display:block;width:100%;height:8px;}
.dia-head-quote{
  margin:0;font-size:11px;letter-spacing:.14em;
  color:var(--text-faint);
}

/* ---- 信纸卡片 ---- */
.dia-feed{display:flex;flex-direction:column;gap:16px;padding:10px 16px 96px;}
.dia-paper{
  position:relative;
  background-color:#fff;
  border:1px solid var(--line);
  border-radius:2px;
  padding:16px 16px 10px;
  box-shadow:0 1px 2px rgba(90,70,40,.06),0 10px 26px rgba(90,70,40,.05);
}
/* 和纸胶带：一页顶一条，斜一点才有贴上去的感觉 */
.dia-paper::before{
  content:'';position:absolute;top:-9px;left:50%;
  width:64px;height:17px;
  transform:translateX(-50%) rotate(-2.4deg);
  background:rgba(196,166,120,.30);
  border-left:1px dashed rgba(255,255,255,.55);
  border-right:1px dashed rgba(255,255,255,.55);
}
/* 信纸线纹：卡片和小样共用同一组类 */
.dia-paper-ruled{background-image:repeating-linear-gradient(transparent 0 27px,rgba(120,100,70,.13) 27px 28px);}
.dia-paper-grid{
  background-image:
    linear-gradient(rgba(120,100,70,.11) 1px,transparent 1px),
    linear-gradient(90deg,rgba(120,100,70,.11) 1px,transparent 1px);
  background-size:22px 22px;
}
.dia-paper-dotted{background-image:radial-gradient(circle,rgba(120,100,70,.16) 1px,transparent 1.3px);background-size:22px 22px;}
.dia-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px;}
.dia-stamp{
  font-size:10.5px;letter-spacing:.1em;
  color:var(--g-accent-deep,#967346);
  border:1px solid rgba(176,138,94,.45);
  border-radius:3px;padding:1px 7px;
  transform:rotate(-1.2deg);
}
.dia-author{font-size:10.5px;color:var(--text-faint);}
.dia-author.is-pending-tag{color:#C07A6B;}
.dia-text{
  margin:0;font-size:14px;color:var(--text);
  line-height:28px;              /* 跟横线信纸的 28px 栅格对齐 */
  white-space:pre-wrap;overflow-wrap:anywhere;
}
.dia-paper-grid .dia-text,.dia-paper-dotted .dia-text{line-height:22px;} /* 对齐 22px 栅格 */
.dia-text.is-pending{color:var(--text-faint);font-style:italic;}
.dia-foot{margin-top:8px;}
.dia-foot-btn{
  border:0;background:none;cursor:pointer;font-family:inherit;
  font-size:12px;color:var(--g-accent);padding:4px 0;
}
.dia-rel{display:block;text-align:right;font-size:10px;color:var(--text-faint);margin-top:6px;}

/* ---- 空态：一枚歪的印章 ---- */
.dia-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:44px 0 16px;}
.dia-empty-seal{
  width:46px;height:46px;display:flex;align-items:center;justify-content:center;
  border:1.5px solid rgba(192,122,107,.5);border-radius:4px;
  color:#C07A6B;font-family:Georgia,'Songti SC',SimSun,serif;font-size:20px;
  transform:rotate(-6deg);
}
.dia-empty-text{margin:0;font-size:13px;color:var(--text-dim);}
.dia-empty-hint{margin:0;font-size:11px;color:var(--text-faint);}

/* FAB 复用全局 .fab-btn，这里只管里面的笔 */
.dia-fab svg{width:22px;height:22px;}

/* ---- 设置页：壁纸 / 信纸选择 ---- */
.dia-wall-row{display:flex;flex-wrap:wrap;gap:12px;padding:4px 2px 8px;}
.dia-wall-chip{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  border:0;background:none;cursor:pointer;font-family:inherit;padding:2px;
}
.dia-wall-swatch{
  width:44px;height:44px;border-radius:4px;
  border:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;
  font-size:16px;color:var(--text-faint);
}
.dia-wall-chip.is-on .dia-wall-swatch{box-shadow:0 0 0 1.5px var(--g-accent);}
.dia-wall-name{font-size:10.5px;color:var(--text-dim);}
.dia-paper-row{display:flex;flex-wrap:wrap;gap:12px;padding:8px 2px 4px;}
.dia-paper-chip{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  border:0;background:none;cursor:pointer;font-family:inherit;padding:2px;
}
.dia-paper-swatch{
  width:44px;height:32px;border-radius:3px;
  border:1px solid var(--line);background-color:#fff;
}
.dia-paper-chip.is-on .dia-paper-swatch{box-shadow:0 0 0 1.5px var(--g-accent);}

/* ---- 壁纸底纹（页面与色板共用）---- */
.dia-wall-plain{background-color:#FFFFFF;}
.dia-wall-cream{
  background-color:#FBF6EC;
  background-image:repeating-linear-gradient(0deg,rgba(196,166,120,.06) 0 1px,transparent 1px 7px);
}
.dia-wall-mint{
  background-color:#F2F7F3;
  background-image:
    linear-gradient(rgba(120,150,125,.07) 1px,transparent 1px),
    linear-gradient(90deg,rgba(120,150,125,.07) 1px,transparent 1px);
  background-size:14px 14px;
}
.dia-wall-sakura{
  background-color:#FBF2F4;
  background-image:radial-gradient(circle,rgba(214,140,155,.12) 1.2px,transparent 1.6px);
  background-size:18px 18px;
}
.dia-wall-kraft{
  background-color:#F4ECDC;
  background-image:repeating-linear-gradient(90deg,rgba(150,115,70,.05) 0 1px,transparent 1px 5px);
}
.dia-wall-dusk{
  background-color:#F6F0EA;
  background-image:linear-gradient(160deg,rgba(176,138,94,.08),transparent 55%);
}
.dia-wall-media{background-size:cover;background-position:center;}

/* ---- 写日记页 ---- */
.dia-edit-paper{margin:6px 16px 14px;}
.dia-edit-paper .set-field textarea{line-height:28px;}

/* ---- 查岗卡片 ---- */
.msg-checkin{
  position:relative;max-width:220px;
  border:1px solid var(--line);border-radius:2px;
  overflow:hidden;background:var(--surface);
}
.msg-checkin .msg-photo-img{display:block;width:100%;}
.msg-checkin-cap{
  padding:6px 9px 7px;font-size:11px;line-height:1.5;
  color:var(--text-dim);border-top:1px solid var(--line);
}
.msg-checkin-tag{
  position:absolute;top:6px;right:6px;
  font-size:9.5px;letter-spacing:.08em;
  color:#fff;background:rgba(192,122,107,.88);
  padding:2px 7px;border-radius:2px;
}

/* 空态垂直居中：页面走 flex 列，空态吃掉剩余空间 */
.dia-page{display:flex;flex-direction:column;}
.dia-empty{flex:1;justify-content:center;padding:0 0 10vh;}

/* FAB 两选一的小面板 */
.dia-fab-sheet{position:fixed;inset:0;display:none;z-index:30;}
.dia-fab-sheet.is-open{display:block;}
.dia-fab-mask{position:absolute;inset:0;background:rgba(20,14,8,.22);}
.dia-fab-menu{
  position:absolute;bottom:160px;right:22px;
  min-width:196px;padding:4px;
  background:var(--surface);border:1px solid var(--g-glass-line);
  border-radius:10px;
  box-shadow:0 14px 34px rgba(90,70,40,.22);
}
.dia-fab-item{
  display:flex;flex-direction:column;gap:2px;align-items:flex-start;
  width:100%;border:0;background:none;cursor:pointer;
  font-family:inherit;text-align:left;
  font-size:13.5px;color:var(--text);
  padding:10px 12px;border-radius:7px;
}
.dia-fab-item:active{background:var(--bg-3);}
.dia-fab-item-hint{font-size:10.5px;color:var(--text-faint);}

/* ---- 日记顶栏：顶栏是这张纸的一部分 ----
   壁纸铺在 section（.page）上，顶栏透明后露出来的就是同一张纸；
   滚动时内容从磨砂顶栏下面过（全局那层 backdrop blur 保留）。 */
.page[data-page^="diary"] .app-head{background:transparent;}
.page[data-page^="diary"] .app-head::after{display:none;}
.page[data-page^="diary"] .back-btn{
  background:rgba(255,255,255,.55);
  color:var(--g-accent-deep,#967346);
}
/* 封面感的字距 + 焦糖深色，像本子脊上烫的字 */
.page[data-page^="diary"] .app-title{
  letter-spacing:.32em;
  color:var(--g-accent-deep,#967346);
  font-size:17px;
}

/* ---- 生图弹层（gen-*，方案-生图 v2） ---- */
.gen-sheet-mask{
  position:fixed;inset:0;z-index:60;
  background:rgba(20,14,8,.30);
  display:flex;align-items:center;justify-content:center;
  padding:20px;
}
.gen-sheet{
  width:100%;max-width:340px;max-height:86vh;overflow-y:auto;
  background:var(--surface);border:1px solid var(--g-glass-line);
  border-radius:10px;padding:14px;
  box-shadow:0 18px 44px rgba(40,28,14,.28);
}
.gen-tabs{display:flex;gap:14px;margin:0 2px 10px;}
.gen-tab{
  border:0;background:none;font-family:inherit;cursor:pointer;
  font-size:13.5px;color:var(--text-faint);
  padding:2px 0 6px;border-bottom:2px solid transparent;
}
.gen-tab.active{color:var(--text);border-bottom-color:var(--g-accent);}
.gen-intent{
  width:100%;box-sizing:border-box;resize:none;
  background:var(--bg-2);border:1px solid var(--line);border-radius:8px;
  padding:9px 11px;font-family:inherit;font-size:13px;color:var(--text);
  margin-bottom:10px;
}
.gen-intent:focus{outline:none;border-color:var(--g-accent);}
.gen-preview{
  min-height:120px;border:1px dashed var(--line);border-radius:8px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  margin-bottom:8px;padding:8px;
}
.gen-preview-empty{margin:0;font-size:11.5px;color:var(--text-faint);}
.gen-preview-img{max-width:100%;max-height:240px;border-radius:6px;}
.gen-preview-cap{margin:8px 0 0;font-size:11.5px;color:var(--text-dim);text-align:center;}
.gen-status{margin:0 2px 8px;font-size:11.5px;color:var(--text-dim);min-height:16px;}
.gen-btns{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;}

/* TA 发的图带图注 */
.msg-photo-cap{
  padding:6px 9px 7px;font-size:11px;line-height:1.5;
  color:var(--text-dim);border-top:1px solid var(--line);
}

/* ---- 日记配图 ---- */
.dia-pic{margin-top:10px;}
.dia-pic-img{
  display:block;width:100%;max-height:300px;object-fit:cover;
  border-radius:2px;border:1px solid var(--line);
}
.dia-edit-pic{
  display:flex;align-items:center;gap:10px;
  margin-top:10px;padding:6px 2px 2px;
}
.dia-edit-pic-img{
  width:64px;height:64px;object-fit:cover;
  border:1px solid var(--line);border-radius:3px;
}
.dia-edit-pic-add,.dia-edit-pic-rm{
  border:1px solid var(--line);border-radius:7px;
  background:none;font-family:inherit;cursor:pointer;
  font-size:11.5px;color:var(--text-dim);padding:5px 10px;
}
.dia-edit-pic-add:active,.dia-edit-pic-rm:active{background:var(--bg-3);}
.dia-edit-pic-hint{font-size:10.5px;color:var(--text-faint);}
