/* ======================================================================
   小青柠 · 手机端（App）样式  ——  视觉口径：闲鱼式「图片优先 · 高密度市集」
   ----------------------------------------------------------------------
   三条纪律：
   1) 这里的 :root 令牌**必须与 static/css/app.css 的值逐字一致**。
      为什么是复制而不是 @import：手机端不想背上 app.css 那一千多行 PC 布局
      （固定顶栏、宽网格之类会互相打架）。为了不出现「改了一处忘了另一处」，
      有 scripts/audit_mobile_tokens.py 做机械比对，不一致就直接报错。
   2) **零外网依赖**：不引任何字体 CDN。字体走系统自带，图片全部本地素材
      （static/img/seed/），断网、弱网、内网都能秒开。
   3) **卡片是「图片优先」的**：一张需求卡 = 大图 + 标题 + 价格 + 发需求的人。
      这一条是从闲鱼学来的核心：没有图的列表看起来像后台表格，
      有图的列表才像「有人在过日子」。
   ====================================================================== */

:root {
  /* 底色：暖白（带一丝温度的白，不是办公室冷白） */
  --paper: #faf9f7;
  --paper-2: #f2f0ec;
  --surface: #ffffff;
  --surface-2: #f7f6f3;

  /* 墨色 */
  --ink: #1a1a1d;
  --ink-2: #5f6268;
  --ink-3: #9b9ea5;
  --ink-4: #c3c5ca;

  /* 品牌：得物青绿（行动 / 圆梦 / 选中 / 信任） */
  --brand: #00bda6;
  --brand-deep: #009c8a;
  --brand-soft: #ddf7f2;
  --brand-tint: #f0fbf9;

  /* 温度：蜜橘（价格 / 急单 / 加价 / 人气）——「温暖」的主要来源 */
  --coral: #ff6a45;
  --coral-deep: #e2522f;
  --coral-soft: #ffece5;

  /* 潮流高亮：嫩芽绿（限时 / 新 / 推荐 这类小面积贴纸） */
  --lime: #d4f14a;
  --lime-soft: #f0fbc8;

  /* 信任：深墨青（担保 / 资金监管的深色块） */
  --jade: #103c37;
  --jade-deep: #062521;
  --jade-soft: #e3f3f0;

  /* 荣誉：金（信用分 / 积分） */
  --gold: #c8952c;
  --gold-soft: #fcf2d8;
  /* 金/柠底上的「墨色」文字（T50 统一：此前 #8a6414/#8a6314/#5e7412/#566b12 四处散写） */
  --gold-ink: #8a6414;
  --lime-ink: #5e7412;

  /* 状态色 */
  --line: #efede9;
  --line-2: #e4e1db;
  --danger: #e5402f;
  --danger-soft: #ffeae6;
  --danger-ink: #a13a3a;
  --warn: #d98211;
  --warn-soft: #fff3dd;
  --warn-ink: #8a5a00;
  --ok: #12a37a;
  --ok-soft: #e0f6ee;

  /* 层次：柔和多层阴影，取代边框做分隔 */
  --sh-1: 0 1px 2px rgba(26, 26, 29, .04), 0 6px 16px -10px rgba(26, 26, 29, .16);
  --sh-2: 0 2px 6px rgba(26, 26, 29, .05), 0 22px 44px -24px rgba(26, 26, 29, .26);
  --sh-brand: 0 10px 24px -12px rgba(0, 189, 166, .55);
  --sh-coral: 0 10px 24px -12px rgba(255, 106, 69, .55);
  /* --sh-sheet：从屏幕底部升起来的面板（抽屉 / 筛选 / 支付 / 设置 / 头像）专属。
     影子朝**上**打在它盖住的内容上 —— 用 --sh-2 那种朝下的影子会让面板像是
     「陷进」屏幕里。原来这 6 个面板各写各的：2 个抄了这条向上阴影、
     2 个用 --sh-2（朝下）、2 个干脆没影子，同一个手势推出来的东西层次不齐。
     皮肤不改它：板块的暖/素体现在卡纸上，面板永远是浮在内容之上的实体。 */
  --sh-sheet: 0 -10px 40px rgba(20, 22, 26, .18);

  /* 圆角：大会显得贵、显得轻松 */
  --r-xs: 8px;
  --r-sm: 12px;
  --r: 18px;
  --r-lg: 26px;
  --r-xl: 34px;
  --r-pill: 999px;

  /* 字体：全无衬线。标题粗黑收紧，是「潮流」而不是「启事」 */
  --f-display: "Noto Sans SC", "Source Han Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  --f-sans: "Noto Sans SC", "Source Han Sans SC", "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", system-ui, sans-serif;
  --f-mono: "IBM Plex Mono", "JetBrains Mono", Consolas, "Courier New", monospace;

  /* 节奏 */
  --gut: clamp(16px, 3.2vw, 40px);
  --maxw: 1240px;
  --ease: cubic-bezier(.22, 1, .36, 1);      /* ease-out-quart */
  --ease-out: cubic-bezier(.16, 1, .3, 1);   /* ease-out-expo  */
  /* ---------- T61：补齐四张令牌表（间距 / 字号 / 层级 / 时长）----------
     为什么加：动手前把两个样式表里实际写下的值数了一遍 ——
       字号  app.css 32 种 / m.css 34 种（含 9px、9.5px 这种手机上读不清的）
       时长  两边合起来 15 种（0.08s ~ 0.55s）
       层级  app.css 16 种 / m.css 27 种（最高 1201）
     同一个「小按钮」在 A 页 42px 高、B 页 44px 高，用户说不清哪里怪，但一眼就觉得不齐。
     根因不是谁写错了，是这套令牌**只有颜色/圆角/阴影**，没有间距、字号、层级、时长 ——
     没规矩时每个人（包括 AI）只能自己发明一个。这一波只立表，后面几波把组件搬上表。 */

  /* 间距：以后只准从这张表里取值，不许再写 13px / 15px / 18px 这种自己凑的数 */
  --sp-2xs: 4px;
  --sp-xs: 6px;
  --sp-sm: 8px;
  --sp-md: 10px;
  --sp-lg: 12px;
  --sp-xl: 16px;
  --sp-2xl: 20px;
  --sp-3xl: 24px;
  --sp-4xl: 32px;
  --sp-5xl: 40px;

  /* 字号阶梯：12 档。地板 10px（T50 定过：比这更小在手机上读不清），
     --fs-6 是正文基准，各页只许在它上面加减档，不许偷改它 */
  --fs-1: 10px;    /* 徽标计数、角标 */
  --fs-2: 11px;    /* 贴纸标签 */
  --fs-3: 12px;    /* 时间戳、辅助说明 */
  --fs-4: 13px;    /* 次要文字、紧凑按钮 */
  --fs-5: 14px;    /* 表单、列表行 */
  --fs-6: 15px;    /* 正文 */
  --fs-7: 16px;    /* 主按钮、小标题 */
  --fs-8: 18px;    /* 区块标题 */
  --fs-9: 21px;    /* 页面标题 */
  --fs-10: 24px;   /* 首屏大标题 */
  --fs-11: 30px;   /* 强调数字（金额、评分） */
  --fs-12: 42px;   /* 只给 hero / 空态大数字 */

  /* 层级：谁盖在谁上面，一次说清。数值不是猜的 —— 由 Wave 1c 现量 m.css 84 处 +
     app.css 34 处 z-index 后定的档；每档都对应现在真在用的一个值，所以套上令牌
     等于零行为变化，只是以后再加浮层有个地方可以选，而不是继续 +1 往上碰运气。
     网页版顶栏 60 / tab 70 / 详情条 120 是历史高度（比手机端的 40/50 高），
     本次不动它们：动一处的层序要全站重排，风险远大于「数字不好看」。 */
  --z-raise: 5;        /* 卡片抬起、角标、局部内层 */
  --z-sticky: 20;      /* 吸顶筛选条、页内小浮层（表情面板网页版） */
  --z-drop: 45;        /* 下拉菜单、筛选面板 */
  --z-nav: 50;         /* 手机端顶栏（40）与底部 tab（50） */
  --z-sheet: 60;       /* 底部抽屉/遮罩：遮罩用本档，面板一律 +1 */
  --z-pop: 90;         /* 支付密码面板、动态设置层、全局提示条 */
  --z-lightbox: 300;   /* 图片 / 视频全屏看 */
  --z-loading: 999;    /* 全局加载遮罩 —— 必须压住灯箱，否则转圈看不见 */
  --z-top: 1000;       /* 表情面板、多选工具条 */
  --z-max: 1200;       /* 系统级抽屉（设置）：遮罩本档、面板 +1 */

  /* 动效时长：同一类动作全站用同一个数，快慢感才一致。
     手机端 T27 验过「下滑卡顿」，收短时长的同时只留 transform/opacity 做动效 */
  --dur-0: 80ms;     /* 极微反馈（颜色一闪） */
  --dur-1: 120ms;    /* 按压反馈 :active */
  --dur-2: 180ms;    /* 边框/底色变化 */
  --dur-3: 260ms;    /* 浮层进出、卡片展开 */
  --dur-4: 360ms;    /* 抽屉、面板滑入 */
  --dur-5: 520ms;    /* 进场、页面转场 */
  --ease-in-out: cubic-bezier(.4, 0, .2, 1);

  /* 组件常量：按钮/输入框「一行多高」以前两端各写各的（网页 42~43、手机 44~58 共十余种） */
  --ctl-h: 44px;     /* 触控最小热区（安卓/iOS 无障碍下限，手机端主控件一律不低于它） */
  --ctl-h-sm: 36px;  /* 紧凑档：筛选 chip、工具条按钮 */
  --ctl-h-lg: 50px;  /* 主行动：注册 / 发布 / 提交 */
  --ring: 0 0 0 4px var(--brand-soft);
  /* 焦点环以前两端不同色：网页用 --brand-soft、手机用 --brand-tint ——
     同一种「我正在填这一格」出现两种颜色，就是「不统一」的来源之一 */
  --scrim: rgba(20, 22, 26, .45);
  /* 遮罩黑统一用这一档（中性墨色、不掺品牌绿：换肤 sk-cir/sk-qn 下品牌绿遮罩会糊成一块）。
     统一前实测 5 种写法：rgba(16,60,55,.38) / rgba(0,0,0,.4) / rgba(0,0,0,.38)
     / rgba(26,26,29,.42) / rgba(15,20,24,.5) / rgba(16,40,36,.55) —— .45 取它们的中位。 */
  --scrim-media: rgba(8, 10, 12, .94);
  /* 看图 / 看视频的深遮罩要压住整屏照片，单独一档，不和普通浮层混用 */
  --r-sheet: 20px;
  /* 底部抽屉的圆角。统一前实测 4 种：16px（头像选择）/ 18px（支付、动态设置、网页版支付）
     / 20px（发布动作）/ var(--r)=18px（设置抽屉）—— 取最大值 20，比原来更柔和，
     且不越出「底部抽屉」这一档（再大就到了 --r-lg 26 卡片档）。 */
  --grad-brand: linear-gradient(135deg, var(--brand), var(--brand-deep));
  /* 主按钮底色。网页版一直是这条渐变、手机端是纯 --brand —— 同一个「提交/圆梦」按钮，
     两端两种质感。统一成渐变：同色系一深一浅，比纯色柔和，也是网页版已有的观感。 */

  /* 手机端自己的节奏 */
  --top-h: 52px;
  /* T28：顶栏那条下边框是**吃掉布局高度**的 1px（不是画上去的）。
     聊天面按「100svh − 顶栏」算自己的高，漏掉这 1px 整页就比窗口高 1px ⇒ 一划就能把
     整页顶上去动一下（派总 2026-10-28「整个内容页比窗口大」纵向那一半，实测 845 对 844）。
     收成变量给两边用，别一边改宽度另一边还按老数算。 */
  --top-line: 1px;
  --tab-h: 58px;
  /* 派总 2026-11-04 第 2 条「视频要真全屏，系统时间/信号/WiFi/电量悬浮在画面之上」：
     App 壳（Flutter WebView）已改成 edgeToEdge + 刘海 shortEdges ⇒ 网页真的铺到屏幕最顶，
     但 **Android WebView 里 `env(safe-area-inset-*)` 恒为 0**（iOS WKWebView 才给真值），
     于是铺上去的内容会被状态栏压在底下 —— 顶栏、底栏、每一层贴边浮条都靠这两个 token 让位。
     绕法：壳把系统真实 inset 通过 `MediaQuery.paddingOf` 注成 `--app-safe-t/b`
     （见 app/lib/pages/webview_page.dart），这里取两者的**较大值**。
     ⚠️ 为什么是 max 而不是「有注入就用注入值」：① iOS 走 env 就有真值、没有注入；
     ② 桌面浏览器和网页版两个都是 0 ⇒ max 之后逐位不变，不会把已量过的几何全顶偏；
     ③ 万一哪天 Android WebView 开始报 env 真值，也自动取准的那个，不会双倍扣高。
     取较大值不会重复扣 —— 两个源说的是同一件事，谁给得多信谁。
     ⚠️ 因此手机端规则**只许用这两个 token，不许再写裸 `env(safe-area-inset-*)`**：
     裸 env 在壳里恒 0，等于「iOS 让位、安卓压字」，而同一个类在两端看着一模一样。
     两端共用的那几张样式表（share / loc / img-grid / video-edit）写成
     `var(--safe-x, env(safe-area-inset-x, 0px))`：token 只在 m.css 有（app.css 没有，
     见 scripts/audit_mobile_tokens.py 的 MOBILE_ONLY 白名单），少了这层兜底，
     网页版那条 padding 会整个失效 —— 不是掉 0，是**这一行声明不被应用**。 */
  --safe-b: max(env(safe-area-inset-bottom, 0px), var(--app-safe-b, 0px));
  --safe-t: max(env(safe-area-inset-top, 0px), var(--app-safe-t, 0px));

  /* T18⑤：板块纸色**只在这里存一份**（body.m-skin-* 与 .brand-preview.sk-* 都引用它）。
     横滑预览层要涂的是「对面那块板」的纸色，没有这一对令牌就得把十六进制抄第二遍 ——
     抄两遍迟早分家，分家就是「切换时颜色跳一下」。
     ⚠️ 这一对原先写在 `body {}` 里，值一样、继承也一样，但 `body` 里的令牌
     scripts/audit_mobile_tokens.py 扫不到（它只扫 `^:root{...^}`）——
     「扫不到」不是「不影响」，是**这两个值从此没人管**。挪进 :root 才进闸门。
     T51①（派总 2026-10-30「粉底收敛」）：小圈子正文底色回全站暖白，
     --paper-cir 一对退役；暖粉只留在胶囊 / 角标 / 海报这些点缀上。 */
  --paper-qn: #fbf9f7;
  --paper-2-qn: #f2efec;
}

/* T24②（派总 2026-10-27）：点任何按钮都冒出一层灰色交互显示 —— 那是安卓 WebView 的
   默认点按高亮（-webkit-tap-highlight-color 默认半透明灰，叠在 CSS 之上，页面里任何
   可点元素都吃）。全站关掉：按压反馈只留 CSS 自己的 :active 缩放/变色，不再叠系统灰。
   之前只有零星几个类单独设过它，其余元素全漏 —— 必须全局 '*' 一条才关得干净。 */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
[hidden] { display: none !important; }

html, body { margin: 0; padding: 0; }
/* 派总 2026-10-25 返工第 5 条（重点）：不许浏览器把**整页/顶部**往下拽。
   Chrome 的原生下拉刷新会连 sticky 顶栏一起拽、iOS 的橡皮筋会整屏回弹，
   两种都表现为「上面的标签被扯下来了」。overscroll-behavior 关掉滚动链，
   refresh.js 再在真正下拉那一把 preventDefault 兜底（老内核也管得住）。 */
html { overscroll-behavior-y: none; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-sans);
  font-size: 15px;
  line-height: 1.6;
  /* Z5②（派总 2026-10-15 晚）：禁双击放大（捏合由 JS gesturestart 拦 + viewport 兜底） */
  touch-action: manipulation;
  -webkit-font-smoothing: antialiased;
  text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
  /* 板块纸色那一对令牌在 :root（原写在这里：闸门只扫 :root，写在 body 就扫不到）。 */
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
/* T16i-2（派总 2026-10-23）：全站禁用长按弹出的**系统**菜单 —— iOS 的
   「存储图像 / 拷贝 / 共享」卡、划词选择菜单、安卓 WebView 的图片长按菜单。
   原则：App 内一切长按只认站内自己的菜单（聊天长按、图片排序拖动等）。
   -webkit-touch-callout 只在 iOS 生效（管链接/图片长按卡）；
   user-select:none 管划词（文本长按的选择+拷贝菜单）—— 输入框除外，打字/粘贴要留；
   安卓的长按菜单 CSS 管不到，由 app.js 的 contextmenu 事件拦截兜底。 */
body, body * { -webkit-touch-callout: none; }
body { -webkit-user-select: none; user-select: none; }
body input, body textarea, body select, body [contenteditable="true"] {
  -webkit-user-select: text; user-select: text;
}
body img { -webkit-user-drag: none; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4 { margin: 0; font-weight: 900; letter-spacing: -.02em; line-height: 1.3; }
p { margin: 0; }
/* dl 浏览器默认带 1em 下边距 —— 不清掉会在详情页「需求参数」下面留一条空带，
   看起来像布局没对齐（verify_layout 量不出来，只有看截图才发现）。 */
dl, dd { margin: 0; }
.ic { width: 20px; height: 20px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ic-sm { width: 16px; height: 16px; }
.ic-lg { width: 26px; height: 26px; }

/* ----------------------------------------------------------------------
   骨架：顶栏（含搜索）/ 内容 / 底部 tab
   ---------------------------------------------------------------------- */
.m-top {
  position: sticky; top: 0; z-index: 40;
  padding-top: var(--safe-t);
  /* T17②（派总 2026-10-25 第 2 条）：顶栏背景与页面背景**合成一张**。
     原来这里写死 rgba(250,249,247,.92) + 毛玻璃，而 body 走 --paper
     （小圈子 #fdf6ef / 小青柠 #fbf9f7）⇒ 两套颜色中间永远隔一条缝，
     滚动时还有毛玻璃糊出来的「另一个区域」。改成 var(--paper) 之后
     顶栏跟着 body 的皮肤走，缝隙自然消失。 */
  background: var(--paper);
  border-bottom: var(--top-line) solid transparent;
  transition: border-color .2s;
}
.m-top.is-stuck { border-bottom-color: var(--line); }
/* 首页（两层标签钉着的那两页）不要那条分隔线：它把「一个背景」又切回两块。
   其余页面（详情页/表单页）仍然要，滚动后分不清顶栏会看着更乱。 */
.m-top.is-home { border-bottom-color: transparent; }
.m-top-in {
  height: var(--top-h);
  display: flex; align-items: center; gap: 8px;
  padding: 0 12px;
  max-width: 720px; margin: 0 auto;
}
/* ——— T17①（派总 2026-10-25 第 1 条）首页顶栏三段式 ———
   左 = 预留按钮位，中 = 「小圈子 / 小青柠」一级卡片**绝对居中**，右 = 搜索图标。
   为什么用 absolute 居中而不是 flex 三段等分：一级卡片的宽度会随皮肤/语言变，
   左右两侧只要不等宽，flex 的 `justify-content:center` 就把中心偏出去半个按钮；
   绝对定位的 left:50% 是**真的**屏宽中心，两侧各占多少都不影响它。
   ⚠️ 只挂在 .m-top.is-home 上：详情页/表单页/搜索页的顶栏排法一个字都没动。 */
.m-top.is-home .m-top-in { position: relative; }
.m-top.is-home .m-topswitch {
  position: absolute; left: 50%; transform: translateX(-50%);
}
.m-top-reserved, .m-top-searchbtn {
  width: 34px; height: 34px; flex-shrink: 0;
  display: grid; place-items: center;
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--ink-2); cursor: pointer;
}
.m-top-reserved:active, .m-top-searchbtn:active { background: var(--paper-2); }
/* 搜索图标 → 点它才把输入框伸展出来（逻辑在 app.js 的 initTopSearchToggle）。
   平时输入框**收成 0 宽但留在 DOM 里**：display:none 会让 .m-topsearch input
   既量不到也 focus 不了（历史验收脚本与服务端测试都按它定位）。 */
.m-top.is-home .m-topsearch {
  flex: 0 0 auto; max-width: 0; opacity: 0; padding: 0;
  overflow: hidden; pointer-events: none;
  transition: max-width .28s var(--ease), opacity .18s ease, padding .28s var(--ease);
}
.m-top.is-home .m-top-in.is-searching .m-topsearch {
  flex: 1; max-width: none; opacity: 1; padding: 0 12px; pointer-events: auto;
}
/* 进入搜索态后左右两个入口让位，整行都是输入框
   （spacer 也要撤：它还占着 flex:1 的话，伸展出来的输入框只能拿到半行宽） */
.m-top.is-home .m-top-in.is-searching .m-top-reserved,
.m-top.is-home .m-top-in.is-searching .m-top-searchbtn,
.m-top.is-home .m-top-in.is-searching .m-top-spacer { display: none; }
/* min-width:0：顶栏是 flex，标题带了 m-ellipsis 要能被 spacer 挤着截断，
   否则长圈子名会把右上角那组按钮顶出屏幕（三轮② spacer 布局的前提）。 */
.m-title { font-size: 17px; font-weight: 900; letter-spacing: -.02em; min-width: 0; }
/* 品牌标志（2026-09-23）：与网页端同一个文件 `xqn-mark-ui.svg`（抽稀版），
   只是尺寸压到 22px（顶栏）/ 20px（首页，要把宽度让给搜索框）。
   `flex-shrink:0` 不能省 —— 顶栏是 flex，标题一长标志会被压扁。 */
.m-mark {
  width: 22px; height: 22px;
  display: inline-block;
  vertical-align: -5px;
  margin-right: 6px;
  flex-shrink: 0;
}
.m-title-sub { font-size: 11.5px; color: var(--ink-3); font-weight: 500; letter-spacing: 0; }
/* —— 顶栏分段 tab（派总 2026-09-30 定稿）——
   顶栏原有的「小圈子 / 小青柠」两个入口按钮 = 一组 tab：
   站在哪个板块哪个白底浮起（+青绿底线+图标恢复彩色），点另一个切板块。
   右侧定位、搜索照旧；极窄屏的退化见文件尾部的媒体查询。 */
.m-topswitch {
  display: flex; gap: 2px; padding: 3px; flex-shrink: 0;
  /* T61：这块「顶栏板块切换」和首页页签 .m-ftab、分类胶囊 .pc-cat 是同一种控件，
     原来却写死 #efede7 + 11px（换肤不跟手）。底色归到 --surface-2（凹下去的那一档），
     圆角归到 --r-sm；两块板块各自的强调底色仍由下面 body.m-skin-* .m-topswitch 覆盖。 */
  background: var(--surface-2); border-radius: var(--r-sm);
  /* 搜索伸展用（见下方 .m-top-in.is-searching）：向左收起时靠 max-width 过渡 */
  transition: max-width var(--dur-3) var(--ease), opacity var(--dur-2) var(--ease),
              margin var(--dur-3) var(--ease);
  max-width: 240px; overflow: hidden;
}
.m-ttab {
  position: relative;
  display: inline-flex; align-items: center; gap: 4px;
  height: 30px; padding: 0 10px; border-radius: var(--r-xs);
  color: var(--ink-3); font-size: 13px; font-weight: 800; letter-spacing: -.01em;
  white-space: nowrap; flex-shrink: 0; cursor: pointer;
  transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}
.m-ttab .m-mark { width: 15px; height: 15px; margin: 0; vertical-align: 0;
                  filter: grayscale(1); opacity: .55; transition: filter .15s, opacity .15s; }
.m-ttab .ic { width: 15px; height: 15px; }
.m-ttab.on {
  background: var(--surface); color: var(--ink);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
}
.m-ttab.on::after {          /* 青绿底线 = 全站「brand=选中」的口径 */
  content: ''; position: absolute; left: 9px; right: 9px; bottom: 2px; height: 2.5px;
  border-radius: 2px; background: var(--brand);
}
.m-ttab.on .m-mark { filter: none; opacity: 1; }
.m-ttab:active { transform: scale(.97); }
/* —— 搜索伸展（派总 2026-09-30）：点搜索框 → tab 组向左收起，
   搜索框（flex:1，见 .m-topsearch）顺势占满整行 —— 输入区直接翻倍。
   状态类由 base.html 的 focusin/focusout 挂到 .m-top-in 上；无 JS 时不生效，功能无损。 */
.m-top-in.is-searching .m-topswitch { max-width: 0; opacity: 0; margin-left: -8px; padding-left: 0; padding-right: 0; }
.m-top-in.is-searching .m-topsearch { box-shadow: 0 2px 12px rgba(16, 60, 55, .14); }
/* T29①（派总 2026-10-28「全站的定位功能全部下架」）：首页那颗定位胶囊 m-loc
   与行内版 m-loc-row（连同模板 m/_loc_row.html）整组撤下，第二步按新框架再重建。 */
.m-back {
  width: 32px; height: 32px; margin-left: -6px;
  display: grid; place-items: center;
  border: 0; background: transparent; border-radius: var(--r-pill);
  color: var(--ink); cursor: pointer;
}
.m-back:active { background: var(--paper-2); }
.m-back .ic { transform: rotate(180deg); }
.m-top-spacer { flex: 1; }
.mono { font-family: var(--f-mono); font-size: .86em; letter-spacing: 0; }
.m-iconbtn {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; background: transparent; border-radius: var(--r-pill);
  color: var(--ink-2); cursor: pointer;
}
.m-iconbtn:active { background: var(--paper-2); }

/* 顶栏里的搜索框 —— 让首屏少掉一整行（原来搜索框独占一行 + 品类条再一行） */
.m-topsearch {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 6px;
  height: 36px; padding: 0 12px;
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--sh-1);
}
.m-topsearch .ic { color: var(--ink-3); }
.m-topsearch input {
  flex: 1; min-width: 0; border: 0; background: transparent;
  font-size: 14px;
}
.m-topsearch input:focus { outline: none; }
.m-topsearch input::placeholder { color: var(--ink-3); }
/* 搜索框内的「撤销输入」小 ✕（派总 2026-09-30 第 1 条）：平时藏着，聚焦才出现 ——
   点击清空输入并退出搜索态；在搜索结果页上还会顺手剥掉 ?q=（逻辑在 base.html）。
   两个出现条件都给：is-searching 是 JS 挂的搜索态；:focus-within 兜住「autofocus
   先于脚本挂监听」的搜索页（那种时候类还没挂上但焦点确实在里面）。 */
.m-search-x {
  display: none; place-items: center;
  width: 22px; height: 22px; margin-right: -2px;
  border: 0; border-radius: var(--r-pill);
  background: var(--paper-2); color: var(--ink-2); cursor: pointer; flex-shrink: 0;
}
.m-search-x .ic { width: 12px; height: 12px; }
.m-search-x:active { background: var(--ink-3); color: #fff; }
/* 二轮⑥（派总 2026-10-12）：小青柠搜索框（data-no-search-expand）也要有左侧 ✕ ——
   出现条件统一改成「焦点在框内」，不再排除不伸展的搜索框。 */
.m-topsearch:focus-within .m-search-x,
.m-top-in.is-searching .m-topsearch .m-search-x { display: grid; }

/* T18 优化④（派总 2026-10-26）：横滑切板块的一层「防整屏被拖走」的壳。
   见 templates/m/base.html 里的注释：平移 .m-main 会把文档 scrollWidth 撑出去，
   浏览器就能横向滚整页，sticky 顶栏（一级标签）跟着横着跑。
   overflow-x: clip 只裁横向溢出、**不新建滚动容器** ⇒ main 里面二级/三级标签的
   sticky 行为一点没变（实测滚到 400 顶栏仍贴顶）。
   ⚠️ 不要用 hidden：hidden 会让这层变成纵向滚动容器，里面的 sticky 标签全部失效。 */
.m-pan { overflow-x: clip; }

.m-main {
  max-width: 720px; margin: 0 auto;
  padding: 10px 12px calc(var(--tab-h) + var(--safe-b) + 22px);
}
/* 首页上内边距归零：二级标签紧贴顶栏下沿（一级卡片下沿），三层之间不留空带 ——
   派总 2026-10-25 返工后二级也跟着内容滚，这里保持归零只为「静止时贴着顶栏」。 */
.m-main.is-home { padding-top: 0; }
.m-main.is-plain { padding-bottom: calc(var(--safe-b) + 22px); }
/* P 波⑦（派总 2026-10-19）：带固定底栏（.m-actions）的页面，主内容底部要让开
   底栏高度，不然最后一张卡（如订单页的「评价」占位卡）被压在底栏下面看不见。 */
.m-main.has-actions { padding-bottom: calc(76px + var(--safe-b) + 12px); }
/* 聊天页要自己占满整屏（内部再独立滚动），所以把外层内边距全归零 */
.m-main.is-flush { padding: 0; }

/* ——— 派总 2026-10-25 返工第 5 条（重点）首页下拉刷新 ———
   被往下拽的**只有这一块**：三级标签（最新/附近/…+ 定位）也在里面，跟着内容一起被拉；
   一级（顶栏）与二级（类型/圈子胶囊）纹丝不动 —— 顶部再也不跟着被扯。
   位移由 static/js/refresh.js 现算（transform: translateY(...)），样式只管长相。 */
.m-pullzone { will-change: transform; }
.m-refresh-hint {
  position: fixed; left: 0; right: 0; top: 0; height: 0; z-index: 30;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  overflow: hidden; pointer-events: none;
  font-size: 12px; font-weight: 700; color: var(--ink-3);
  background: transparent;
}
.m-refresh-hint .ic { width: 14px; height: 14px; }
.m-refresh-hint.is-spin .ic { animation: ymw-spin .9s linear infinite; }
@keyframes ymw-spin { to { transform: rotate(360deg); } }

/* 底部五格 tab：发现 / 消息 / 发布 / 定位 / 我的 */
.m-tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-nav);
  display: flex; align-items: stretch;
  padding-bottom: var(--safe-b);
  background: rgba(255, 255, 255, .95);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-top: 1px solid var(--line);
}
.m-tab {
  flex: 1; height: var(--tab-h);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--ink-3); font-size: 10.5px; font-weight: 700;
  position: relative;
}
.m-tab.on { color: var(--brand-deep); }
/* 「AI 管家柠柠」格（2026-10-26 升级）：顶替原「问一问」格，AI 动画图标 + 平台主色 */
/* T43b（派总 2026-10-29 改口「不要方框渐变」）：渐变只给「AI」图标描边和「柠柠」两字
   （图标走 _tabbar.html 内联 stroke="url(#ai-grad)"，文字用 background-clip:text），
   格子本身恢复普通导航格，不再有底色/胶囊。 */
.m-tab.m-tab-ai { color: var(--brand); }
.m-tab.m-tab-ai > span {
  background: linear-gradient(120deg, var(--brand) 10%, var(--gold) 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.m-tab.m-tab-ai .ic {
  animation: ai-pulse 2s ease-in-out infinite;
}
/* T44③（派总 2026-10-29「AI/柠柠 不显眼」）：该格字号与图标比其余四格大一档（10.5px→12.5px、22→26px）。 */
.m-tab.m-tab-ai { font-size: 12.5px; }
.m-tab.m-tab-ai .ic { width: 26px; height: 26px; }
@keyframes ai-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.7; transform: scale(1.08); }
}
.m-tab .ic { width: 22px; height: 22px; }
.m-tab .badge {
  position: absolute; top: 7px; left: 50%; margin-left: 4px;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--coral); color: #fff; font-size: 10px; font-weight: 900;
  display: grid; place-items: center; line-height: 1;
}
/* 「只有通知未读」那一态：同一枚角标缩成红点、不写数字。
   口径见 static/js/live.js 的 paintOne —— 数字只留给真人对话，其余只点红点。 */
.m-tab .badge.is-dot {
  min-width: 0; width: 9px; height: 9px; padding: 0; font-size: 0; top: 10px;
}
/* 派总 2026-10-27 第 7 条：底栏五格**左右平均分布**。实测两处不均：
   ① 「发布」是 `<button>`，而全站 reset（上面第 136 行）只继承了 font/color，
      没清 border/background/appearance ⇒ 它带着浏览器默认的 `2px outset` 灰边框 +
      #f0f0f0 底（截图里那一圈灰框），min-content 又把它撑到 91px，
      其余四格各 75px —— 中心间距变成 75 / 82 / 82 / 75，中间两格明显往中间挤；
   ② 原来还写死 flex:0 0 66px。
   修法：把按钮的 UA 样式清干净 + 五格一律 flex:1 1 0 等分（min-width:0 才允许等分），
   凸起的大圆钮靠自己的 .bubble 尺寸和负 margin 凸显，不靠抢宽度、不靠灰底框。 */
.m-tab-pub { flex: 1 1 0; min-width: 0; padding: 0; border: 0; background: none;
  appearance: none; -webkit-appearance: none; cursor: pointer; }
.m-tab-pub .bubble {
  width: 44px; height: 44px; margin-top: -14px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; display: grid; place-items: center;
  box-shadow: var(--sh-brand);
}
.m-tab-pub .bubble .ic { stroke-width: 2.6; width: 24px; height: 24px; }
.m-tab-pub .lbl { margin-top: 1px; }

/* ----------------------------------------------------------------------
   通用积木：卡 / 按钮 / 标签 / 价格 / 表单 / 空态
   ---------------------------------------------------------------------- */
.m-card {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: var(--sp-xl);
}
.m-card + .m-card { margin-top: 10px; }
.m-card-flat { background: var(--surface-2); box-shadow: none; }
/* 多人接单·候选比选（派总 2026-10-13）：一组候选圆梦者卡片的竖向堆叠容器。 */
.m-stack { display: flex; flex-direction: column; gap: 12px; }
.m-stack .m-card { margin-top: 0; }

.m-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-xs);
  min-height: var(--ctl-h); padding: 0 var(--sp-xl);
  border: 0; border-radius: var(--r-pill);
  background: var(--grad-brand); color: #fff;
  box-shadow: var(--sh-brand);
  font-size: var(--fs-6); font-weight: 700; letter-spacing: -.01em;
  cursor: pointer;
  transition: transform var(--dur-1) var(--ease), opacity var(--dur-2) var(--ease);
}
.m-btn:active { transform: scale(.98); }
.m-btn[disabled] { opacity: .45; pointer-events: none; }
.m-btn-block { width: 100%; }
/* L 波②（派总 2026-10-17 晚）：提交评价右侧并排「分享流水账」—— 两钮等宽一行 */
.m-btn-row { display: flex; gap: 8px; }
.m-btn-row .m-btn { flex: 1; }
.m-btn-lg { min-height: var(--ctl-h-lg); font-size: var(--fs-7); }
.m-btn-ghost { background: var(--surface-2); color: var(--ink); box-shadow: none; }
.m-btn-line { background: transparent; color: var(--brand-deep); box-shadow: inset 0 0 0 1.5px var(--brand); }
.m-btn-coral { background: linear-gradient(135deg, var(--coral), var(--coral-deep)); box-shadow: var(--sh-coral); }
.m-btn-slim { min-height: var(--ctl-h-sm); padding: 0 var(--sp-lg); font-size: var(--fs-4); }

.m-tag {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px var(--sp-sm); border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font-size: var(--fs-2); font-weight: 700; white-space: nowrap;
}
.m-tag-brand { background: var(--brand-soft); color: var(--brand-deep); }
.m-tag-coral { background: var(--coral-soft); color: var(--coral-deep); }
.m-tag-lime { background: var(--lime-soft); color: var(--lime-ink); }
.m-tag-gold { background: var(--gold-soft); color: var(--gold-ink); }
.m-tag-jade { background: var(--jade-soft); color: var(--jade); }
.m-tag-ok { background: var(--ok-soft); color: var(--ok); }
.m-tag-warn { background: var(--warn-soft); color: var(--warn); }
.m-tag-danger { background: var(--danger-soft); color: var(--danger); }
/* T30（派总 2026-10-28）：陪审员等级标签 —— 只有样式，没有任何物质/信用/积分加成。
   颜色只做区分，不是高低暗示：见习/合格/资深/首席。 */
.m-tag-lv { font-weight: 800; }
.m-tag-lv.lv-1 { background: var(--surface-2); color: var(--ink-2); }
.m-tag-lv.lv-2 { background: var(--jade-soft); color: var(--jade); }
.m-tag-lv.lv-3 { background: var(--brand-soft); color: var(--brand-deep); }
.m-tag-lv.lv-4 { background: var(--gold-soft); color: var(--gold-ink); }

.m-price { color: var(--coral); font-weight: 900; letter-spacing: -.02em; }
.m-price em { font-style: normal; font-size: .66em; margin-right: 1px; font-weight: 800; }
.m-price-lg { font-size: 26px; }
/* K 波⑨：「你来出价」—— 没有数字的价格态，深青 + 收窄，别跟 ¥ 数字一样大 */
.m-price-lg.is-quote { font-size: 19px; color: var(--brand-deep); letter-spacing: 0; }
.m-price-md { font-size: 19px; }
/* K 波⑨：「你来出价」中号价格态（我的需求列表同口径） */
.m-price-md.is-quote { font-size: 14px; color: var(--brand-deep); letter-spacing: 0; }
/* 订单页需求卡的价格（2026-10-05 派总第 1 条）：19px 的 2 倍 */
.m-price-xl { font-size: 38px; }
/* O 波①（派总 2026-10-18）：「你来出价/对方出价」四个汉字与价格数字同框时
   显得特别巨大（汉字是满格字形，数字只有半格高）—— 降到 27px，
   与 38px 数字的实际字高对齐，视觉上「统一大小」。 */
.m-price-xl.is-quote { font-size: 27px; letter-spacing: 0; }
/* 需求卡头部（2026-10-06 派总第 2 条）：缩略图占左，右列＝标题 +（状态/订单号两行 ‖ 大价格） */
.m-demhead { display: flex; align-items: flex-start; gap: 11px; margin-top: 10px; text-decoration: none; color: inherit; }
.m-demhead-r { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
.m-demhead .m-thumb { flex-shrink: 0; }
/* ⚠️ 2026-10-08 H 波①（派总：小屏上价格被挤到下一行，必须回到图片同一行右侧）。
   罪魁就是原本那句 `flex-wrap: wrap` —— 一放不下就把整个价格甩下去。
   正确做法是**让左侧那一列自己收缩**（min-width:0 + 溢出截断），价格永远贴右侧不落跑；
   真到极窄屏（≤360）再把价格字号降一档，而不是把它丢到下一行。 */
.m-ordhead { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: nowrap; }
.m-ordhead-l { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; flex: 1 1 auto; overflow: hidden; }
.m-ordhead-l > .m-status, .m-ordhead-l > .m-tag { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-ordhead .m-price-xl { flex: 0 0 auto; margin-left: auto; white-space: nowrap; }
@media (max-width: 360px) {
  .m-ordhead .m-price-xl { font-size: 27px; }
  .m-ordhead-l { gap: 3px; }
}
/* H 波②：验收的「满意确认 / 不满意申诉」两颗按钮并排，各占一半 */
.m-act2 { display: flex; align-items: stretch; gap: 10px; margin-bottom: 12px; }
.m-act2 > .m-btn { flex: 1 1 0; min-width: 0; padding-left: 4px; padding-right: 4px; }
/* H 波额外：发货卡里的「延期发货申请」（折叠起来的小工具，不抢主按钮的位置） */
.m-ext-req { margin-bottom: 10px; }
.m-ext-req > summary { cursor: pointer; }
.m-ext-req > summary::-webkit-details-marker { display: none; }
.m-ext-req > summary { list-style: none; }
/* 方案表单「新报价」/「附图」：标签和输入框同一行 + 元单位（2026-10-06/07 派总第 3 条） */
.m-price-field, .m-inline-field { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.m-price-field .m-label, .m-inline-field .m-label { flex-shrink: 0; margin: 0; }
.m-price-field .m-input, .m-inline-field .m-input { flex: 1; min-width: 0; }
.m-price-unit { color: var(--ink-2); font-weight: 800; font-size: 14.5px; flex-shrink: 0; }
.m-muted { color: var(--ink-3); }
.m-sub { color: var(--ink-2); font-size: 13px; }
.m-row { display: flex; align-items: center; gap: 8px; }
.m-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.m-wrap { flex-wrap: wrap; }
.m-grow { flex: 1; min-width: 0; }
.m-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-clamp2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.m-clamp3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.m-divider { height: 1px; background: var(--line); margin: 12px 0; }
.m-sec-title { font-size: 15px; font-weight: 900; margin: 16px 2px 8px; letter-spacing: -.02em; }
.m-sec-title:first-child { margin-top: 4px; }

/* 关注页「关注 | 发现」子标签（派总 2026-09-30） */
.m-subtabs { display: flex; gap: 8px; padding: 12px 12px 6px; }
.m-subtab {
  flex: 1; text-align: center; padding: 9px 0; border: 0; border-radius: 999px;
  font-weight: 800; font-size: 14px; background: var(--surface-2); color: var(--ink-3);
  cursor: pointer;
}
.m-subtab.on { background: var(--brand); color: #fff; }

/* 关注页两个子标签的内容容器（切换时靠 hidden 属性显隐，无需额外布局） */
.m-fview { display: block; }

/* 表单 */
.m-field { margin-bottom: 12px; }
.m-label { display: block; font-size: var(--fs-3); font-weight: 800; color: var(--ink-2); margin: 0 0 var(--sp-xs) 2px; }
.m-input, .m-textarea, .m-select {
  width: 100%; padding: var(--sp-lg) var(--sp-xl);
  border: 1.5px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--surface); font-size: var(--fs-6);
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
  appearance: none; -webkit-appearance: none;
}
.m-textarea { min-height: 108px; resize: vertical; line-height: 1.65; }
.m-input:focus, .m-textarea:focus, .m-select:focus {
  outline: none; border-color: var(--brand); box-shadow: var(--ring);
}
/* N 波⑪（派总 2026-10-18，第三轮修）：date/time 控件在 iOS 上的内部 shadow 节点
   不按 padding 撑高 —— 延期申请里的日期框被压成一条细线（M 波换纯 date 也没解决，
   因为那时只换了类型、没管高度）。显式给高度，与其他 .m-input 视觉齐平。 */
.m-input[type="date"], .m-input[type="time"] { height: 46px; line-height: 22px; }
/* 图形验证码那张图（注册页 + 两处找回密码共用 templates/m/_captcha_row.html）。
   模板里已写死 width/height 属性，这里只管「怎么塞进那一行」：不被 flex 压扁、
   不变形、点一下能换一张（js 绑在 #capImg 上）。与网页版 .cap-img 同一套视觉口径。 */
.m-cap-img {
  flex: 0 0 108px; height: var(--ctl-h); object-fit: cover;
  border: 1.5px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--surface); cursor: pointer;
}
.m-select {
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
                    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
.m-hint { font-size: var(--fs-2); color: var(--ink-3); margin: var(--sp-xs) 2px 0; line-height: 1.6; }
.m-err {
  background: var(--danger-soft); color: var(--danger);
  padding: 10px 12px; border-radius: var(--r-sm);
  font-size: 13px; font-weight: 600; margin-bottom: 12px;
}
/* --- 发布草稿（「填到一半走人，下次接着填」）---
   提示条只在真的存着草稿时出现，且默认**只提示不铺开** ——
   点「继续填写」才把内容铺进表单并翻到上次那一步。
   用青绿不用警告色：这不是出错，是「我们替你留着了」这句好消息。 */
.m-draftbar {
  display: flex; align-items: center; gap: 10px;
  background: var(--brand-tint); border-radius: var(--r);
  padding: 12px 14px; margin-bottom: 12px; box-shadow: var(--sh-1);
  color: var(--brand-deep);
}
.m-draftbar.is-resuming { background: var(--brand-soft); }
.m-draftbar .ic { flex-shrink: 0; }
.m-draftbar b { display: block; color: var(--ink); font-size: 14px; }
.m-draftbar .m-sub { display: block; margin-top: 2px; }
.m-draftbar form { margin: 0; flex-shrink: 0; }
.m-draftbar .m-btn { flex-shrink: 0; }
/* 「草稿已自动保存 · 12:03:44」—— 没内容时整行不占位（会有个空行把页面撑高） */
.m-draftnote { color: var(--ink-3); font-size: 12px; margin: 0 0 10px; }
.m-draftnote:empty { display: none; }
/* L 波①（派总 2026-10-17 晚）：五角星评价。纯 CSS 打星，没有 JS 也不坏 ——
   一行里 DOM 顺序 5→1，row-reverse 反转成视觉 1→5；
   `input:checked ~ label` 把「选中的那颗及其以下」全部点亮（兄弟选择器只向后看，
   正好配合反转实现「点亮到这颗为止」）。 */
.m-star-row { display: inline-flex; flex-direction: row-reverse; gap: 4px; }
.m-star-row input { position: absolute; opacity: 0; pointer-events: none; }
.m-star-row label {
  font-size: 28px; line-height: 1.15; color: var(--line-2);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.m-star-row input:checked ~ label { color: #f7b500; }
.m-radio-row span {
  display: block; text-align: center; padding: 10px 6px;
  border-radius: var(--r-sm); background: var(--surface-2);
  font-size: 13.5px; font-weight: 700; color: var(--ink-2);
  border: 1.5px solid transparent;
}
.m-radio-row input:checked + span {
  background: var(--brand-tint); color: var(--brand-deep); border-color: var(--brand);
}
.m-check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink-2); }

/* T29①（派总 2026-10-28「全站的定位功能全部下架」）：原来的「定位条」m-locate
   （告诉用户现在按哪座城在看 + 给他一次改的机会）连同 `m/locate.html` 一起撤下。 */

/* 空态 */
.m-empty { text-align: center; padding: 46px 20px; color: var(--ink-3); }
.m-empty .ic { margin: 0 auto 12px; color: var(--ink-4); width: 40px; height: 40px; stroke-width: 1.6; }
.m-empty b { display: block; color: var(--ink-2); font-size: 15px; margin-bottom: 4px; }
.m-empty .m-btn { margin-top: 16px; }

/* 提示条 */
/* ⚠️ `top` 必须把顶栏高度算进去（+ var(--top-h)）：
   原来只加 safe-t，浮层就整体盖在 .m-top（z-index 40）上面 ——
   于是「发布成功」那条提示正好压住右上角的 ×，用户点 × 点到的却是提示，
   所有顶栏有按钮的页面在提示消失前都点不动。而且它**不报任何错**，
   只表现为「按钮看得见、按不下去」（2026-09-22 被验收脚本撞出来）。 */
.flash-stack { position: fixed; left: 0; right: 0; top: calc(var(--safe-t) + var(--top-h) + 6px); z-index: var(--z-pop); padding: 0 var(--sp-lg); display: grid; gap: 6px; max-width: 720px; margin: 0 auto; }
.flash {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface); box-shadow: var(--sh-2);
  font-size: 13.5px; font-weight: 600; animation: mDrop .28s var(--ease-out);
}
.flash .x { margin-left: auto; border: 0; background: transparent; color: var(--ink-3); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 2px; }
.flash.success { color: var(--ok); }
.flash.error { color: var(--danger); }
.flash.info, .flash.warning { color: var(--warn); }
@keyframes mDrop { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* ----------------------------------------------------------------------
   瀑布流 + 需求卡片（图片优先，闲鱼口径）
   ---------------------------------------------------------------------- */
/* 错落瀑布流用「两个纵向栏」实现（分配由 ymw_ui.masonry 完成）。
   为什么不用 CSS column-count：它按「先填满第一栏再填第二栏」排，
   于是左栏是第一页、右栏是第二页，浏览顺序完全错乱。 */
.m-feed { display: flex; gap: 8px; align-items: flex-start; }
.m-feed-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.m-feed-1 { display: grid; grid-template-columns: 1fr; }

.m-dc {
  position: relative;
  background: var(--surface); border-radius: var(--r-sm);
  box-shadow: var(--sh-1); overflow: hidden;
}
/* 整卡可点的那一层铺在最底下，收藏按钮浮在它上面（z-index 更高）。
   不把 <button> 塞进 <a> 里 —— 那是无效 HTML，各家浏览器的点击行为不一致。 */
.m-dc-link { position: absolute; inset: 0; z-index: 1; }
/* N 波③（派总 2026-10-18）：收藏星从右上角挪进发布者行（DOM 也搬进去了）——
   绝对定位取消，改 margin-left:auto 推到行尾；relative + z-index 保住
   「浮在整卡可点层之上」（.m-dc-link 是 absolute inset:0，会把行内元素盖住）。 */
.m-dc-fav-form { position: relative; z-index: 2; margin: 0 0 0 auto; flex-shrink: 0; }
.m-dc:active { transform: scale(.988); }

/* 图片区：**按画幅预留高度**。不留的话图片一张张加载完会把下面内容不断往下顶，
   滑列表时页面一直在跳 —— 这是「毛坯感」最典型的来源之一。
   画幅标记写在文件名里（-p 竖图 / -s 方图），由 ymw_ui.cover_ratio 读出来。 */
/* 派总 2026-10-27 第 4 条：小青柠列表图**完全照小圈子**（.pc-card-media img 那条）。
   原来画幅从素材文件名尾缀读（-p → 800/1116=0.717、-s → 800/744=1.075），
   公网实测同一屏里两种高度混排，竖图那条明显比圈子卡高出一截、
   方图那条又矮成一条，看着就是「图顶着上面、下面空一块」。
   圈子卡是**恒定 3:4 + cover 居中裁切**，所以两列排面齐平 —— 统一到这里。
   （模板仍然输出 r-p / r-s 这两个尾缀 class，但样式表不再据它改画幅：
     画幅由图片自己的 object-fit 表达，见下面 .m-detail-media。） */
.m-dc-media {
  position: relative; display: block;
  background: var(--surface-2);
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
.m-dc-media.r-s { aspect-ratio: 3 / 4; }
.m-dc-media img {
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  display: block; background: var(--surface-2);
}

/* 没图的品类：用「分类插画牌」兜底，而不是甩一张裂图。
   插画牌也按同样比例占位，所以有图没图的卡片能混在一条瀑布流里。 */
.m-dc-cover {
  position: relative; display: grid; place-items: center;
  aspect-ratio: 3 / 4;
  background: linear-gradient(150deg, var(--brand-tint), var(--brand-soft));
  color: var(--brand-deep);
}
.m-dc-cover.r-s { aspect-ratio: 3 / 4; }
.m-dc:nth-child(3n+2) .m-dc-cover { background: linear-gradient(150deg, var(--coral-soft), #ffe0d5); color: var(--coral-deep); }
.m-dc:nth-child(3n+3) .m-dc-cover { background: linear-gradient(150deg, var(--lime-soft), #f6fdd8); color: var(--lime-ink); }
.m-dc-cover b { font-size: 12.5px; font-weight: 800; margin-top: 4px; }
.m-dc-cover .stack { display: grid; justify-items: center; }
.m-dc-cover .ic { width: 30px; height: 30px; stroke-width: 1.7; }

/* 压在图片上的角标：照片底色不可控，所以角标要自带底色才读得清 */
.m-dc-badge { position: absolute; top: 6px; left: 6px; z-index: 2; }
.m-badge-float {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 8px; border-radius: var(--r-pill);
  font-size: 10.5px; font-weight: 800; color: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}
.m-badge-hot { background: rgba(255, 106, 69, .95); }
.m-badge-promo { background: rgba(16, 60, 55, .88); }
.m-badge-soft { background: rgba(0, 0, 0, .42); }
/* 「我发布的」—— 用品牌青绿，和推广（深墨绿）/ 急着要（珊瑚）区分开。 */
.m-badge-own { background: rgba(0, 189, 166, .95); }

/* T18①（派总 2026-10-25）：这颗右下角的钮从小圈子的「收藏星」变成「点赞爱心 + 次数」，
   里面多了一个数字 ⇒ 由定宽圆钮改成「至少 28px 的胶囊」（图标单飞时 padding 6.5px
   正好还是 28×28 那颗，需求卡的外观一点没变）。颜色/发光沿用下方皮肤覆盖块，不动。 */
.m-dc-fav {
  min-width: 28px; height: 28px; padding: 0 6.5px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .92);
  color: var(--ink-3);
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
  border: 0; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
}
.m-dc-fav .ic { width: 15px; height: 15px; flex: none; }
/* 点赞次数：跟详情页底部条那个数字同字号，数字用等宽数位（跳数时不抖行宽） */
.m-dc-n { font-size: 11.5px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.m-dc-fav.on { color: var(--coral); }
.m-dc-fav.on .ic { fill: currentColor; }

.m-dc-body { padding: var(--sp-sm) var(--sp-md) var(--sp-md); }
.m-dc-title {
  font-size: 13.5px; font-weight: 600; line-height: 1.42;
  letter-spacing: -.01em; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.m-dc-why { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.m-dc-why .m-tag { font-size: 10px; padding: 1px 6px; }
.m-dc-foot {
  display: flex; align-items: center; gap: 5px;
  margin-top: 6px;
}
/* T16f-5（派总 2026-10-22）：价格行整体重排 ——
   价格加大一号；发布地址仍在同行最右（.m-dc-meta margin-left:auto 不动）。
   T16f-5b（派总 2026-10-22 追加）：价格再加大一号（22→24）；
   「可议/一口价」挪到价格后面同排（.m-dc-price-row 内 baseline 对齐）；
   「N人在聊」单独落价格下方一行（.m-dc-price-side 纵向列）。 */
.m-dc-price { font-size: 24px; color: var(--coral); font-weight: 900; letter-spacing: -.03em;
  display: inline-flex; align-items: baseline; }
.m-dc-price em { font-style: normal; font-size: .62em; margin-right: 1px; }
.m-dc-price-num { display: inline-flex; align-items: baseline; gap: 4px; }
/* 价格列（foot 里第一个元素）：第一行 价格+议价小标，第二行 N人在聊 */
.m-dc-price-side { display: flex; flex-direction: column; align-items: flex-start;
  gap: 4px; }
.m-dc-price-row { display: inline-flex; align-items: baseline; gap: 5px; }
/* 「N 人在聊」：报价数字后方的活跃度小徽章（N 波⑤从发布者行挪来） */
.m-dc-live { font-style: normal; font-size: 10px; font-weight: 700; color: var(--coral);
  background: rgba(255, 106, 69, .1); border-radius: var(--r-pill);
  padding: 1px 6px; white-space: nowrap; }
.m-dc-price-side .neg { font-size: 11px; font-weight: 700; color: var(--ink-3);
  letter-spacing: 0; }
/* K 波⑨（派总 2026-10-17）：「你来出价」—— 没有数字的一种价格态。
   用品牌深青（不是珊瑚红）：它不是一个「便宜的价」，是「价还没定」，
   颜色跟 ¥0 混同会让人以为这是个免费单。 */
/* T16g-0（派总 2026-10-23）：「你来出价」四个字 900 字重视觉块面比数字价格大，
   降到 17px 并把行高撑出底部呼吸 —— 否则字面底缘紧贴下方「N人在聊」，
   看起来比数字价格与标签的间距小一截。 */
.m-dc-price.is-quote { font-size: 17px; line-height: 1.35; color: var(--brand-deep); letter-spacing: 0; }
.m-dc-meta { font-size: 10.5px; color: var(--ink-3); margin-left: auto; text-align: right; line-height: 1.4; }
/* 「离我多远」—— 只有定位页会挂上这个数，别的列表页不显示（没有就没有，不编） */
.m-dc-dist {
  font-size: 10px; font-weight: 800; color: var(--brand-deep);
  background: var(--brand-soft); border-radius: var(--r-pill);
  padding: 1px 6px; white-space: nowrap;
}

/* 卡片底部的「谁在求」—— 有头像、有昵称，名单才有「人」的感觉 */
.m-dc-by {
  display: flex; align-items: center; gap: 5px;
  margin-top: 7px;
  font-size: 10.5px; color: var(--ink-3);
}
.m-dc-by .av {
  width: 17px; height: 17px; border-radius: var(--r-pill);
  object-fit: cover; flex-shrink: 0;
  background: var(--brand-soft); color: var(--brand-deep);
  /* 同时服务两种形态：有头像时是 <img>，没有时是装首字的 <span>。
     写在一起是为了两者永远一样大、一样圆 —— 混排时不会一高一低。 */
  display: grid; place-items: center;
  font-size: 10px; font-weight: 900; line-height: 1;
  overflow: hidden;
}
.m-dc-by .nm { color: var(--ink-2); font-weight: 600; max-width: 5.5em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* N 波⑥（派总 2026-10-18）：「信用好」小徽章 —— 发布者名字右侧，
   信用分 ≥ CREDIT_GOOD_MIN 才显示。品牌青绿（信任色，不用珊瑚红那种警示色）。 */
.m-dc-credit {
  flex-shrink: 0;
  font-size: 10px; font-weight: 800; color: var(--brand-deep);
  background: var(--brand-soft); border-radius: var(--r-pill);
  padding: 1px 6px; line-height: 1.5;
}
/* 「N 人在聊」已挪到价格区（N 波⑤），发布者行不再显示 */

/* ----------------------------------------------------------------------
   头像（真图 / 首字兜底）
   ---------------------------------------------------------------------- */
.m-avatar {
  width: 42px; height: 42px; border-radius: var(--r-pill); flex-shrink: 0;
  display: grid; place-items: center; font-weight: 900; font-size: 15px;
  background: var(--brand-soft); color: var(--brand-deep);
  overflow: hidden;
}
.m-avatar img { width: 100%; height: 100%; object-fit: cover; }

/* ----------------------------------------------------------------------
   分类横滑条
   ---------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
   需求详情
   ---------------------------------------------------------------------- */
/* 详情页头图：一张真图顶十行字。没有它的详情页一眼就是「表单」。
   派总 2026-10-27 第 4 条：这块**完全照小圈子详情页的图集**（.pc-gal-slide）——
   窗口恒定 1:1.3、图上下左右居中；竖图由 app.js 的 initGalleryFit 补 .is-tall
   → contain 完整装进来（左右留白，不裁），横图 cover 填满。
   原来这里还有一条 `.m-detail-media.r-p { aspect-ratio: 5 / 7.8 }`（竖图素材整块拉高），
   公网实测 366×571 = 68% 屏高，圈子图集是 366×476 = 56% —— 派总说的「详情页图片显示过高」
   就是这一条；画幅改由 object-fit 表达，外框不许再跟文件名尾缀走。 */
.m-detail-media {
  position: relative; margin-bottom: 10px;
  border-radius: var(--r-lg); overflow: hidden;
  background: var(--surface-2);
  aspect-ratio: 1 / 1.3;
}
.m-detail-media img { width: 100%; height: 100%; object-fit: cover; object-position: center; cursor: zoom-in; }
.m-detail-media img.is-tall { object-fit: contain; }   /* 竖图不裁切，和 .pc-gal-slide 同一条口径 */
.m-detail-media .m-dc-badge { top: 10px; left: 10px; }
.m-detail-media .shade {
  position: absolute; left: 0; right: 0; bottom: 0; height: 42%;
  background: linear-gradient(to top, rgba(0, 0, 0, .34), transparent);
  pointer-events: none;
}
.m-detail-media .on-shot {
  position: absolute; left: 12px; bottom: 11px; right: 12px;
  color: #fff; font-size: 12px; font-weight: 700;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .4);
}
.m-detail-media .on-shot .ic { width: 13px; height: 13px; vertical-align: -2px; }

/* 收藏星（Z8② 派总 2026-10-16）：从图片右上角移进需求详情底栏，
   坐「聊一聊」和「分享」中间；沿用 Z6 全站统一口径 —— 无圆底/毛玻璃，
   绿线白星、已收藏红色实心（颜色规则在文件末尾 Z6 统一块）。
   （旧版 position:absolute + 深色玻璃圆底是压图样式，进底栏后是杂色，连根拆。） */
.m-media-fav-form {
  position: static; margin: 0; display: inline-flex; align-items: center;
  width: auto; height: auto; border-radius: 0;
  background: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  color: inherit; text-decoration: none;
}
.m-media-fav { display: inline-flex; align-items: center; gap: 3px; padding: 4px 2px; border: 0; background: none; cursor: pointer; }
.m-media-fav .ic { width: 20px; height: 20px; }
/* Z9⑦：收藏星右侧的被收藏次数 —— 与帖子底栏点赞次数同一张脸（裸数字 12.5px 加粗） */
.m-fav-n { font-size: 12.5px; font-weight: 800; color: var(--ink-2); }
.m-media-fav.on { color: var(--coral); }   /* L 波⑤ / Z6②：已收藏 = 红色实心 */
.m-media-fav.on .ic { fill: currentColor; }
/* 状态行里的发布者名字：可点进 TA 主页，颜色跟随状态胶囊不变 */
.m-status-by { color: inherit; text-decoration: none; font-weight: 800; }

.m-hero {
  background: var(--surface); border-radius: var(--r-lg);
  box-shadow: var(--sh-1); padding: 15px 15px 14px;
}
.m-hero-price { display: flex; align-items: baseline; gap: 8px; margin: 9px 0 11px; }
.m-params { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border-radius: var(--r-sm); overflow: hidden; margin-top: 12px; }
.m-params div { background: var(--surface); padding: 10px 12px; }
.m-params dt { font-size: 11px; color: var(--ink-3); font-weight: 700; margin-bottom: 2px; }
.m-params dd { margin: 0; font-size: 13.5px; font-weight: 700; }
.m-params dd .m-dd-sub { display: block; font-size: 11px; font-weight: 600; color: var(--ink-3); margin-top: 2px; }
.m-params dd .m-dd-strong { font-size: 15px; font-weight: 700; color: var(--ink); }
.m-params dd .m-dd-strong + .m-dd-sub { margin-top: 1px; }
.m-secures { display: grid; gap: 8px; }
.m-secure {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 11px 12px; border-radius: var(--r-sm); background: var(--surface-2);
}
.m-secure .ic { color: var(--jade); margin-top: 1px; }
.m-secure b { display: block; font-size: 13px; font-weight: 800; }
.m-secure span { font-size: 11.5px; color: var(--ink-2); line-height: 1.6; }

/* 需求方名片（详情页） */
.m-user-card {
  display: flex; gap: 11px; align-items: center;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: var(--sp-lg) var(--sp-xl);
}
.m-user-card .nm { font-size: 15px; font-weight: 800; letter-spacing: -.01em; }

/* 底部固定操作条 */
.m-actions {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px calc(10px + var(--safe-b));
  background: rgba(255, 255, 255, .96);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
/* 第七波②：min-width:fit-content + nowrap —— 第六波底栏重排后单行最多 5 个元素，
   纯 flex:1 均分会把「聊一聊」挤到 70px 导致文字换行；保内容最小宽、不许折行。 */
.m-actions > .m-btn { flex: 1; min-width: fit-content; white-space: nowrap; }

/* 底栏里的「轻动作」图标（留言 / 分享）：竖排图标 + 小字，比按钮矮一截、
   不抢面积 —— 一眼能看出它俩和右边「编辑 / 下架」不是同一类操作。 */
.m-act-icon {
  position: relative; flex-shrink: 0;
  display: grid; gap: 2px; justify-items: center;
  min-width: 44px; padding: 4px 2px;
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-2); font-size: 11px; font-weight: 700;
}
.m-act-icon:active { background: var(--paper-2); border-radius: var(--r-sm); }
.m-act-icon .ic { width: 21px; height: 21px; }
.m-act-dot {
  /* 派总 2026-10-21 第 1 条：角标不能压住图标本体 —— 挂到图标**外**右上角
     （微信风：数字胶囊圆心大约落在图标右上角顶点上）。 */
  position: absolute; top: -6px; right: -9px;
  min-width: 15px; height: 15px; padding: 0 4px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: var(--coral); color: #fff;
  font-size: 10px; font-weight: 800; font-style: normal;
}
/* 派总 2026-10-20 优化：聊一聊角标只显示红点、不显示数字（已有未读/有人聊时） */
.m-act-dot.is-dot {
  min-width: 0; width: 9px; height: 9px; padding: 0; font-size: 0;
}

/* ----------------------------------------------------------------------
   聊天
   ---------------------------------------------------------------------- */
/* T28（派总 2026-10-28「整个内容页比窗口大」）：高度要把顶栏那条 1px 下边框一起扣掉。
   实测（390×844）：顶栏占位 53（52 + 1px 边框），原来这里只减 52 ⇒ 整页 845 对可视 844，
   文档比窗口高 1px，手指一划整页被顶上去动一下 —— 加上下面的横向那处，就是「内容页超出窗口」。 */
.m-chat { display: flex; flex-direction: column; height: calc(100svh - var(--top-h) - var(--top-line) - var(--safe-t)); }
/* T27①（派总 2026-10-27「聊天窗口左右不该能推动」）：这里**必须显式写 overflow-x**。
   CSS 有一条不出错的规矩：一个轴是 visible、另一个轴不是时，visible 那个会被**算成 auto**
   —— 原来只写了 `overflow-y: auto`，于是 overflow-x 的实际值是 auto，
   聊天容器自己变成一个**横向滚动容器**：气泡里一条长链接/长编号把这一行撑到 1228px
   （实测见下 `.m-msg .bubble` 那条注释），手指斜着划就能把整页聊天左右推着走
   —— 派总看到的「整个页面在聊天框里可以移动」就是这个。
   hidden 只裁横向、纵向照旧滚；overscroll-behavior: contain 让滑到顶/底不再把滚动链交给页面
   （页面那头还有 refresh.js 的下拉手势，交给它就是把历史整页刷掉，见 T27②）。 */
.m-chat-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain; padding: 12px 14px; -webkit-overflow-scrolling: touch; }

/* T29④（派总 2026-10-28「柠柠对话窗口右上角删归档、加搜索，能搜索定位所有对话内容」）
   搜索定位条开在 .m-chat 的**正常流**里：顶栏下面、历史上面，收起时 hidden 一点不占位。
   ⚠️ 为什么不学浮层那样 position:fixed/bottom：输入框那一摞有两层多高（≈108px + 安全区），
      写死 bottom 一定压住快捷菜单和输入框 —— T26④ 就是这么翻车的。
      放在流里，flex 自己算：这条长多高，.m-chat-scroll 就短多高，谁也压不到谁。 */
.m-findbar { display: flex; align-items: center; gap: 6px; flex: none;
  padding: 6px 10px; background: var(--paper-2); border-bottom: 1px solid var(--line); }
.m-findbar[hidden] { display: none; }  /* display:flex 会盖掉 hidden 的默认值，必须写回来 */
.m-find-input { flex: 1; min-width: 0; height: var(--ctl-h-sm); padding: 0 var(--sp-lg);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--paper); color: var(--ink); font-size: var(--fs-4); }
.m-find-count { font-size: var(--fs-2); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.m-findbtn { width: var(--ctl-h-sm); height: var(--ctl-h-sm); display: grid; place-items: center;
  border: 0; background: transparent; border-radius: var(--r-pill);
  color: var(--ink-2); cursor: pointer; }
.m-findbtn:active { background: var(--paper); }
#findPrev svg { transform: rotate(180deg); }  /* 同一份精灵，朝上就转一下，不再造第二个图标 */
/* 命中：整行轻底；当前这一处：品牌色 + 描边（量得到，不靠 class 名自证） */
.m-msg.m-find-hit { background: var(--paper-2); border-radius: var(--r-sm); }
.m-msg.is-cur { background: var(--brand-soft); outline: 2px solid var(--brand); outline-offset: 2px; }
/* 从消息板块的搜索结果跳进来（?hi=）：亮一下再淡出，见 static/js/app.js 的 ymwLocateFromUrl */
.m-msg.m-hilite { background: var(--brand-soft); border-radius: var(--r-sm); transition: background .4s; }
/* 搜索结果页里命中的那几个字（kwmark 过滤器裹出来的 <mark>，见 core/templatetags/ymw_ui.py）。
   浏览器默认的 mark 是荧光黄配黑字，跟这套版式不搭；改用「上新」那一组金色。 */
mark.m-kw { background: var(--gold-soft); color: inherit; font-weight: 700;
  border-radius: 3px; padding: 0 1px; }
.m-chat-compose {
  position: relative; /* 表情面板 absolute 以它为锚 */
  flex-shrink: 0; display: flex; align-items: flex-end; gap: 8px;
  padding: 8px 12px calc(8px + var(--safe-b));
  background: var(--surface); border-top: 1px solid var(--line);
}
/* 派总 2026-10-14 晚第 1 条：聊天输入框的「+」号按钮（视觉同表情按钮一排） */
.m-chat-plus { flex: 0 0 auto; border: 0; background: none; padding: 6px 2px;
  color: var(--ink-2); cursor: pointer; }
.m-chat-plus .ic { width: 22px; height: 22px; }
/* Z6⑦（派总 2026-10-15）：emoji 与「+」做成同一个方框（34×34）、整体放大 1.2 倍
   （emoji 20→24px，加号图标 22→26px），两者底边对齐输入框，不再一高一矮。 */
.m-chat-compose .pcp-emoji-btn,
.m-chat-compose .m-chat-plus,
.m-chat-compose .m-chat-loc {
  flex: 0 0 auto; width: 34px; height: 34px; padding: 0; margin-bottom: 3px;
  display: grid; place-items: center; align-self: flex-end;
  border: 0; background: none; cursor: pointer;
}
.m-chat-compose .pcp-emoji-btn { font-size: 24px; line-height: 1; }
.m-chat-compose .m-chat-plus { color: var(--ink-2); }
.m-chat-compose .m-chat-plus .ic { width: 26px; height: 26px; }
/* T29②-2（派总 2026-10-29）：输入框右侧「发送定位」。四颗钮（定位/表情/+/发送）
   在 360px 宽的机器上要占掉 ~166px，所以这颗按 24px 图标画，不再放大 ——
   再大就会把输入框挤成一行的三分之一。 */
.m-chat-compose .m-chat-loc { color: var(--ink-2); }
.m-chat-compose .m-chat-loc .ic { width: 24px; height: 24px; color: var(--brand-deep); }
.m-chat-compose .m-chat-loc[disabled] { opacity: .4; }
/* 「+」面板宫格：图片 / 拍摄 / 收藏 / 需求单 / 圈子 */
.plus-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 6px; }
.plus-item { display: flex; flex-direction: column; align-items: center; gap: 6px;
  border: 0; background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-xl) 0;
  color: var(--ink-2); cursor: pointer; }
.plus-item .ic { width: 22px; height: 22px; color: var(--brand-deep); }
.plus-item b { font-size: 11.5px; font-weight: 700; }
.plus-item:active { background: var(--line, #ececec); }
.plus-tabs { display: flex; gap: 8px; margin-top: 10px; }
.plus-tabs button { border: 1px solid var(--line-2); background: var(--surface);
  border-radius: var(--r-pill); padding: 6px 16px; font-size: 12.5px; font-weight: 700;
  color: var(--ink-2); cursor: pointer; }
.plus-tabs button.on { background: var(--jade); border-color: var(--jade); color: #fff; }
.m-chat-input {
  flex: 1; min-height: 40px; max-height: 110px; resize: none;
  padding: 10px 13px; border-radius: var(--r); border: 1.5px solid var(--line-2);
  background: var(--surface-2); font-size: 15px; line-height: 1.5;
}
.m-chat-input:focus { outline: none; border-color: var(--brand); background: var(--surface); }
.m-chat-send { width: 40px; height: 40px; border-radius: var(--r-pill); border: 0; background: var(--brand); color: #fff; display: grid; place-items: center; cursor: pointer; }
.m-chat-send[disabled] { opacity: .4; }
/* T28（派总 2026-10-28「柠柠聊着聊着，整个内容页超出窗口」）：列宽必须写 `minmax(0,1fr)`。
   原来这里只写 `display:grid`，那一列是 **auto** 轨 —— auto 轨按「成员的最大内容宽度」长，
   而 `.m-msg` 上那句 `max-width:100%` **拦不住它**：轨道本身还没定宽时，百分比按 auto 处理
   （CSS Grid 求内在轨道尺寸时对百分比的规定），于是「100%」等于没说。
   实测（390 视口、公网，闸门 `scripts/verify_t28_chat_overflow.js` 的 R1 反向验就是复现这一条）：
   柠柠一回**六列表格**（表头 `th` 写了
   `white-space:nowrap`）整行就被撑到 468px，再来一张**长标题卡片**（`.m-ning-cards` 的
   `width:min(340px,100%)` 同样吃这个亏）撑到 488px；而且这是**轨道**宽，不是那一行宽 ——
   后面每条消息（哪怕是一句正常换行的短话）都被拉到同一宽度，
   这就是「聊着聊着才溢出、越聊越多越回不去」的来历。
   `minmax(0,1fr)` 把轨钉成「容器宽、下限 0」：轨道不再跟着内容长，
   表格交回它自己的 `.m-ning-table{overflow-x:auto}` 横滚，卡片交回 `min(340px,100%)` 里那个 100%
   （轨道定宽后这个百分比才真的算得出数）。三个聊天面（1-1 / 柠柠 / 订单沟通区）共用这一份。 */
.m-bubbles { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.m-msg { display: flex; gap: 8px; align-items: flex-start; max-width: 100%; }
.m-msg .who {
  width: 32px; height: 32px; border-radius: var(--r-pill); flex-shrink: 0;
  display: grid; place-items: center; font-size: 12px; font-weight: 900;
  background: var(--brand-soft); color: var(--brand-deep);
  overflow: hidden;
}
/* Z6⑭（派总 2026-10-15）：头像从 span 换成 a（点它进 TA 主页）——
   链接默认的下划线和蓝色要盖掉，否则头像圈里那块底色会露出蓝字。 */
.m-msg a.who { text-decoration: none; }
.m-msg .who img { width: 100%; height: 100%; object-fit: cover; }
.m-msg .bubble {
  max-width: 74%; padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--surface); box-shadow: var(--sh-1);
  /* T27①：`word-break: break-word` 在有 `white-space: pre-wrap` 时**不保证**折断
     「一长串不换行的 token」（订单号、网址、验证码）。实测（390px 视口、本地 8013，
     scripts/probe_t27_gesture.js 造的那条 200 字符 URL）：一行被撑到 **1228px**，
     聊天容器 scrollWidth 1499 对可视 390 ⇒ 可横推 **1109px**。
     `overflow-wrap: anywhere` 才是「装不下就硬折」的那一条，也是小屏幕唯一安全的选择
     （再叠上上面 .m-chat-scroll 的 overflow-x:hidden 双保险，改后实测可横推 0px）。 */
  font-size: 14.5px; line-height: 1.6; word-break: break-word; overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.m-msg .t { font-size: 10.5px; color: var(--ink-3); align-self: flex-end; }
.m-msg.me { flex-direction: row-reverse; }
.m-msg.me .bubble { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.m-msg.me .who { background: var(--brand); color: #fff; }
/* Z 波后续（派总 2026-10-17 反馈⑨）：引用块移到气泡下方独立显示 + 点它定位原消息 */
.m-msg-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto; max-width: 100%; }
.m-msg:not(.me) .m-msg-body { align-items: flex-start; }
.m-msg.me .m-msg-body { align-items: flex-end; }
.m-quote-below { max-width: 74%; margin: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.m-quote-below:active { opacity: .65; }
.m-msg.m-flash .m-msg-body { box-shadow: 0 0 0 2px var(--brand); border-radius: 14px; transition: box-shadow .2s; }
/* Z6③（派总 2026-10-15）：气泡加一个指向说话人的小尖尖 —— 微信式。
   对方的尖角在气泡左侧、我的在右侧；三角用 border 画，颜色跟着气泡底色走。 */
.m-msg .bubble { position: relative; }
.m-msg .bubble::before {
  content: ''; position: absolute; top: 13px; left: -5px;
  border-style: solid; border-width: 5px 5px 5px 0;
  border-color: transparent var(--surface) transparent transparent;
}
.m-msg.me .bubble::before {
  left: auto; right: -5px;
  border-width: 5px 0 5px 5px;
  border-color: transparent transparent transparent var(--brand);
}
/* 派总 2026-10-14 晚第 4 条：苹果手机长按消息/图片会弹**系统**的放大预览和
   「共享 / 保存到照片 / 拷贝」菜单 —— 那是 iOS 的默认行为，会和站内自己的
   长按菜单叠罗汉。全消息区禁用系统 callout / 划词 / 拖拽，长按只认站内菜单。 */
.m-msg, .m-msg .m-chat-img, .m-msg .bubble {
  -webkit-touch-callout: none;
  -webkit-user-select: none; user-select: none;
  -webkit-user-drag: none;
}
.m-msg .m-chat-img { pointer-events: auto; }
.m-msg.is-pending .bubble { opacity: .6; }
.m-msg-state { font-size: 10px; color: var(--ink-3); align-self: flex-end; }
.m-daysep { text-align: center; font-size: 10.5px; color: var(--ink-3); margin: 6px 0; }
.m-quick { display: flex; gap: 6px; overflow-x: auto; padding: 8px 12px 4px; flex-shrink: 0; }
.m-quick button {
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink-2);
  padding: 6px 11px; border-radius: var(--r-pill); font-size: 12.5px; white-space: nowrap; cursor: pointer;
}
/* T44（派总 2026-10-29：纯青太突兀 → 渐变样式授权助手定）：青系同族柔和渐变
   浅青 → 品牌青 → 深青，135° 对角；不跨到金色，避免与红角标抢眼。
   T44② 未读角标改红色标注（红底白字，与底栏红点同语言）。
   T53①（派总 2026-10-31「绿框太显眼」）：整块饱和渐变退成淡青底 +
   深青字 —— 快捷入口是工具不是横幅，安静下来；红角标不变。 */
.m-quick-tiles { background: var(--brand-soft); }
.m-quick-tiles .m-quick-tile { color: var(--brand-deep); }
.m-quick-tiles .m-act-dot { background: var(--coral); color: #fff; }
.m-jump {
  position: sticky; bottom: 8px; margin: 0 auto;
  width: fit-content; padding: 6px 14px; border-radius: var(--r-pill); border: 0;
  background: var(--jade); color: #fff; font-size: 12px; font-weight: 700;
  box-shadow: var(--sh-2); cursor: pointer;
}

/* AI 管家柠柠聊天界面（2026-10-26，派总拍板升级）
   T26②：底部这一摞（浮层 + 快捷菜单 + 待发附件 + 输入栏）包成一个**相对定位**的容器，
   三个浮层改成贴着它的上沿浮出（bottom:calc(100% + 8px)）。
   原先三处都写 position:fixed + bottom:60px —— 那个 60 是按「只有输入栏一层」拍的，
   而这页底下实际摞了两层多（快捷菜单 ~54 + 输入栏 ~54 + 安全区），
   浮层就正好压在快捷菜单和输入框上（派总真机截图）。锚到容器上沿之后
   「这一摞长多高、浮层就抬多高」，不再靠猜数。同页「聊一聊」的 .m-chat-compose 早就是这个套路。 */
.m-composer { position: relative; flex-shrink: 0; display: flex; flex-direction: column; }

.m-quick-menu {
  display: flex; gap: 8px; padding: var(--sp-sm) var(--sp-lg); flex-shrink: 0;
  background: var(--surface); border-top: 1px solid var(--line);
}
.m-quick-btn {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  border: 1px solid var(--line-2); background: var(--surface-2); color: var(--ink-2);
  padding: 8px 4px; border-radius: var(--r); font-size: 11px; font-weight: 600;
  cursor: pointer; transition: all .15s;
}
.m-quick-btn .ic { width: 18px; height: 18px; color: var(--brand); }
.m-quick-btn:active { background: var(--brand-soft); border-color: var(--brand); }

.m-input-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px calc(8px + var(--safe-b));
  background: var(--surface); border-top: 1px solid var(--line);
  flex-shrink: 0;
}
.m-input-bar .m-input {
  flex: 1; min-height: var(--ctl-h); padding: 8px var(--sp-lg);
  border-radius: var(--r-pill); border: 1.5px solid var(--line-2);
  background: var(--surface-2); font-size: var(--fs-6);
}
.m-input-bar .m-input:focus { outline: none; border-color: var(--brand); background: var(--surface); }
.m-input-bar .m-iconbtn {
  width: var(--ctl-h); height: var(--ctl-h); border-radius: 50%; border: 0;
  background: none; color: var(--ink-2); display: grid; place-items: center;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.m-input-bar .m-iconbtn:active { background: var(--line); }
.m-input-bar .m-iconbtn .ic { width: 20px; height: 20px; }
.m-input-bar .m-send { background: var(--brand); color: #fff; }
.m-input-bar .m-send:active { background: var(--brand-deep); }

.m-emoji-picker {
  position: absolute; bottom: calc(100% + 8px); left: 12px; right: 12px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--sh-2);
  padding: var(--sp-lg); z-index: var(--z-top); max-height: 200px; overflow-y: auto;
}
.m-emoji-grid {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px;
}
.m-emoji-grid button {
  width: 100%; aspect-ratio: 1; border: 0; background: none;
  font-size: 24px; cursor: pointer; border-radius: var(--r-sm);
  transition: background .15s;
}
.m-emoji-grid button:active { background: var(--line); }

.m-typing {
  display: inline-block;
  animation: typing-pulse 1.2s ease-in-out infinite;
}
@keyframes typing-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .5; }
}

.m-location-card {
  display: flex; align-items: center; gap: 6px;
  padding: var(--sp-sm) var(--sp-lg); border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--line-2);
  font-size: 13px; color: var(--ink-2); cursor: pointer;
}
.m-location-card .ic { width: 16px; height: 16px; color: var(--brand); }
.m-location-card:active { background: var(--line); }

/* T29①（派总 2026-10-28「全站的定位功能全部下架」）：柠柠聊天里那颗「位置」按钮、
   定位面板（m-loc-panel / m-loc-search / m-loc-where / m-loc-item / m-loc-gps）
   连同 /app/loc/* 三个口一起撤下，第二步按新框架再重建。
   聊天里的定位卡片（上面那块）保留 —— 下架前发出去的定位消息还要照常显示。 */

/* 多选删除（P2）：双击气泡进入选择模式，浮出一条操作栏。
   ⚠️ 这一片浮层（emoji 面板 / 选择条 / T25 设置抽屉）原本都写的是
   `var(--sh-3)`，而 m.css 的 :root **从来没有这颗令牌** —— var() 引用未定义变量
   不报错，只是 box-shadow 整条失效（浮层没有投影，看着像贴在页面上）。
   T25 一并改成 --sh-2；加新令牌要先加进 :root，别在这儿凭空造名字。 */
.m-selbar {
  position: absolute; bottom: calc(100% + 8px); left: 12px; right: 12px;
  display: flex; align-items: center; gap: 8px;
  background: var(--surface); border-radius: var(--r); box-shadow: var(--sh-2);
  padding: var(--sp-sm) var(--sp-md); z-index: calc(var(--z-top) + 1); font-size: 13px; color: var(--ink-2);
}
.m-selbar button {
  border: 1px solid var(--line-2); background: none; color: var(--ink-2);
  border-radius: var(--r-sm); padding: 6px 10px; font-size: 13px; cursor: pointer;
}
.m-selbar .m-sel-del { background: var(--danger); border-color: var(--danger); color: #fff; }
.m-selbar .m-sel-del:disabled { opacity: .45; cursor: not-allowed; }
.m-selbar span.m-sel-count { margin-left: auto; }
.m-msg.is-checked .bubble, .m-msg.is-checked .m-chat-img,
.m-msg.is-checked .m-location-card, .m-msg.is-checked .lc-card {
  outline: 2px solid var(--brand); outline-offset: 2px;
}
.m-msg.is-checked { cursor: pointer; }

.m-msg-time {
  font-size: 10px; color: var(--ink-3); margin-top: 2px;
}

/* 会话列表 */
.m-conv { display: flex; gap: 11px; align-items: center; padding: 11px 2px; border-bottom: 1px solid var(--line); }
.m-conv:last-child { border-bottom: 0; }
.m-conv .av {
  width: 46px; height: 46px; border-radius: var(--r-pill); flex-shrink: 0;
  display: grid; place-items: center; font-weight: 900; font-size: 16px;
  background: var(--brand-soft); color: var(--brand-deep); overflow: hidden;
}
.m-conv .av img { width: 100%; height: 100%; object-fit: cover; }
/* 会话行未读角标（2026-09-24 派总反馈「只是黑字数字」）：
   消息列表的行是 .m-li（不是早年假设的 .m-conv —— 那个选择器已死、无模板引用），
   角标等于裸奔。这里给成和底栏角标同一颗红底圆角数字。 */
.m-li .badge {
  flex: none; align-self: flex-start; margin-top: 4px;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
  background: var(--coral); color: #fff; font-size: 10.5px; font-weight: 900;
  display: grid; place-items: center; line-height: 1;
}
.m-conv .nm { font-size: 14.5px; font-weight: 700; }
.m-conv .last { font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }

/* ----------------------------------------------------------------------
   我的 / 列表行 / 订单
   ---------------------------------------------------------------------- */
.m-mehead {
  position: relative;
  background: linear-gradient(135deg, var(--jade) 0%, #1c5550 62%, #24645d 100%);
  color: #fff; border-radius: var(--r-lg);
  padding: 16px 16px 18px; margin-bottom: 10px;
  overflow: hidden;
}
/* 派总 2026-10-12 第 ⑦ 条：整块头部包成指向资料维护页的链接（点昵称/头像即进）。
   去掉 a 默认下划线/蓝字、去掉移动端点按灰块，让它看起来就是原来那块。 */
.m-mehead-link { display: block; color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.m-mehead-link:active { opacity: .92; }
.m-mehead::after {           /* 右上角一圈柔光，避免整块死平 */
  content: ''; position: absolute; right: -34px; top: -46px;
  width: 148px; height: 148px; border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 189, 166, .42), transparent 68%);
  pointer-events: none;
}
.m-mehead .nick { font-size: 20px; font-weight: 900; letter-spacing: -.02em; }
.m-mehead .sub { font-size: 12px; opacity: .72; margin-top: 2px; }
.m-mehead .m-avatar { width: 54px; height: 54px; font-size: 20px; }
.m-wallet { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 16px; }
.m-wallet > div,
.m-wallet > a { display: block; background: rgba(255, 255, 255, .1); border-radius: var(--r-sm); padding: 10px; text-align: center; color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.m-wallet > a:active { background: rgba(255, 255, 255, .18); }
.m-wallet b { display: block; font-size: 18px; font-weight: 900; letter-spacing: -.02em; }
.m-wallet span { font-size: 10.5px; opacity: .72; }
.m-wallet b.coral { color: #ffb59f; }
.m-wallet b.gold { color: #f0d089; }
/* T56⑧（派总 2026-11-04 第 8 条）：「关注 TA / 已关注」和「聊一聊」搬进绿色大卡里面。
   结构一点没动 —— 仍是两个 POST 表单 + 那两颗钮，app.js 切换的还是 m-btn-primary /
   m-btn-ghost 两个类；这里只解决一件事：**在松绿底上配色要反过来**。
   · 关注 TA（未关注，m-btn-primary）→ 白底墨绿字：一块白在这张卡上最亮，是主动作；
   · 已关注 / 聊一聊（m-btn-ghost）→ 半透明白 + 白字 + 一道白描边：次动作，不抢。
   原来那套（品牌绿实心 / 浅灰底）在这里要么陷进背景、要么闪成两块白斑。
   选择器带 `.m-mehead-acts` 前缀 ⇒ 权重高于 `.m-btn-ghost` 本身，不靠书写顺序压规则。 */
.m-mehead-acts { display: flex; gap: 8px; margin-top: 14px; }
.m-mehead-acts form { flex: 1; min-width: 0; }
.m-mehead-acts .m-btn { background: rgba(255, 255, 255, .14); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .32); }
.m-mehead-acts .m-btn-primary { background: #fff; color: var(--jade); box-shadow: none; }
.m-mehead-acts .m-btn:active { transform: scale(.97); }

.m-li-log { align-items: flex-start; }
.m-log-amt { font-weight: 900; white-space: nowrap; text-align: right; }
.m-log-amt.plus { color: var(--coral); }
/* #16（派总 2026-10-14）：出账 = 离开自己账户（含冻结）→ 绿色（中国记账习惯：进红出绿） */
.m-log-amt.minus { color: var(--ok); }

.m-grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.m-grid4 a { text-align: center; padding: 12px 2px; border-radius: var(--r-sm); }
.m-grid4 a:active { background: var(--surface-2); }
.m-grid4 .ic { margin: 0 auto 6px; color: var(--brand-deep); }
.m-grid4 span { font-size: 11.5px; font-weight: 700; color: var(--ink-2); }
.m-grid4 b { display: block; font-size: 10px; color: var(--coral); font-weight: 800; }

/* 「我的」页的五宫格（2026-10-05 派总第 3 条）：我的需求 / 我的圆梦 /
   关注的人 / 我的收藏 / 仲裁庭 五件事并排，所以比 m-grid4 多一格。
   字号同步收 0.5px，五格才不会把「关注的人」挤成两行。 */
.m-grid5 { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; }
.m-grid5 a { text-align: center; padding: 12px 1px; border-radius: var(--r-sm); }
.m-grid5 a:active { background: var(--surface-2); }
/* T24③（派总 2026-10-27）：六宫格 3×2 —— 「草稿」插在「我的圆梦」和「圈子」中间。 */
.m-grid6 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.m-grid6 a { text-align: center; padding: 12px 1px; border-radius: var(--r-sm); }
.m-grid6 a:active { background: var(--surface-2); }
/* T24③：草稿页勾选框（全选联动 + 批量删除按钮按它计数） */
.draft-pick { width: 17px; height: 17px; accent-color: var(--brand); flex: none; }
/* T24③ 时六宫格只抄了容器和 a 的规则，.ic/span/b 三行漏了 ——
   图标没居中、标签和角标挤成一行。补上，与五宫格共用。 */
.m-grid5 .ic, .m-grid6 .ic { margin: 0 auto 6px; color: var(--brand-deep); }
.m-grid5 span, .m-grid6 span { display: block; font-size: 11px; font-weight: 700; color: var(--ink-2); }
.m-grid5 b, .m-grid6 b { display: block; font-size: 10px; color: var(--coral); font-weight: 800; }

/* 派总 2026-10-29：「我的」页六宫格 ——
   ① 图标放大到原先的 1.2 倍（.ic 基准 20px → 24px）；
   ② 红色数字从文字下方挪到**图标右下角**，白底徽标、白底大小贴着数字
      （line-height:1 + 2px/3px 内边距，不再占文字下面一整行）。 */
.m-grid6 .gicon { position: relative; display: block; width: 24px; margin: 0 auto 6px; }
.m-grid6 .gicon .ic { display: block; margin: 0; width: 24px; height: 24px; }
.m-grid6 .gicon b {
  position: absolute; right: -13px; bottom: -6px;
  font-size: 10px; line-height: 1; padding: 2px 3px; border-radius: 7px;
  color: var(--coral); background: #fff;
}

/* 混合信息流的「来源小标」（2026-10-05 派总第 4/5 条）：
   小青柠的需求卡和小圈子的动态卡**长得不一样**，混排时给每张卡顶上挂一个
   10px 的小标，人一眼知道这条是哪边的 —— 比再塞一排筛选胶囊省事，也更安静。 */
.m-mix-item { display: flex; flex-direction: column; gap: 4px; }
.m-mix-src {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 10px; font-weight: 800; letter-spacing: .3px;
  color: var(--ink-3);
}
.m-mix-src .ic { width: 11px; height: 11px; }
.m-mix-src.is-lime { color: var(--brand-deep); }   /* 小青柠（需求池）用品牌色 */

.m-list { background: var(--surface); border-radius: var(--r); box-shadow: var(--sh-1); overflow: hidden; }
.m-li {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px; border-bottom: 1px solid var(--line);
}
.m-li:last-child { border-bottom: 0; }
.m-li:active { background: var(--surface-2); }
.m-li .ic { color: var(--ink-3); }
.m-li .lb { font-size: 14.5px; font-weight: 600; }
.m-li .val { margin-left: auto; color: var(--ink-3); font-size: 13px; }
/* H 波③/④（派总 2026-10-08）：交易记录行里的三种「这不是实数」标记 ——
   · <s>＝被顶掉的计划日期（延期之后，原截止日打删除线留着让人看见「本来该几号」）
   · .is-dim＝这一行暂时作废（申诉没结束，验收/放款期限就没意义了 —— 灰掉且不显示日期）
   · .m-tag＝行内的结果胶囊（「谁赢了申诉」），挤在标题和日期中间，不换行。 */
.m-li .val s { text-decoration: line-through; opacity: .55; }
.m-li.is-dim .lb, .m-li.is-dim .val { opacity: .42; }
.m-li > .m-tag { font-size: 10.5px; padding: 2px 7px; white-space: nowrap; }
/* 「这件事是谁做的」徽标（本人 / 对方 / 平台）—— 订单「时间」列表每行前面那颗。
   口径与网页版 `.who-tag` 完全一致，手机端把字号再压一点以省横向空间。 */
.who-tag {
  flex-shrink: 0; font-style: normal; font-weight: 800;
  font-size: 10px; line-height: 1.7; padding: 0 6px;
  border-radius: var(--r-pill); background: var(--surface-2); color: var(--ink-3);
}
.who-tag.is-me { background: var(--brand-soft); color: var(--brand-deep); }
.who-tag.is-other { background: var(--coral-soft); color: var(--coral); }
.who-tag.is-both { background: var(--jade-soft); color: var(--jade); }

/* 「交易记录 · 确定信息」折叠块（App 订单页用）。口径与网页版 `.rec` 完全一致。
   ⚠️ 同 .m-fold 那条铁律：关着时必须**显式**藏掉 body —— <details> 只是
      「跳过渲染」内容，里面若有 absolute 定位的元素仍会参与排版。 */
.rec + .rec { border-top: 1px solid var(--line); }
.rec > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 13px 0; font-size: 13.5px; font-weight: 700; list-style: none;
}
.rec > summary::-webkit-details-marker { display: none; }
.rec > summary .ic { width: 16px; height: 16px; color: var(--brand-deep); flex: none; }
.rec-when { margin-left: auto; font-size: 11px; color: var(--ink-3); font-weight: 500; }
.rec-caret { color: var(--ink-4); flex: none; transition: transform .18s; }
.rec[open] .rec-caret { transform: rotate(90deg); }
.rec:not([open]) > .rec-body { display: none; }
.rec-body { padding: 0 0 14px; font-size: 13px; color: var(--ink-2); line-height: 1.75; }
.rec-body .rl { display: flex; gap: 10px; padding: 3px 0; align-items: baseline; }
/* J 波④（派总 2026-10-09）：「服务费（需求者 5%）」这类长名字不许折成两行，
   金额一律推到行的最右 —— 一列名字一列数字，账目一眼扫得齐。 */
.rec-body .rl .k { flex: 1 1 auto; white-space: nowrap; }
.rec-body .rl .v { margin-left: auto; text-align: right; }
.rec-body .rl .k { flex: none; width: 72px; color: var(--ink-3); font-size: 12.5px; }
.rec-body .rl .v { min-width: 0; word-break: break-word; }
.rec-body .rl .v b { color: var(--coral); }
.m-li .chev { color: var(--ink-4); }

.m-tabs { display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 10px; -webkit-overflow-scrolling: touch; }
.m-tabs::-webkit-scrollbar { display: none; }
.m-tabs a {
  flex-shrink: 0; padding: 7px 13px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink-2); font-size: 13px; font-weight: 700;
  box-shadow: var(--sh-1);
}
.m-tabs a.on { background: var(--jade); color: #fff; box-shadow: none; }

/* 列表里的需求行：左边一张小图，右边文字 —— 有图才不像 Excel */
.m-demand-row { display: flex; gap: 11px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.m-demand-row:last-child { border-bottom: 0; }
/* 缩略图：两个选择器共用一条规则 ——
   `.thumb` 是「在列表行里」的位置类（既有模板在用），
   `.m-thumb` 是通用版（订单详情那种不在列表行里的场合）。
   不写两份：两份一旦有人只改一处，同一个缩略图在两个页面上大小就不一样了。 */
.m-thumb, .m-demand-row .thumb {
  width: 72px; height: 72px; border-radius: var(--r-sm); flex-shrink: 0;
  display: grid; place-items: center; overflow: hidden;
  background: linear-gradient(150deg, var(--brand-tint), var(--brand-soft));
  color: var(--brand-deep);
}
.m-thumb img, .m-demand-row .thumb img { width: 100%; height: 100%; object-fit: cover; }

/* 「我的」页进行中需求/圆梦行（派总 2026-10-29）：行前加缩略图 ——
   视觉沿用 .m-demand-row .thumb 那套（渐变底 + 无图退品类图标），
   尺寸按行高压到 46px（72px 会把 13px 上下内边距的行撑到近半屏高）。 */
.m-li .thumb {
  width: 46px; height: 46px; border-radius: var(--r-sm); flex-shrink: 0;
  display: grid; place-items: center; overflow: hidden;
  background: linear-gradient(150deg, var(--brand-tint), var(--brand-soft));
  color: var(--brand-deep);
}
.m-li .thumb img { width: 100%; height: 100%; object-fit: cover; }
.m-li .thumb .ic { color: var(--brand-deep); }

.m-status { padding: 3px 9px; border-radius: var(--r-pill); font-size: 11px; font-weight: 800; white-space: nowrap; }
.st-published { background: var(--brand-soft); color: var(--brand-deep); }
.st-taken, .st-delivering { background: var(--warn-soft); color: var(--warn); }
.st-completed, .st-paid, .st-verified { background: var(--ok-soft); color: var(--ok); }
.st-closed, .st-failed, .st-cancelled, .st-breached { background: var(--surface-2); color: var(--ink-3); }
.st-reviewing, .st-delivered, .st-settling { background: var(--gold-soft); color: var(--gold-ink); }
.st-disputed { background: var(--danger-soft); color: var(--danger); }
.st-accepted { background: var(--warn-soft); color: var(--warn); }
/* 「行动中」＝正在干活，用品牌青绿，和「等待中」的黄区分开 */
.st-working { background: var(--brand-soft); color: var(--brand-deep); }
/* 「验收未通过」＝钱还冻着、有争议，用警示红 */
.st-rejected { background: var(--danger-soft); color: var(--danger); }

.m-steps { display: flex; align-items: center; gap: 4px; margin: 14px 0 4px; }
.m-step { flex: 1; text-align: center; }
.m-step i {
  display: block; height: 4px; border-radius: 999px; background: var(--line-2); margin-bottom: 6px;
}
.m-step.on i { background: var(--brand); }
.m-step span { font-size: 10px; color: var(--ink-3); font-weight: 700; }

/* 订单页顶部进度条吸顶（派总 2026-10-02 E波①）：滚到哪一步都看得见。
   ⚠️ top 必须含 --top-h（铁律 19 同源）；左右负 margin 把底色铺满整行，
   不然滚动时卡片会从两侧 12px 的缝隙里穿出来（同 .pc-cats 的做法）。 */
.m-steps-sticky {
  position: sticky; top: calc(var(--safe-t) + var(--top-h)); z-index: 25;
  background: var(--paper);
  margin: 0 -12px; padding: 8px 12px 2px;
}
.m-steps-sticky .m-steps { margin: 0; }
.m-step.on span { color: var(--brand-deep); }
/* P 波①（派总 2026-10-19）：正在进行的格不亮条，文字改粗体+深色标记「正在进行」 */
.m-step.is-cur span { color: var(--ink); font-weight: 900; }

/* X④（2026-10-11）：需求详情进度卡（m-ownprog）已随「直跳圆梦单」拆除，
   这两条样式随之退役。 */

/* 「修改方案」折叠条只在**收起态**有存在意义（派总 2026-10-08：编辑都进去了，
   这条横幅还杵在上面就是画蛇添足）——展开后立即让位，
   收起路径由表单底部的「退出编辑」负责。带 data-edit-for 的编辑型折叠通用此规则。 */
details[data-edit-for][open] > summary { display: none; }

/* 方案附图查看器（派总 2026-10-08 第 1 条）：点附图不再跳新标签看原图 ——
   页面内全屏遮罩，多图左右滑动（scroll-snap 原生），点 × / 背景 / Esc 关闭。
   与 app.css 同一份类名（app.js 单一实现，两端样式各自维护）。 */
/* 灯箱基定义（两端同一条）：既服务「方案附图」的横滑查看器（track+slide），
   也服务聊天里单击看原图（img+hint）。两种子结构靠 flex 列居中同时成立，
   但 track 必须显式 width:100% —— 列向 flex 里 align-items:center 会让它按内容算宽，
   每张图的 flex-basis:100% 就成了循环百分比，一屏放不下整张图。 */
.m-lightbox[hidden] { display: none; }
.m-lightbox-track { display: flex; width: 100%; height: 100%; flex: none; overflow-x: auto; scroll-snap-type: x mandatory; }
/* min-width:0 是这条链上唯一的闸：flex 项默认 min-width:auto = 不小于内容宽，
   一张 900px 宽的照片会把「一屏一张」的 slide 顶成 932px，滑动距离随之失控
   （实测：不给 min-width:0 时 slide 932 / 给 390）。 */
.m-lightbox-slide { flex: 0 0 100%; min-width: 0; scroll-snap-align: center; display: flex; align-items: center; justify-content: center; padding: var(--sp-xl); }
.m-lightbox-slide img { max-width: 100%; max-height: 82vh; border-radius: 10px; }
.m-lightbox-x {
  position: absolute; top: calc(var(--safe-t) + 10px); right: 12px;
  width: 38px; height: 38px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255,255,255,.14); color: #fff; font-size: 22px; line-height: 1;
}
.m-lightbox-count {
  position: absolute; bottom: 16px; left: 0; right: 0; text-align: center;
  color: #fff; font-size: 13px; font-variant-numeric: tabular-nums;
}

/* ⑦ 时间可视化（F波）：倒计时进度条卡片 —— 把截止时间从行动区提到顶部并做成可见的进度 */
.m-timer { padding: 12px 14px; }
.m-timer-head { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.m-timer-head b { font-weight: 700; color: var(--ink); }
.m-timer-date { margin-left: auto; color: var(--ink-3); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.m-timer-bar { height: 6px; background: var(--line); border-radius: 99px; margin: 10px 0 6px; overflow: hidden; }
.m-timer-fill { height: 100%; background: var(--brand); border-radius: 99px; transition: width .3s; }
.m-timer-fill.is-over { background: var(--danger); }
.m-timer-remain { font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.m-timer-remain.is-over { color: var(--danger); font-weight: 600; }

/* ⑤ 发布者行 + 聊一聊胶囊（2026-10-05 派总第 1/4/6 条）：
   原「聊一聊」大卡（.m-chat-entry，已删）与「⑧ 对方」卡片收拢成需求卡底部的一行 */
.m-pub {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; padding-top: 11px;
  border-top: 1px dashed var(--line);
}
.m-pub-who {
  display: flex; align-items: center; gap: 9px;
  flex: 1; min-width: 0; text-decoration: none; color: inherit;
}
.m-pub-who .m-avatar { width: 34px; height: 34px; font-size: 13px; flex-shrink: 0; }
.m-pub-who b { font-size: 13.5px; display: block; line-height: 1.3; }
.m-pub-who .m-sub { display: block; font-size: 11.5px; }
.m-chat-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 14px; border-radius: 999px; flex-shrink: 0;
  background: rgba(0, 189, 166, .12); color: var(--brand);
  font-size: 13px; font-weight: 800; text-decoration: none;
}
.m-chat-pill .ic { width: 15px; height: 15px; }

.m-note { background: var(--surface-2); border-radius: var(--r-sm); padding: 11px 12px; font-size: 13px; line-height: 1.7; }

/* 搜索框（搜索页整行用；首页走顶栏里的 .m-topsearch） */
.m-searchbar { display: flex; gap: 8px; align-items: center; padding-bottom: 10px; }
.m-searchbar .box {
  flex: 1; display: flex; align-items: center; gap: var(--sp-xs);
  min-height: var(--ctl-h);
  background: var(--surface); border-radius: var(--r-pill);
  padding: 0 var(--sp-xl); box-shadow: var(--sh-1);
}
.m-searchbar input { flex: 1; border: 0; background: transparent; font-size: var(--fs-6); min-width: 0; }
.m-searchbar input:focus { outline: none; }
.m-searchbar .ic { color: var(--ink-3); }

/* ----------------------------------------------------------------------
   关注的人列表（派总 2026-10-12：序号 · 小头像+昵称+简介 · 关注/取消关注）
   行 = 序号 + 头像（点进 TA 主页）+ 昵称/简介（点进 TA 主页）+ 关注钮。
   R8（派总 2026-10-21 晚）：取消关注**行不退场** —— 按钮原地变回「关注」可再点回来，
   行退场动效样式已随行退场功能一起拆除。
   ---------------------------------------------------------------------- */
.m-flist { list-style: none; margin: 0; padding: 0; }
/* 派总 2026-10-21 下午第 4 条：关注页三类按钮口径。
   m-btn-chat  = 浅青底深青字「聊一聊」（互相关注行）；
   m-btn-back  = 青色线框 + 青字 + 白底「回关」（被关注 · 未回关行）；
   m-follow-pill = 白底灰字状态胶囊（已关注 / 互相关注）。
   派总 2026-10-21 傍晚：胶囊**可点** —— 点一下 = 取消关注/取消回关，
   状态可逆；加 m-follow-pill-btn 给按压反馈。
   派总 2026-10-21 晚（R8 第 2 条）：三类按钮**高度务必一致** ——
   胶囊跟 .m-btn-slim 同高（34px）同字号（13px），不能有大有小。 */
.m-btn-chat {
  background: var(--brand-tint); color: var(--brand-deep);
  border: 0; text-decoration: none;
}
.m-btn-back {
  background: #fff; color: var(--brand);
  border: 1px solid var(--brand);
}
.m-follow-pill {
  flex: none; display: inline-grid; place-items: center;
  min-width: 64px; height: 34px; padding: 0 13px;
  background: #fff; color: var(--ink-3);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  font-size: 13px; font-weight: 700; white-space: nowrap;
}
button.m-follow-pill-btn {
  border: 1px solid var(--line); cursor: pointer; font-family: inherit;
}
button.m-follow-pill-btn:active { transform: scale(.95); opacity: .8; }
.m-frow {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; background: var(--surface);
  border-radius: var(--r-sm); box-shadow: var(--sh-1);
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.m-flist .m-frow + .m-frow { margin-top: 8px; }
.m-frow-no {
  width: 20px; flex-shrink: 0; text-align: center;
  font-size: 12.5px; font-weight: 800; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.m-frow .m-avatar { width: 38px; height: 38px; font-size: 14px; }
.m-frow-avatar { text-decoration: none; color: inherit; }
.m-frow-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  text-decoration: none; color: inherit;
}
.m-frow-nick {
  font-size: 14px; font-weight: 800; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m-frow-bio {
  font-size: 12px; color: var(--ink-3); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m-frow form { flex-shrink: 0; margin: 0; }

.m-chips { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 10px; -webkit-overflow-scrolling: touch; }
.m-chips::-webkit-scrollbar { display: none; }
.m-chips a {
  flex-shrink: 0; padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700; box-shadow: var(--sh-1);
}
.m-chips a.on { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }

/* ----------------------------------------------------------------------
   闲鱼式筛选条（发现页 / 搜索页） —— 2026-09-22 把「横滑条」换掉的版本
   ----------------------------------------------------------------------
   上一版是 `m-chips + m-catbar` 两条横滑条，毛病是：
   **屏幕只有这么宽，十几个品类里有大半要靠拖才看得到 —— 用户不知道它们存在。**
   现在：横条上只留 3 档类型（屏内等分，绝不横滑），其余全部收进「筛选」面板分组。

   面板是**纯 CSS 抽屉**（隐藏的 checkbox + 两个 label），没有 JS 也能用：
   点「筛选」打开（勾选）、点遮罩关闭（再点一次 checkbox 就是取消勾选）。
   ⚠️ `#feedFilter:checked ~ ...` 要求三者**同一父级且互为兄弟**，
   所以 m-fcheck / m-fbtn / m-fmask / m-fpanel 必须都在 .m-fbar 下面。
   ---------------------------------------------------------------------- */
/* 派总 2026-10-26：二级标签「下滑即现身」——
   上滑（往下翻）时它跟着内容滑到一级卡片背后；在**任意深度**轻轻往下带一下，
   它和三级标签一起滑回来钉在顶栏下沿（见下方 .m-navtabs 与 app.js 的 initHomeNavReveal）。
   所以这里要 sticky：钉得住才谈得上「带回来」；显隐由 .is-nav-hidden 统一控制。
   左右负 margin 仍然保留：底色铺满整行，卡片不会从两侧 12px 的缝里露出来。 */
.m-menubar {
  position: relative; z-index: 25;
  background: var(--paper);
  margin: 0 -12px; padding: 2px 12px 4px;
}
/* sticky 只给两个板块首页（搜索页的筛选条保持原样：随内容滚走）。
   top 用一级卡片（顶栏）高度算 —— 与 .m-top 的 sticky top 同源。 */
.m-main.is-home > .m-menubar {
  position: sticky; top: calc(var(--safe-t) + var(--top-h)); z-index: 26;
  transition: transform .2s cubic-bezier(.22,.61,.36,1);
}
.m-fbar {
  position: relative;
  display: flex; align-items: center; gap: 8px;
}
/* 三个类型标签**等分**剩下的宽度：宽就一定不变吗？不一定 —— 所以还要 nowrap + 省略号兜底，
   保证再窄的屏（320px）也不会把「求物品」压成两行或挤出屏外。 */
.m-ftabs { flex: 1; min-width: 0; display: flex; gap: 6px; }
/* ⚠️ 小圈子页的分类胶囊（.pc-cat）与需求池的三档胶囊（.m-ftab）共用**同一套盒模型**：
   同一行里高矮胖瘦不一致，看起来就像两个产品。尺寸/圆角/投影统一在这里定死，
   **颜色各留各的**（见下面 .on）—— 派总原话：「大小样式改为一致，颜色保持当前不变」。
   以后要调胶囊大小，只改这一处，并且**必须同步改 .pc-cat**（单测
   test_the_two_entry_menus_share_one_pill_size 逐键比对 min-height/padding/
   border-radius/font-size/box-shadow/background，两边必须一模一样）。
   T17③（派总 2026-10-25 第 3 条「次级标签大小可以适当缩小一些」）：
   32px / 7px 12px / 13px → 27px / 4px 10px / 12.5px（两个入口一起缩，不许只缩一边）。 */
.m-ftab {
  flex: 1; min-width: 0;
  min-height: 27px; padding: 4px 10px; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700; text-align: center;
  box-shadow: var(--sh-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-ftab.on { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }

.m-fcheck { display: none; }          /* 状态开关，不需要出现在界面上 */
/* 「筛选」按钮跟同一行的三档胶囊**齐高**（T17③：32 → 27，与 .m-ftab 一起缩），
   否则这一排看着像高低肩 */
.m-fbtn {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 4px;
  min-height: 27px; padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700; box-shadow: var(--sh-1);
  cursor: pointer; user-select: none;
}
.m-fbtn.has { background: var(--brand-soft); color: var(--brand-deep); box-shadow: none; }
.m-fbtn-chev { transition: transform .18s ease; }
/* 面板开着时箭头翻上来，一眼看出「还能再点一次收回去」 */
#feedFilter:checked ~ .m-fbtn .m-fbtn-chev { transform: rotate(180deg); }
.m-fbadge {
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--r-pill); background: var(--coral); color: #fff;
  font-size: 10.5px; font-weight: 900; font-style: normal; line-height: 16px; text-align: center;
}

/* 仲裁庭列表（派总 2026-10-12 第 ⑥ 条）：顶部三数据卡 + 筛选 + 2.5 条折叠。
   复用 .m-ftab 做筛选胶囊（与需求池/小圈子胶囊同尺寸同手感）。 */
.court-cards { display: flex; gap: 8px; margin: 2px 0 4px; }
.court-stat {
  flex: 1; min-width: 0; padding: 12px 8px; border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--sh-1); text-align: center;
}
.court-stat b { display: block; font-size: 22px; font-weight: 900; line-height: 1.1; color: var(--ink); }
.court-stat span { display: block; margin-top: 3px; font-size: 11.5px; color: var(--ink-3); font-weight: 700; }
.court-stat.coral b { color: var(--coral); }
.court-stat.jade b { color: var(--jade); }

/* T45（派总 2026-10-29）：三档筛选从通栏胶囊改**文字小标签**（左对齐、自适应宽度），
   左右滑屏切标签（手势在 court_list.html 模板里）。 */
.court-filters { display: flex; gap: 8px; margin: 12px 0 2px; }
.court-filters .m-ftab { flex: 0 0 auto; min-height: 24px; padding: 3px 12px; font-size: 12px; }

/* T31 ②（派总 2026-10-29）：数据卡点数字锚点定位 —— 顶栏 sticky 会盖住落点，让一截。 */
#sec-open, #sec-closed, #sec-jury { scroll-margin-top: 64px; }

/* 1.5 条折叠（T33-2，派总 2026-10-29：口径从 2.5 条收紧）：默认（data-collapse="1"）
   只露前 1 条，第 2 条半截 + 其余隐藏。点「展开全部」翻成 "0" 显示全部。
   背景用 --surface 与外层 .m-card 对齐，淡出才接得上。 */
.court-flist { display: flex; flex-direction: column; }
.court-flist[data-collapse="1"] > .m-li:nth-child(2) {
  max-height: 40px; overflow: hidden; position: relative;
}
.court-flist[data-collapse="1"] > .m-li:nth-child(2)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 24px;
  background: linear-gradient(to bottom, transparent, var(--surface));
}
.court-flist[data-collapse="1"] > .m-li:nth-child(n+3) { display: none; }

/* T33-1（派总 2026-10-29）：hero 右侧「去考陪审资格」按钮 + 金标签「信用达标 · 待考核」
   成一列（按钮在上、标签贴其正下方，右对齐），整体往下沉 1 个字符
   —— 1 个字符 = 「我的信用分」标签字号 12px，不顶绿框上沿。 */
.court-cta {
  /* T41（派总 2026-10-29「与 680 数字底部对齐」）：右列沉到底 —— align-self:flex-end
     对齐左栏底部（左栏含数字行 8px 下边距），再补回 8px 让按钮组底边贴齐数字底边。 */
  align-self: flex-end; margin-bottom: 8px;
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
}

/* K 波④（派总 2026-10-17）：投票期、还没投票的陪审 —— 两颗投票大卡是
   这个阶段页面上最显眼的东西：彩边 + 浅色底 + 大字号，远看就知道往哪点。
   ⚠️ 大卡上**不显示当前票数**（看到一边倒会锚定判断，公正性优先），
   也不挂「点卡看详情」—— 投完才走 .m-card 普通票数卡那条路。 */
.m-votebig {
  text-align: center; padding: 18px 10px; cursor: pointer;
  border: 1.5px solid var(--line-2); box-shadow: var(--sh-2);
  transition: transform .08s ease;
}
.m-votebig:active { transform: scale(.97); }
.m-votebig-brand { border-color: var(--brand); background: var(--brand-soft); }
.m-votebig-jade { border-color: var(--jade); background: var(--jade-soft); }
.m-votebig .m-tag { font-size: 11px; }
.m-votebig-t { display: block; margin: 10px 0 4px; font-size: 17px; font-weight: 900; color: var(--ink); }

/* T30（派总 2026-10-28）：陪审考核卷 —— 选择题选项行。 */
.m-exam-opt {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 12px; border: 1px solid var(--line); border-radius: 12px;
}
.m-exam-opt input { margin-top: 3px; flex-shrink: 0; }
.m-exam-q { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }

.m-more {
  margin: 10px 0 2px; width: 100%; min-height: 38px; border: 0;
  border-radius: var(--r-pill); background: var(--surface); color: var(--brand-deep);
  font-size: 13px; font-weight: 800; box-shadow: var(--sh-1); cursor: pointer;
}

.m-fmask {
  position: fixed; inset: 0; z-index: var(--z-sheet);
  background: var(--scrim);
  opacity: 0; visibility: hidden; transition: opacity var(--dur-2) var(--ease);
}
.m-fpanel {
  position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: calc(var(--z-sheet) + 1);
  background: var(--surface); border-radius: var(--r-lg); box-shadow: var(--sh-sheet);
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
#feedFilter:checked ~ .m-fmask { opacity: 1; visibility: visible; }
#feedFilter:checked ~ .m-fpanel { opacity: 1; visibility: visible; transform: none; }

/* 面板内容太高就自己滚 —— 十几个品类 + 5 组条件不可能一屏放下。
   底部操作条用 sticky，滚到哪儿都能点「查看结果」。 */
.m-fpanel-in {
  max-height: 68vh; overflow-y: auto; padding: var(--sp-xl) var(--sp-lg) 0;
  -webkit-overflow-scrolling: touch;
}
.m-fgroup { margin-bottom: 16px; }
.m-fg-t {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 900; color: var(--ink-3);
  margin-bottom: 8px; letter-spacing: -.01em;
}
.m-fg-t .ic { width: 14px; height: 14px; }
.m-fopts { display: flex; flex-wrap: wrap; gap: 7px; }

/* 胶囊选项：input 铺满整个 label 当点击区，span 只管长相。
   ⚠️ 不能用 `visibility:hidden` / `display:none` 藏 input —— 那样表单就提交不出参数了，
   键盘也 tab 不到。这里用「透明铺满」，点哪儿都是点在 radio 上。 */
.m-fopt { position: relative; display: inline-flex; cursor: pointer; }
.m-fopt input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.m-fopt span {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 12px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font-size: 13px; font-weight: 600; white-space: nowrap;
}
.m-fopt span em { font-style: normal; font-size: 11px; font-weight: 700; color: var(--ink-3); }
.m-fopt input:checked + span { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.m-fopt input:checked + span em { color: rgba(255, 255, 255, .78); }
.m-fopt input:focus-visible + span { outline: 2px solid var(--brand-deep); outline-offset: 2px; }

.m-ffoot {
  position: sticky; bottom: 0;
  display: flex; gap: 8px; padding: 10px 0 12px;
  background: var(--surface); border-top: 1px solid var(--line);
}
.m-ffoot .m-btn { flex: 1; }

/* 「已选」小胶囊：面板一关，得一眼看出现在是按什么在筛 —— 否则用户会以为站里就这点东西 */
.m-active { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px 0 2px; }
.m-actchip {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 5px 10px; border-radius: var(--r-pill);
  background: var(--brand-soft); color: var(--brand-deep);
  font-size: 12px; font-weight: 700;
}
.m-actchip .ic { width: 12px; height: 12px; }
.m-actclear { margin-left: auto; font-size: 12px; font-weight: 700; color: var(--ink-3); }

.m-pager { display: flex; gap: 10px; align-items: center; justify-content: center; padding: 18px 0 6px; }
.m-pager a, .m-pager span {
  padding: 9px 18px; border-radius: var(--r-pill); background: var(--surface);
  box-shadow: var(--sh-1); font-size: 13.5px; font-weight: 700; color: var(--ink-2);
}
.m-pager span { background: transparent; box-shadow: none; color: var(--ink-3); font-weight: 600; }

/* ----------------------------------------------------------------------
   发布页：选封面（把「没有图」这件事从源头解掉）
   ---------------------------------------------------------------------- */
.m-pick { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.m-pick label { position: relative; display: block; cursor: pointer; }
.m-pick input { position: absolute; opacity: 0; pointer-events: none; }
.m-pick .ph {
  position: relative; overflow: hidden;
  border-radius: var(--r-sm); aspect-ratio: 1;
  background: var(--surface-2);
  box-shadow: inset 0 0 0 2px transparent;
  transition: box-shadow .15s;
}
.m-pick .ph img { width: 100%; height: 100%; object-fit: cover; }
.m-pick .ph .nm {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 12px 6px 4px;
  background: linear-gradient(to top, rgba(0, 0, 0, .58), transparent);
  color: #fff; font-size: 10.5px; font-weight: 700; text-align: center;
}
.m-pick input:checked + .ph { box-shadow: inset 0 0 0 2.5px var(--brand); }
.m-pick input:checked + .ph::after {
  content: ''; position: absolute; top: 0; right: 0;
  width: 0; height: 0; border-left: 22px solid transparent;
  border-top: 22px solid var(--brand);
}
.m-pick-none .ph {
  display: grid; place-items: center;
  color: var(--ink-3); font-size: 11px; text-align: center;
}

/* ==================== 头像按钮 + 选择面板（派总 2026-10-12 第 ⑤ 条） ==================== */
.av-btn { display: inline-flex; align-items: center; gap: 10px; background: none; border: 0; padding: 4px 0; cursor: pointer; }
.av-btn .av { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; background: var(--surface-2); }
.av-btn-edit { font-size: 13px; color: var(--brand); font-weight: 700; }
.av-file { display: none; }

.av-sheet { position: fixed; inset: 0; z-index: var(--z-sheet); display: flex; align-items: flex-end; }
.av-sheet[hidden] { display: none; }
.av-sheet-mask { position: absolute; inset: 0; background: var(--scrim); }
.av-sheet-panel {
  position: relative; width: 100%; background: var(--surface);
  border-radius: var(--r-sheet) var(--r-sheet) 0 0; padding: var(--sp-xl) var(--sp-xl) calc(var(--sp-lg) + var(--safe-b));
  max-height: 82vh; overflow-y: auto; box-shadow: var(--sh-sheet);
}
.av-sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.av-sheet-head b { font-size: 16px; }
.av-sheet-x { width: 32px; height: 32px; border: 0; background: var(--surface-2); border-radius: 50%; display: grid; place-items: center; color: var(--ink-2); }
.av-sheet-x .ic { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; }
.av-sheet-sub { font-size: 12px; color: var(--ink-3); margin: 4px 0 8px; }

.av-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.av-cell { padding: 0; border: 0; background: var(--surface-2); border-radius: var(--r-sm); overflow: hidden; aspect-ratio: 1 / 1; }
.av-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.av-actions { display: flex; gap: 10px; margin-top: 12px; }
.av-act {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 11px; border: 1px solid var(--line, #ececec); border-radius: 12px;
  background: var(--surface, #fff); font-size: 14px; font-weight: 700; color: var(--ink);
}
.av-act .ic { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; }
.av-act-ghost { color: var(--ink-2); font-weight: 600; }
.av-link-wrap { margin-top: 10px; }

/* ---------- 通知中心 ----------
   未读给一层青绿底：一屏扫下来能立刻看见「哪几条还没看」。
   跳转一律走视图里翻译过的 app_url，翻不出来的通知根本没有「去看看」，
   所以这里不存在「点了跳到网页版」的可能。 */
.m-notice { display: flex; gap: 10px; align-items: flex-start; }
/* T16i-4（派总 2026-10-23）：未读/已读一眼可辨 ——
   未读 = 青绿底 + 左缘珊瑚条 + 标题前小红点（分区头上的红点从此对应得到具体条目）；
   已读 = 无底色、标题退灰不加粗 —— 摊开分区扫一眼，看没看过一目了然。 */
.m-notice.unread { background: var(--brand-tint); box-shadow: inset 3px 0 0 var(--coral); }
.m-dot-item { display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--coral); margin-right: 5px; vertical-align: 2px; }
.m-notice:not(.unread) .n-title { font-weight: 600; color: var(--ink-2); }
.m-notice-ic {
  width: 32px; height: 32px; border-radius: 10px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--ink-2);
}
.m-notice-ic.k-order { background: var(--brand-soft); color: var(--brand-deep); }
.m-notice-ic.k-court { background: var(--danger-soft); color: var(--danger); }
.m-notice-ic.k-credit { background: var(--gold-soft); color: var(--gold-ink); }
.m-notice-ic.k-message { background: var(--jade-soft); color: var(--jade); }
/* 2026-09-23 新增的两个分区：上新 = 青绿（"有新东西"）；活动 = 金（"运营/公告"）。 */
.m-notice-ic.k-new { background: var(--brand-soft); color: var(--brand-deep); }
.m-notice-ic.k-activity { background: var(--gold-soft); color: var(--gold-ink); }
.m-notice-ic.k-system { background: var(--gold-soft); color: var(--gold-ink); }
.m-notice-link {
  display: inline-flex; align-items: center; gap: 1px;
  margin-top: 6px; font-size: 12.5px; font-weight: 700; color: var(--brand-deep);
}
/* 2026-10-01 新增：未读通知独立的「标为已读」入口（系统消息没有链接，
   原来只能整段标掉；加了这条，看了就能点一下清掉，浅绿高亮 + 红点一起消失）。 */
.m-notice-read {
  display: inline-flex; align-items: center;
  margin-top: 6px; margin-left: 10px; padding: 2px 10px;
  font-size: 11.5px; font-weight: 700; color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 999px;
}

/* ---------- 规则页（可折叠） ----------
   8 大章全铺开在手机上太长，所以默认只展开「资金与担保」。
   ⚠️ 关着的 <details> 里**不要放 position:absolute 的子元素**：
   浏览器仍会给它排版（这是老坑，见 MEMORY 铁律 11）。这里全是普通文档流元素。 */
.m-rule {
  margin-bottom: 8px; background: var(--surface);
  border-radius: var(--r); box-shadow: var(--sh-1); overflow: hidden;
}
.m-rule > summary {
  display: flex; align-items: center; list-style: none; cursor: pointer;
  padding: 13px 14px; font-size: 14.5px; font-weight: 800; letter-spacing: -.01em;
}
.m-rule > summary::-webkit-details-marker { display: none; }
.m-rule > summary::after {
  content: ''; margin-left: auto; width: 7px; height: 7px; margin-right: 3px;
  border-right: 2px solid var(--ink-4); border-bottom: 2px solid var(--ink-4);
  transform: rotate(45deg); transition: transform .18s ease;
}
.m-rule[open] > summary::after { transform: rotate(-135deg); }
.m-rule-body {
  padding: 0 14px 15px; font-size: 13.5px; line-height: 1.85; color: var(--ink-2);
}
.m-rule-body ol, .m-rule-body ul { margin: 0; padding-left: 18px; }
.m-rule-body p { margin: 0 0 9px; }
.m-rule-body strong { color: var(--ink); }
.m-rule-body.danger { color: #7d1b16; }

/* 规则页顶上的「核心数字」：先给人结论，再让人决定要不要展开看细则 */
.m-rule-key {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px;
  padding: 12px 6px; margin-bottom: 12px; text-align: center;
}
.m-rule-key b { display: block; font-size: 17px; font-weight: 900; letter-spacing: -.02em; }
.m-rule-key b.coral { color: var(--coral); }
.m-rule-key b.gold { color: var(--gold-ink); }
.m-rule-key span { font-size: 10.5px; color: var(--ink-3); }

/* 规则页的「资金四步」：必须**竖向**排。
   一开始顺手用了发布页的 .m-steps，那是个横向进度条（flex:1 + 居中），
   四段文字挤在一行里直接成了乱码 —— 横向的进度条只装得下两个字。 */
.m-flow { display: grid; gap: 7px; margin-bottom: 12px; }
.m-flow > div {
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: 10px 12px; border-left: 3px solid var(--brand);
}
.m-flow b { display: block; font-size: 13px; color: var(--ink); margin-bottom: 2px; }
.m-flow span { font-size: 12.5px; color: var(--ink-2); line-height: 1.65; }

/* 规则页里的信用分表：两列就够，手机上三列一定挤 */
.m-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.m-tbl td { padding: 7px 0; border-bottom: 1px solid var(--line); }
.m-tbl td:last-child { text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }
.m-tbl td.ok { color: var(--ok); }
.m-tbl td.warn { color: var(--warn); }
.m-tbl td.bad { color: var(--danger); }

/* ======================================================================
   发布向导（13 步）—— App 端
   ----------------------------------------------------------------------
   为什么是「一张表单 + JS 分步显示」而不是 13 个页面：
   App 的发布本来就不该有 13 次页面跳转（每次都要重新请求、还要担心草稿丢），
   而且服务端只需要一个 POST 入口。JS 一挂，13 步平铺成一张长表单，照样能发。

   ⚠️ 步骤的收起**必须**写成 `.wiz-js .wz-step:not(.is-on){display:none}`。
   写成 `.wz-step{display:none}` 的话，JS 一旦加载失败整页就是空白 ——
   而「页面空白」是最难被归因的故障（用户只会说「打不开」）。
   ====================================================================== */
.wz-head {
  position: sticky; top: calc(var(--safe-t) + var(--top-h)); z-index: 30;
  margin: -10px -12px 10px; padding: 10px 12px 8px;
  background: rgba(250, 249, 247, .94);
  backdrop-filter: saturate(150%) blur(12px);
  -webkit-backdrop-filter: saturate(150%) blur(12px);
}
.wz-bar { display: flex; gap: 3px; margin-bottom: 7px; }
.wz-seg {
  flex: 1; height: 4px; border-radius: var(--r-pill);
  background: var(--line-2); transition: background .2s;
}
.wz-seg.is-done { background: var(--brand-soft); }
.wz-seg.is-on { background: var(--coral); }
.wz-meta { display: flex; align-items: baseline; gap: 8px; }
.wz-meta b { font-size: 13px; font-weight: 900; color: var(--ink); }
.wz-name { font-size: 12px; color: var(--ink-3); }

.wz-step {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 16px 14px;
}
.wiz-js .wz-step:not(.is-on) { display: none; }
/* 被拦下的那一步描一圈红 —— 用户点「下一步」被拒时，得看得出是哪一屏的问题 */
.wz-step.is-bad { box-shadow: 0 0 0 3px var(--danger-soft), var(--sh-1); }

.wz-t { font-size: 20px; font-weight: 900; letter-spacing: -.025em; margin: 0 0 8px; }
.wz-sub { font-size: 13px; color: var(--ink-2); line-height: 1.7; margin: 0 0 16px; }
.wz-sub b { color: var(--ink); }
.wz-sechead {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  margin: 16px 2px 8px;
}
.wz-sechead b { font-size: 13.5px; font-weight: 900; }

/* 第 1 步：两张大的二选一卡片。单选要「一眼看得出这是在做选择」，
   所以给它卡片尺寸，而不是两个小圆点。 */
.wz-two { display: grid; gap: 10px; }
.wz-two label { display: block; }
.wz-two input { position: absolute; opacity: 0; pointer-events: none; }
.wz-two-in {
  display: block; padding: 14px; border-radius: var(--r);
  background: var(--surface-2); border: 1.5px solid transparent;
  transition: border-color .15s, background .15s;
}
.wz-two-in .ic { width: 26px; height: 26px; color: var(--brand-deep); margin-bottom: 8px; }
.wz-two-in b { display: block; font-size: 16px; font-weight: 900; margin-bottom: 3px; }
.wz-two-in em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); line-height: 1.6; }
.wz-two input:checked + .wz-two-in {
  background: var(--brand-tint); border-color: var(--brand);
}

/* 第 7 / 12 步：一排单选（可横可纵） */
.wz-opts { display: flex; flex-wrap: wrap; gap: 8px; }
.wz-opts-col { flex-direction: column; }
.wz-opts label { flex: 1 1 46%; }
.wz-opts label { position: relative; }
.wz-opts input { position: absolute; opacity: 0; pointer-events: none; }
.wz-opts span {
  display: block; text-align: center; padding: 11px 6px;
  border-radius: var(--r-sm); background: var(--surface-2);
  border: 1.5px solid transparent;
  font-size: 13.5px; font-weight: 700; color: var(--ink-2);
}
.wz-opts input:checked + span {
  background: var(--brand-tint); color: var(--brand-deep); border-color: var(--brand);
}

/* 第 3 步：素材多选（在 m-pick 基础上加一个「已选上限」与命中角标） */
.m-pick-multi { grid-template-columns: repeat(3, 1fr); }
.m-pick-multi input[disabled] + .ph { opacity: .34; }
.m-pick label.is-top .ph { box-shadow: inset 0 0 0 2.5px var(--coral); }
.wz-hit {
  position: absolute; top: 5px; left: 5px;
  padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--lime); color: #3f4d0a;
  font-size: 10px; font-weight: 900;
}
.wz-preview { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 9px; }
.wz-preview img {
  width: 62px; height: 62px; object-fit: cover;
  border-radius: var(--r-xs); box-shadow: var(--sh-1);
}

/* 第 4 / 8 / 10 步：横向可滑的胶囊 */
.wz-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.wz-chips-row { align-items: center; }
.wz-chip {
  display: inline-flex; align-items: center;
  padding: 7px 13px; border: 0; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700; font-family: inherit; cursor: pointer;
}
.wz-chip:active { transform: scale(.96); }
.wz-chip.is-on { background: var(--brand-soft); color: var(--brand-deep); }
/* 可勾选的胶囊：checkbox 藏在 label 里，点整颗胶囊即可 */
.wz-chk { position: relative; }
.wz-chk input { position: absolute; opacity: 0; pointer-events: none; }
.wz-chk span {
  display: inline-flex; padding: 7px 13px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700;
}
.wz-chk input:checked + span { background: var(--brand-soft); color: var(--brand-deep); }
.wz-chk input[disabled] + span { opacity: .4; }

/* 第 5 步：填词模板卡片 */
.wz-tpls { display: grid; gap: 8px; }
.wz-tpl {
  display: flex; align-items: flex-start; gap: 10px; text-align: left;
  padding: 11px 12px; border: 0; border-radius: var(--r-sm);
  background: var(--surface-2); font-family: inherit; cursor: pointer;
}
.wz-tpl .ic { width: 20px; height: 20px; color: var(--brand-deep); flex: none; margin-top: 1px; }
.wz-tpl b { display: block; font-size: 13.5px; font-weight: 800; color: var(--ink); }
.wz-tpl em { display: block; font-style: normal; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }

/* 第 6 步：建议出价 */
.wz-sug-head { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.wz-sug-head .ic { width: 17px; height: 17px; color: var(--brand); }
.wz-sug-head b { font-size: 13.5px; }
.wz-sug-price { display: flex; align-items: baseline; gap: 7px; }
.wz-sug-price b {
  font-size: 26px; font-weight: 900; color: var(--coral);
  font-variant-numeric: tabular-nums;
}
.wz-sug-price em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.wz-basis { margin: 8px 0 0; padding-left: 16px; }
.wz-basis li { font-size: 11.5px; color: var(--ink-2); line-height: 1.75; }
.wz-sug-btns { display: flex; gap: 8px; margin-top: 10px; }

/* 第 6 / 12 / 13 步：算钱的键值行 */
.wz-kv {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 5px 0; font-size: 13px; color: var(--ink-2);
}
.wz-kv + .wz-kv { border-top: 1px dashed var(--line); }
.wz-kv b { font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.wz-kv.is-soft { color: var(--ink-3); }
.wz-kv.is-soft b { color: var(--ink-2); }
.wz-kv.is-total { border-top: 1.5px solid var(--line-2); margin-top: 4px; padding-top: 9px; }
.wz-kv.is-total b { font-size: 20px; color: var(--coral); }
.wz-pay {
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: 10px 12px; margin-bottom: 12px;
}
.wz-short {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-xs);
  background: var(--danger-soft); color: var(--danger);
  font-size: 12px; font-weight: 700; line-height: 1.6;
}

/* 第 8 步：滑动条 */
.wz-range { width: 100%; margin: 10px 0 0; accent-color: var(--brand); height: 28px; }

/* 第 9 步：常用地址 + 两列栅格 */
.wz-addrs { display: grid; gap: 8px; }
.wz-addr { display: block; position: relative; }
.wz-addr input { position: absolute; opacity: 0; pointer-events: none; }
.wz-addr-in {
  display: block; padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1.5px solid transparent;
}
.wz-addr input:checked + .wz-addr-in { background: var(--brand-tint); border-color: var(--brand); }
.wz-addr-top { display: flex; align-items: center; gap: 7px; margin-bottom: 3px; }
.wz-addr-top b { font-size: 13.5px; }
.wz-mono { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.wz-addr-in em { display: block; font-style: normal; font-size: 11.5px; color: var(--ink-3); line-height: 1.6; }
.wz-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.wz-grid2 .m-field { margin-bottom: 12px; }

/* 第 10 步：已选来源地 */
.wz-picked {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 9px 10px; border-radius: var(--r-sm); background: var(--surface-2);
  margin-bottom: 4px; min-height: 40px;
}

/* 第 11 步：加急开关 */
.wz-urgent { display: block; position: relative; }
.wz-urgent input { position: absolute; opacity: 0; pointer-events: none; }
.wz-urgent-in {
  display: block; padding: 13px; border-radius: var(--r);
  background: var(--coral-soft); border: 1.5px solid transparent;
}
.wz-urgent input:checked + .wz-urgent-in { border-color: var(--coral); background: #ffe2d8; }
.wz-urgent-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.wz-urgent-top b { font-size: 14.5px; font-weight: 900; }
.wz-urgent-in em {
  display: block; font-style: normal; font-size: 12px; color: var(--ink-2);
  line-height: 1.7; margin-top: 6px;
}
.wz-urgent-calc {
  display: block; margin-top: 8px; font-size: 12.5px; font-weight: 800; color: var(--coral-deep);
  font-variant-numeric: tabular-nums;
}

/* 第 13 步：不可退提醒 + 确认 */
.wz-warn {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 11px 12px; border-radius: var(--r-sm);
  background: var(--warn-soft); color: #7a4c07;
  font-size: 12.5px; line-height: 1.7;
}
.wz-warn .ic { width: 17px; height: 17px; flex: none; margin-top: 1px; }
.wz-agree {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 14px 0 0; font-size: 13px; font-weight: 700; color: var(--ink); line-height: 1.6;
}

/* 吸底导航：必须坐在五格 tabbar **上面**，否则两者会叠在一起，
   而「下一步」被 tabbar 盖住是致命的（用户以为按钮坏了）。 */
.wz-nav {
  position: fixed; left: 0; right: 0; z-index: 45;
  bottom: calc(var(--tab-h) + var(--safe-b));
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px;
  background: rgba(255, 255, 255, .95);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  box-shadow: 0 -6px 18px -12px rgba(26, 26, 29, .5);
}
.wz-dots { flex: 1; display: flex; align-items: center; justify-content: center; gap: 4px; }
.wz-dot {
  width: 5px; height: 5px; border-radius: var(--r-pill);
  background: var(--line-2); transition: transform .18s, background .18s;
}
.wz-dot.is-done { background: var(--brand-soft); }
.wz-dot.is-on { background: var(--coral); transform: scale(1.7); }
/* 表单底部要给吸底导航留位置，否则最后一行会被压在导航下面点不到 */
.m-main.is-wiz { padding-bottom: calc(var(--tab-h) + var(--safe-b) + 96px); }

/* ==================================================================
   圆梦全览：商榷 / 行动 / 交付 / 验收 四个区块（2026-09-21 C 项）
   ================================================================== */
/* 聊天区做成「有界的」「能滚的」一块，而不是把整页撑长 ——
   订单页里消息只是其中一段，撑长了会把验收按钮顶到一屏之外。 */
.m-talk { background: var(--surface-2); border-radius: var(--r); padding: 12px; margin-top: 10px; }
.m-talk-scroll { max-height: 300px; overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding-right: 2px; }
.m-talk-empty { text-align: center; font-size: 12.5px; color: var(--ink-3); padding: 20px 8px; line-height: 1.7; }
.m-talk .m-bubbles { gap: 9px; }
.m-talk .m-msg .bubble { background: var(--surface); }

/* 发消息 / 发文件的一行工具条 */
.m-compose { margin-top: 10px; display: grid; gap: 7px; }
.m-compose-row { display: flex; gap: 7px; align-items: center; }
.m-compose-row .m-textarea { flex: 1; min-height: 40px; }
.m-attach-btn {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--brand-deep); display: grid; place-items: center;
  cursor: pointer; box-shadow: var(--sh-1);
}
.m-attach-btn .ic { width: 19px; height: 19px; }
.m-attach-name { font-size: 11.5px; color: var(--brand-deep); font-weight: 700; word-break: break-all; }
.m-send-sm {
  flex-shrink: 0; height: 40px; padding: 0 15px; border: 0; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; font-size: 13.5px; font-weight: 800; cursor: pointer;
}
.m-send-sm[disabled] { opacity: .4; }

/* 消息里的附件：文件卡片 / 图片 / 视频 / 链接 */
/* `.m-mediabox` 是「图片/视频/文件 + 下面一行说明」这个竖排小盒子。
   它**刻意不套 .bubble**：绿色气泡底上放一张图会显得脏，而且图片宽度会被气泡 padding 挤小。 */
.m-mediabox { display: grid; gap: 5px; max-width: 210px; }
.m-mediabox .cap { font-size: 12.5px; line-height: 1.6; color: var(--ink-2); word-break: break-word; }
.m-msg.me .m-mediabox .cap { text-align: right; }
.m-filecard {
  display: flex; gap: 8px; align-items: center; padding: var(--sp-sm) var(--sp-md);
  background: var(--surface); border-radius: var(--r-sm);
}
.m-mediabox .m-filecard { background: var(--surface); box-shadow: var(--sh-1); }
.m-filecard .ic { width: 22px; height: 22px; flex-shrink: 0; color: var(--brand-deep); }
.m-filecard .meta { min-width: 0; }
.m-filecard .meta b { display: block; font-size: 12.5px; font-weight: 700; color: var(--ink); word-break: break-all; }
.m-filecard .meta span { font-size: 10.5px; color: var(--ink-3); }
.m-mediabox img.shot, .m-mediabox video.shot {
  max-width: 100%; border-radius: var(--r-sm); display: block;
}
.m-linkcard {
  display: flex; gap: 5px; align-items: flex-start;
  font-size: 12.5px; word-break: break-all; text-decoration: underline;
}
.m-linkcard .ic { width: 14px; height: 14px; flex-shrink: 0; margin-top: 2px; }

/* 区块小标题（带图标和一句说明） */
.m-sec-head { display: flex; align-items: center; gap: 6px; margin: 16px 0 2px; }
.m-sec-head .ic { width: 15px; height: 15px; color: var(--brand); }
.m-sec-head b { font-size: 14.5px; font-weight: 800; color: var(--ink); }
.m-sec-tip { font-size: 12px; color: var(--ink-3); line-height: 1.7; margin: 2px 0 6px; }

/* ----------------------------------------------------------------------
   消息页：可折叠的通知分区（活动 / 交易 / 上新）—— 2026-09-23 新增
   ----------------------------------------------------------------------
   为什么用 <details> 而不是自己写 JS 开合：它天生就是「无 JS 也能开合」的控件，
   键盘 Tab / 回车、读屏软件全都认。自己写的那种一旦 JS 挂了或没加载完，
   分区就彻底打不开 —— 用户连里面有什么都看不到。
   默认收起的原因见 chat_list.html 顶部那段注释（一句话：别把要紧的聊天挤出屏幕）。
   ⚠️ 收起 ≠ 假装没有：未读时标题行上有点亮的 .m-dot。
   ---------------------------------------------------------------------- */
.m-fold {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); margin-bottom: 9px; overflow: hidden;
}
.m-fold-head {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 14px; cursor: pointer; list-style: none;
  font-size: 14.5px; font-weight: 800; color: var(--ink);
  /* 点击热区够大（≈46px 高），拇指点得中；也让「点标题行就展开」这件事符合直觉 */
  min-height: 46px;
}
/* 去掉 Safari / Chrome 自带的那个三角 —— 我们自己有会转的箭头 */
.m-fold-head::-webkit-details-marker { display: none; }
.m-fold-head .ic { width: 17px; height: 17px; color: var(--brand); flex-shrink: 0; }
.m-fold-n { font-size: 11.5px; font-weight: 700; color: var(--ink-3); }
.m-fold-caret { color: var(--ink-4); transition: transform .18s var(--ease); }
.m-fold[open] .m-fold-caret { transform: rotate(180deg); }
.m-fold-body { padding: 0 14px 13px; }
.m-fold-more {
  display: block; margin-top: 10px; font-size: 12.5px; font-weight: 700;
  color: var(--brand-deep); text-decoration: none;
}

/* 未读红点：**只表示「那边有东西」，不带数字**。
   数字留给真人对话（会话行上的 .badge）—— 把「3 条公告没看」和
   「有人找你说话」显示成同一个数字，用户就分不出哪件该先办。 */
.m-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: var(--r-pill);
  background: var(--coral); flex-shrink: 0;
}

/* ----------------------------------------------------------------------
   顶部「新消息」提示条 —— 2026-09-23 新增
   ----------------------------------------------------------------------
   派总要求：「任何界面都能收到消息，并且 APP 顶部有新信息提示」。
   线上是 http://IP:8080（非安全上下文）⇒ Service Worker / Web Push 用不了，
   只能自己轮询 + 弹这条看得懂、点得动的提示（详见 static/js/live.js）。
   ⚠️ `top` 必须含 `--top-h`（顶栏高度）。漏了的话提示条会被压在固定顶栏底下，
      表现是「看得见但点不动」，而且零报错 —— 2026-09-23 flash-stack 踩过同一个坑。
   ---------------------------------------------------------------------- */
.live-banner {
  position: fixed; top: calc(var(--safe-t) + var(--top-h) + 6px);
  left: 12px; right: 12px; z-index: 95;
  max-width: 696px; margin: 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px; border-radius: var(--r);
  background: var(--jade); color: #fff; text-decoration: none;
  box-shadow: var(--sh-2);
  opacity: 0; transform: translateY(-8px); pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease);
}
.live-banner.is-in { opacity: 1; transform: translateY(0); pointer-events: auto; }
.live-banner-av {
  width: 30px; height: 30px; border-radius: var(--r-pill); flex-shrink: 0;
  display: grid; place-items: center; font-weight: 900; font-size: 13px;
  background: rgba(255, 255, 255, .16);
}
.live-banner-tx { display: grid; gap: 1px; min-width: 0; flex: 1; }
.live-banner-tx b { font-size: 13.5px; font-weight: 800; }
.live-banner-tx span {
  font-size: 12px; color: rgba(255, 255, 255, .8);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.live-banner-go { margin-left: auto; font-size: 12.5px; font-weight: 700; color: var(--lime); white-space: nowrap; }

/* 交付内容 / 验收依据这类「一栏一栏」的信息 */
.m-kv { display: grid; gap: 1px; background: var(--line-2); border-radius: var(--r-sm); overflow: hidden; }
.m-kv > div { display: flex; gap: 10px; background: var(--surface); padding: 9px 11px; font-size: 13px; }
.m-kv .k { color: var(--ink-3); flex-shrink: 0; width: 76px; }
.m-kv .v { color: var(--ink); font-weight: 700; word-break: break-all; flex: 1; }
.m-kv .v.copyable { color: var(--brand-deep); }

/* 验收不过：一块红的，把依据和诉求都摆出来 */
.m-reject {
  background: var(--danger-soft); border-radius: var(--r-sm); padding: 11px 12px;
  font-size: 12.5px; line-height: 1.75; color: var(--ink); margin-top: 8px;
}
.m-reject b { display: block; font-size: 12px; color: var(--danger); margin-bottom: 3px; }
.m-reject + .m-reject { margin-top: 6px; }

/* 单选项做成卡片（服务费承担方 / 评价星级都用它） */
.m-radio-row { display: flex; gap: 7px; flex-wrap: wrap; }
.m-radio-row label {
  flex: 1 1 30%; text-align: center; padding: 9px 6px; border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 12.5px; font-weight: 700; color: var(--ink-2); cursor: pointer;
}
.m-radio-row input { position: absolute; opacity: 0; pointer-events: none; }
.m-radio-row input:checked + span { color: var(--brand-deep); }
.m-radio-row label:has(input:checked) { background: var(--brand-soft); box-shadow: inset 0 0 0 1.5px var(--brand); }

/* 「进度条上这一步在干什么」的一句话说明 */
.m-stagenote {
  display: flex; gap: 7px; align-items: flex-start;
  background: var(--brand-soft); color: var(--brand-deep);
  border-radius: var(--r-sm); padding: 9px 11px; font-size: 12.5px; line-height: 1.7; margin-top: 10px;
}
.m-stagenote .ic { width: 15px; height: 15px; flex-shrink: 0; margin-top: 2px; }

/* 平板 / 桌面预览（手机端站点被电脑打开时别拉得太宽） */
@media (min-width: 720px) {
  .m-tabbar, .m-actions, .m-main, .m-top-in, .flash-stack, .wz-nav { max-width: 720px; margin-left: auto; margin-right: auto; }
  .m-tabbar, .m-actions { box-shadow: var(--sh-2); border-radius: var(--r-lg) var(--r-lg) 0 0; }
}

/* ======================================================================
   图片轮播（翻页看图）  ——  2026-09-22 新增
   ----------------------------------------------------------------------
   为什么自己写而不引轮播库：一个库 = 一个外网依赖 + 几十 KB，
   而这里要的只是「横着划能翻页」。浏览器自带的 scroll-snap 就能做到：
   手指一划滚一屏、松手自动吸住 —— **而且没有 JS 也能划**。

   手机上**故意不显示左右箭头**：手指直接划就是翻页，箭头只会挡图、还容易误触。
   这跟闲鱼 / 淘宝的详情页是一个口径 —— 只留底部圆点和右下角「2/5」。
   圆点 / 页码同样只在 JS 初始化成功后才显示（容器加 .is-ready），
   所以 JS 挂了也不会露出「点得动但没反应」的死按钮。
   ====================================================================== */
.carousel { position: relative; overflow: hidden; border-radius: var(--r-sm); background: var(--surface-2); }
.carousel-track {
  display: flex; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.carousel-track::-webkit-scrollbar { display: none; }
.carousel-slide { flex: 0 0 100%; margin: 0; scroll-snap-align: center; aspect-ratio: 4 / 3; background: var(--surface-2); }
.carousel-slide img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* 详情页头图：轮播把 m-detail-media 整块填满。
   派总 2026-10-27 截图现场（需求 YM261024934352，1600×734 横图）抓的根因：
   原来 slide 写 `aspect-ratio:auto; height:100%`，而父级 track 高度是 auto
   ⇒ height:100% 对着 auto 解析回落成内容高 = 图片自然比例 168px，
   窗口 476px，底下 308px 全是底色 + 渐变遮罩（用户看到「图居上、下面一片灰」）。
   小圈子图集没这个问题，因为 .pc-gal-slide 自己带 1:1.3 画幅 —— 这里照抄同一条口径。 */
.m-detail-media .carousel { position: absolute; inset: 0; border-radius: 0; }
.m-detail-media .carousel-slide { aspect-ratio: 1 / 1.3; height: auto; }

.carousel-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 34px; height: 34px; padding: 0; border: 0; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .93); color: var(--ink);
  display: none; align-items: center; justify-content: center;
  box-shadow: var(--sh-1); cursor: pointer;
}
.carousel-nav.prev { left: 10px; }
.carousel-nav.next { right: 10px; }
.carousel-nav.prev .ic { transform: scaleX(-1); }
.carousel-nav[disabled] { opacity: .3; cursor: default; }

/* z-index 给到 3：详情页头图底部有一层 .shade 渐变遮罩，不能让它盖住圆点和页码 */
.carousel-count {
  position: absolute; right: 10px; bottom: 10px; z-index: 3; display: none;
  padding: 3px 10px; border-radius: var(--r-pill);
  background: rgba(6, 37, 33, .6); color: #fff;
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
}
.carousel-dots {
  position: absolute; left: 0; right: 0; bottom: 11px; z-index: 3;
  display: none; justify-content: center; gap: 6px;
}
.carousel-dot {
  flex: none; width: 6px; height: 6px; padding: 0; border: 0;
  border-radius: var(--r-pill); background: rgba(255, 255, 255, .78); cursor: pointer;
  box-shadow: 0 0 0 1px rgba(6, 37, 33, .2);   /* 浅色图上白点会隐身，描一圈细边 */
  transition: width .18s ease, background .18s ease;
}
.carousel-dot.is-on { width: 16px; background: var(--brand); }

.carousel.is-ready .carousel-count { display: block; }
.carousel.is-ready .carousel-dots { display: flex; }
.carousel.is-single .carousel-count,
.carousel.is-single .carousel-dots { display: none !important; }

/* ======================================================================
   发布向导「附图」抽屉  ——  2026-09-22 改版
   ----------------------------------------------------------------------
   改之前：第 3 步一进来就把备选素材一张张全平铺，一屏全是图，
   还没填正文就先被图片淹了（派总原话：「备选图片不用一股脑全部展示」）。
   改之后：默认只露一个「附图」按钮，点开才是两个动作 —— 推荐图片 / 上传图片。
   用 <details> 而不是 JS 弹窗：**没有 JS 也能开合**，
   不会出现「按钮在那儿、点了没反应」这种半死状态。
   ====================================================================== */
.att {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); overflow: hidden;
}
.att > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  padding: 15px; font-size: 15.5px; font-weight: 700;
  min-height: 52px;                       /* 手机上低于 44px 就很难点中 */
}
.att > summary::-webkit-details-marker { display: none; }
.att > summary .ic { width: 20px; height: 20px; color: var(--brand-deep); flex: none; }
.att-count { margin-left: auto; font-size: 12.5px; font-weight: 700; color: var(--ink-3); }
.att-count.is-on { color: var(--brand-deep); }

/* ⚠️ 铁律：<details> 关着的时候，里面 position:absolute 的浮层**仍然参与排版**，
   会把页面撑高、还可能挡住别的东西 ⇒ 关着时必须整块 display:none。 */
.att:not([open]) > .att-body,
.att:not([open]) > .att-panel { display: none; }
.att-body { padding: 0 15px 15px; display: grid; gap: 10px; }
.att-panel { padding: var(--sp-lg) 0 var(--sp-2xs); }

/* 两个动作：一个是 details 的 summary（推荐图片，会展开），一个是 label（上传图片，直接选文件）。
   两者长得必须一样 —— 用户不该看出「这两个是不同的东西」，只看到两个并排的入口。 */
.att-act {
  display: flex; align-items: center; gap: 11px; width: 100%; min-height: 52px;
  padding: 14px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2); cursor: pointer; text-align: left;
}
.att-act:active { background: var(--brand-tint); }
.att-act > .ic { width: 20px; height: 20px; color: var(--brand-deep); flex: none; }
.att-act .tx { flex: 1; min-width: 0; }
.att-act .tx b { display: block; font-size: 15px; font-weight: 700; }
.att-act .tx span { display: block; font-size: 12.5px; font-weight: 400; color: var(--ink-2); }
.att-act .chev { width: 17px; height: 17px; color: var(--ink-4); flex: none; }
.att-sub[open] > .att-act .chev { transform: rotate(180deg); }

/* ==================================================================
   圆梦单六步：方案 / 交付 / 验收（2026-09-24）
   ------------------------------------------------------------------
   起因：以前「行动」和「交付」挤在同一张卡里（同一个区块里既有聊天、
   又有交付表单），需求方看不出圆梦者到底做完没有。现在六步各自成卡，
   每一步有自己的时间戳；而**沟通记录只留一个窗口**，用分隔条分段。
   ================================================================== */

/* 聊天窗里的阶段分隔条：- 以下为交付环节 - */
.talk-sep { display: flex; align-items: center; gap: 9px; margin: 6px 0 2px; }
.talk-sep::before, .talk-sep::after { content: ''; flex: 1; height: 1px; background: var(--line-2); }
.talk-sep span {
  font-size: 10.5px; font-weight: 800; letter-spacing: .04em;
  color: var(--brand-deep); background: var(--brand-tint);
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap;
}

/* -- 方案卡（商榷阶段：圆梦者交、需求方认可）-- */
.m-plan { background: var(--brand-tint); border-radius: var(--r); padding: 13px; margin-top: 10px; }
.m-plan-h { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 900; color: var(--brand-deep); }
.m-plan-h .ic { width: 15px; height: 15px; }
.m-plan-h time { margin-left: auto; font-size: 10.5px; font-weight: 600; color: var(--ink-3); }
.m-plan-body { margin-top: 8px; font-size: 13.5px; line-height: 1.75; color: var(--ink); white-space: pre-wrap; word-break: break-word; }
/* K 波④：附图平铺规则统一收口到下方 .m-plan-imgs 网格（原 flex 78px 规则已删）。 */
.m-plan-agreed { margin-top: 9px; display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 800; color: var(--ok); }
.m-plan-agreed .ic { width: 14px; height: 14px; }
.m-plan-pending { margin-top: 9px; display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 700; color: var(--ink-2); }
.m-plan-pending .ic { width: 14px; height: 14px; }

/* -- 快递三选一：去发货 / 扫码 / 无需快递 -- */
.m-ship-modes label { flex: 1; position: relative; }
.m-ship-modes input { position: absolute; opacity: 0; pointer-events: none; }
.m-ship-modes span {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  padding: 10px 4px; border-radius: var(--r-sm); background: var(--surface-2);
  font-size: 12.5px; font-weight: 800; color: var(--ink-2); cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.m-ship-modes .ic { width: 15px; height: 15px; }
.m-ship-modes input:checked + span { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.m-ship-panel { margin-top: 10px; }
/* ⚠️ 只有 JS 接管之后才折叠面板。没 JS 时三块全铺开 —— 功能一个不少，只是不紧凑。
   反着做（默认折叠、靠 JS 展开）就成了「没 JS 就不能填」，那是不能接受的。 */
.m-ship.is-js .m-ship-panel { display: none; }
.m-ship.is-js .m-ship-panel.on { display: block; }
.m-ship-tip { font-size: 11.5px; line-height: 1.65; color: var(--ink-3); margin: 7px 0 0 2px; }
.m-ship-tip b { color: var(--ink-2); }
.m-gen-row { display: flex; gap: 7px; align-items: flex-end; }
.m-gen-row .m-field { flex: 1; margin-bottom: 0; }

/* -- 如实说明块（例：这个单号是平台生成的参考号）-- */
.m-warn {
  display: flex; gap: 8px; align-items: flex-start;
  background: var(--warn-soft); border-radius: var(--r-sm);
  padding: 10px 11px; margin-top: 8px;
  font-size: 12px; line-height: 1.7; color: var(--ink-2);
}
.m-warn .ic { width: 15px; height: 15px; color: var(--warn); flex-shrink: 0; margin-top: 2px; }
.m-warn b { color: var(--ink); }

/* -- 收发件人 -- */
.m-parties .p { background: var(--surface-2); border-radius: var(--r-sm); padding: 9px 11px; font-size: 12.5px; line-height: 1.65; color: var(--ink-2); }
.m-parties .p b { display: block; font-size: 11px; font-weight: 800; color: var(--ink-3); margin-bottom: 2px; }
.m-parties .p span { display: block; color: var(--ink-3); font-size: 11.5px; }

/* 查快递轨迹（点「查看物流」就地展开）。
   观感照着快递官网来：最新一条高亮、往下越来越淡，用户不用重新学怎么读。 */
.m-track { margin-top: 8px; }
.m-track-box { margin-top: 9px; background: var(--surface-2); border-radius: var(--r-sm); padding: var(--sp-lg); }
.m-track-list { list-style: none; margin: 0; padding: 0; }
.m-track-list li { position: relative; padding: 0 0 11px 16px; font-size: 12.5px; line-height: 1.6; color: var(--ink-3); }
.m-track-list li:last-child { padding-bottom: 0; }
.m-track-list li::before { content: ""; position: absolute; left: 3px; top: 6px; width: 6px; height: 6px; border-radius: 50%; background: var(--line-2); }
.m-track-list li:not(:last-child)::after { content: ""; position: absolute; left: 5px; top: 15px; bottom: 1px; width: 1px; background: var(--line-2); }
.m-track-list li.is-now { color: var(--ink); font-weight: 700; }
.m-track-list li.is-now::before { background: var(--brand); }
.m-track-list li .t { display: block; font-size: 11.5px; font-weight: 400; color: var(--ink-3); }
.m-track-list li.is-now .t { color: var(--brand-deep); }
.m-track-list li .x { display: block; }
.m-track-msg { margin: 0; font-size: 12.5px; line-height: 1.65; color: var(--ink-2); }
.m-track-alt { display: block; margin-top: 9px; padding-top: 9px; border-top: 1px dashed var(--line-2); font-size: 12px; color: var(--brand-deep); }

/* -- 附件清单 -- */
.m-files { display: grid; gap: 7px; }
.m-files .m-filecard { background: var(--surface-2); }

/* -- 验收佐证 -- */
.m-ev { background: var(--surface-2); border-radius: var(--r-sm); padding: 11px 12px; margin-top: 8px; }
.m-ev .hd { font-size: 11.5px; font-weight: 800; color: var(--ink-3); margin-bottom: 6px; }
.m-ev .tx { font-size: 13px; line-height: 1.7; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }

/* 扫码取景框 */
.m-scan { margin-top: 9px; }
.m-scan video { width: 100%; border-radius: var(--r-sm); background: #000; display: block; }
.m-scan canvas { display: none; }

/* ======================================================================
   圈子（社区）· 手机端
   ----------------------------------------------------------------------
   形态照得物社区：双列瀑布流（图片封面 + 标题，高度随图自适应）
   + 顶部一排圈子 + 最新/热门 + 右下角点赞。
   ---------------------------------------------------------------------- */
.pc-head { display: flex; align-items: flex-end; gap: 10px; margin: 2px 0 10px; }
.pc-head h1 { margin: 0; font-size: 21px; letter-spacing: .5px; }
.pc-head p { margin: 3px 0 0; font-size: 12px; color: var(--ink-3); }
.pc-head > div { flex: 1; min-width: 0; }
.pc-new {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 7px 12px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; font-size: 12.5px; font-weight: 800;
  flex-shrink: 0;
}

/* 一排圈子（横滑；得物的「垂直细分圈子」那一层）
   2026-09-30（派总 W3）：吸顶 —— 刷瀑布流时随时能换圈子（小红书同款）。
   ⚠️ top 必须含 --top-h（铁律 19 同源）；左右负 margin 把底色铺满整行，
   不然滚动时卡片会从两侧 12px 的缝隙里穿出来。 */
/* 派总 2026-10-26（与 .m-menubar 同一口径）：二级（全部 + 官方圈）可钉住，
   上滑时收进顶栏背后、任意深度轻微下滑就带回来（显隐见 .is-nav-hidden）。
   左右负 margin 铺满整行，滚动时卡片不会从两侧 12px 的缝隙里穿出来。 */
.pc-menubar {
  position: relative; z-index: 25;
  background: var(--paper); margin: 0 -12px; padding: 2px 12px 4px;
}
.m-main.is-home > .pc-menubar {
  position: sticky; top: calc(var(--safe-t) + var(--top-h)); z-index: 26;
  transition: transform .2s cubic-bezier(.22,.61,.36,1);
}
.pc-cats {
  display: flex; gap: 6px; overflow-x: auto; padding: 0;
  margin: 0; background: transparent;
  position: relative;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.pc-cats::-webkit-scrollbar { display: none; }
/* 与上面的 .m-ftab **同尺寸同手感**（派总 2026-09-24 第 H 波）——
   只换掉颜色相关的部分：选中态仍是深青 jade（原样保留）。
   ⚠️ 盒模型四个键必须与 .m-ftab 逐字相同（见那上面的说明与单测）。 */
.pc-cat {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-height: 27px; padding: 4px 10px; border-radius: var(--r-pill); flex-shrink: 0;
  background: var(--surface); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700;
  box-shadow: var(--sh-1);
}
/* 最新 / 热门 —— T17③：这排是**三级**标签；2026-10-26 起跟二级一起钉住/收起，
   见下方 .m-navtabs 与 .is-nav-hidden 那两条。 */
.pc-tabs { display: flex; gap: 14px; margin: 8px 2px 10px; align-items: center; }
/* 需求池（小青柠）页的「最新/热门」快捷排：吸顶容器下面只留 4px，
   上面自己给 8px 呼吸；下面 10px 呼应小圈子页 tabs 与瀑布流的间距。 */
.feed-sort-tabs { margin: 8px 2px 10px; }

/* T29②（派总 2026-10-29「首页：原位置加上定位功能」）：快捷行最右端的定位胶囊。
   形状由两端共用的 loc.css `.lc-trigger` 给（不许在这儿重画一遍，重画就会分家 ——
   上一次定位散在七八处、三个入口一起失效就是这么来的）。这里只管两件**排版**上的事：
     · margin-left:auto —— 标签靠左、胶囊单独居右（派总 2026-09-30 第 2 条）；
     · max-width + 省略号 —— 城市名最长能到「巴音郭楞蒙古自治州」这种长度，
       不限宽就会把左边的「最新/热门」挤到换行。 */
.m-loc-row { margin-left: auto; flex-shrink: 0; max-width: 116px; }
.m-loc-row span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 派总 2026-10-26：三级标签（最新/附近/热门 + 定位）也可钉住 ——
   跟二级一起收进顶栏背后、一起带回来。用 padding 顶替原来的 margin，
   纸色底于是能整条覆盖（内容从标签下面滑过时不会露出来）；
   top 里的 --m-nav2-h 由 app.js 的 initHomeNavReveal 量出来（二级高度随板块不同）。 */
.m-main.is-home .m-navtabs {
  position: sticky;
  top: calc(var(--safe-t) + var(--top-h) + var(--m-nav2-h, 34px));
  z-index: 25;
  margin: 0;
  padding: 8px 2px 10px;
  background: var(--paper);
  transition: transform .2s cubic-bezier(.22,.61,.36,1);
}
/* 底色铺满整行（主内容左右各 12px 内边距，不然卡片会从缝里露出来） */
.m-main.is-home .m-navtabs::before {
  content: ''; position: absolute; left: -12px; right: -12px; top: 0; bottom: 0;
  background: var(--paper); z-index: -1;
}
/* 收起姿态：两块一起钻到一级卡片（顶栏）背后 —— 顶栏不透明、层级更高，所以看不见。
   平移量按「自己 + 下面那块」算：二级只挪自己，三级要连二级一起挪。 */
.m-main.is-nav-hidden > .m-menubar,
.m-main.is-nav-hidden > .pc-menubar {
  transform: translateY(calc(-1 * var(--m-nav2-h, 34px) - 2px));
  pointer-events: none;
}
.m-main.is-nav-hidden .m-navtabs {
  transform: translateY(calc(-1 * (var(--m-nav2-h, 34px) + var(--m-nav3-h, 41px)) - 2px));
  pointer-events: none;
}
.pc-tab { font-size: 13.5px; font-weight: 800; color: var(--ink-3); padding: 3px 0; }
.pc-tab.on { color: var(--ink); }
.pc-tab.on::after { content: ''; display: block; height: 3px; margin-top: 2px; border-radius: 2px; background: var(--brand); }
/* K 波①（派总 2026-10-17）：「附近」同城没数据、回落全部最新时的一行小提示 */
.pc-near-tip { margin: 0 2px 10px; font-size: 12.5px; color: var(--ink-4); }
/* T18 优化①e（派总 2026-10-26）：点正文里的 #话题 落进列表时的「正在筛哪个话题」横幅 */
.pc-topicbar { display: flex; align-items: center; gap: 8px; margin: 0 2px 10px;
  padding: 7px 10px; border-radius: var(--r-pill);
  background: var(--brand-soft, #e6f7f4); color: var(--brand-deep, #007d6d); }
.pc-topicbar b { font-size: 13px; font-weight: 800; }
.pc-topicbar a { margin-left: auto; font-size: 12px; font-weight: 700;
  color: var(--brand-deep, #007d6d); text-decoration: underline; }

/* 双列瀑布流：两列各自往下堆（列优先），列内卡片高度互不影响 */
.pc-feed { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; align-items: start; }
.pc-col { display: grid; gap: 9px; align-content: start; }

/* —— 一张动态卡 —— */
.pc-card {
  position: relative; background: var(--surface);
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--sh-1);
}
.pc-card-link { position: absolute; inset: 0; z-index: 1; }
.pc-card-media { position: relative; background: var(--surface-2); }
/* T51②（派总 2026-10-30）：图片没解码完（慢网 / 懒加载 / 坏图）别再露一片死底色 ——
   垫一块「插画牌」：柔和青绿-米色渐变 + 居中相框图形（内联 data-URI，不引外网资源）。
   坑（截图实测）：::before 带 position:absolute 是**定位元素**，按绘制顺序画在
   普通流的 img/video **之上**——图加载完了也被它盖住。所以 img/video 必须
   position:relative 提成定位层，之后才按 DOM 顺序画在伪元素上面；
   object-fit:cover 的 img 不透明，盖住即走，两者不会叠影。 */
.pc-card-media::before {
  content: ""; position: absolute; inset: 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237fa39b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='3'/%3E%3Ccircle cx='8.7' cy='8.7' r='1.7'/%3E%3Cpath d='M21 15.5 15.5 10 5 20.5'/%3E%3C/svg%3E") center 42%/44px 44px no-repeat,
    radial-gradient(circle at 82% 16%, rgba(0, 189, 166, .10) 0 22%, transparent 23%),
    linear-gradient(165deg, #eef6f3 0%, #f5efe4 80%);
}
/* X③：图文帖缩略图统一竖版 3:4（视频帖本就是 3:4） */
/* 派总 2026-10-12 第 ⑨ 条：所有上传图片显示形式统一 —— 上下居中（contain，不裁切），
   与详情页画廊一致；多图走画廊横向滑动（见 .pc-gallery / carousel.js）。
   T51②：img 自身不涂底色 —— 元素背景会在图片数据到达前就画出来、把 ::before
   插画牌整个盖死，占位就永远看不见了；底色职责整体交给 ::before。 */
.pc-card-media img { position: relative; width: 100%; display: block; aspect-ratio: 3 / 4; object-fit: cover; }
/* 视频帖封面（2026-09-24 派总：圈子主页视频卡撑得超高）：video 元素会按
   原始分辨率自然铺高，瀑布流里能顶出好几屏 —— 统一压成 3:4 封面裁切。 */
.pc-card-media video {
  position: relative;
  width: 100%; display: block;
  aspect-ratio: 3 / 4; object-fit: cover; background: #101418;
}
.pc-card-kind {
  position: absolute; left: 6px; top: 6px;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: rgba(0, 0, 0, .55); color: #fff; font-size: 10px; font-weight: 800;
}
.pc-card-cover {
  /* X③：无图兜底格同卡片缩略图统一竖版 3:4 */
  aspect-ratio: 3 / 4; display: grid; place-items: center;
  background: linear-gradient(150deg, var(--brand-tint), var(--brand-soft));
  color: var(--brand-deep);
}
.pc-card-cover .stack { display: grid; gap: 4px; justify-items: center; font-size: 12px; }
.pc-card-body { padding: var(--sp-sm) var(--sp-md) var(--sp-md); }
.pc-card-title {
  margin: 0; font-size: 13px; line-height: 1.45; font-weight: 700; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pc-card-circle {
  display: inline-flex; align-items: center; gap: 3px; margin-top: 5px;
  font-size: 10.5px; color: var(--brand-deep); background: var(--brand-tint);
  padding: 2px 7px; border-radius: var(--r-pill); font-weight: 700;
}
.pc-card-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 7px; gap: 6px; }
.pc-card-by { position: relative; z-index: 2; display: flex; align-items: center; gap: 5px; min-width: 0; font-size: 10.5px; color: var(--ink-3); text-decoration: none; }
.pc-card-by b { max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-card-by .av, .pcp-head .av {
  width: 18px; height: 18px; border-radius: var(--r-pill); object-fit: cover; flex-shrink: 0;
  background: var(--brand-soft); color: var(--brand-deep);
  display: grid; place-items: center; font-size: 10px; font-weight: 900; overflow: hidden;
}
.av-lg { width: 38px !important; height: 38px !important; font-size: 15px !important; }


/* 收藏星标：圈子卡与需求卡**共用同一套 m-dc-fav**（派总 2026-10-21 第 1 条：
   位置都在卡片右下角作者行右端，样式/大小/颜色完全一致）。
   旧的右上角 .pc-fav 已随 _post_card 改版删除。 */
/* 详情页互动行的收藏（跟「赞」同一排、同款字重） */
.pcp-fav { position: relative; z-index: 2; margin: 0; }
.pcp-fav button {
  display: inline-flex; align-items: center; gap: 3px;
  border: 0; background: none; padding: 3px 4px; color: var(--ink-3);
  font-size: 11px; font-weight: 800; cursor: pointer;
}
.pcp-fav.on button { color: var(--coral); }   /* L 波④：详情互动行的收藏也统一红实心 */
.pcp-fav.on .ic { fill: currentColor; }
a.pcp-fav { display: inline-flex; align-items: center; gap: 3px; color: var(--ink-3); font-size: 11px; font-weight: 800; text-decoration: none; }
/* 详情页作者头像 / 名字 → 进 TA 的主页 */
.pcp-ava-link { display: flex; flex: none; text-decoration: none; }
.pcp-name-link { color: #0b5a54; text-decoration: none; } /* W⑦：用户名深青 */

/* —— 文字海报（6 套模板；详情页大图与卡片封面共用这些类） —— */
.pc-poster {
  position: relative; display: grid; align-content: center; gap: 8px;
  aspect-ratio: 4 / 5; padding: 18px 16px;
}
.pc-poster b { font-size: 19px; line-height: 1.35; }
.pc-poster span { font-size: 12.5px; line-height: 1.7; opacity: .82; }
.pc-poster i {
  position: absolute; left: 16px; right: 16px; bottom: 12px;
  font-style: normal; font-size: 10.5px; opacity: .65;
}
.pc-poster-mini { aspect-ratio: 16 / 10; padding: 12px; }
.pc-poster-mini b { font-size: 14px; }
.pc-poster-mini span { font-size: 10.5px; }
.pc-poster-full { aspect-ratio: auto; min-height: 300px; margin: 12px 0; border-radius: var(--r-lg); }
.pc-poster-full b { font-size: 24px; }
.pc-poster-full span { font-size: 14.5px; }
/* 模板配色（key 存库，定了别改 —— 见 settings.CIRCLE_POSTER_TEMPLATES 注释） */
.pc-lime { background: linear-gradient(160deg, #d4f14a, #a8e063); color: #123b0e; text-align: center; }
.pc-ink { background: linear-gradient(160deg, #23262b, #0f1114); color: #f4f2ec; }
.pc-paper { background: #d9b98c; color: #3c2e1c; text-align: center; box-shadow: inset 0 0 0 1px #c2a06c; }
.pc-sunset { background: linear-gradient(160deg, #ff8a5c, #ff5470); color: #fff; text-align: center; }
.pc-ocean { background: linear-gradient(160deg, #0e7490, #164e63); color: #eafcff; }
.pc-night { background: linear-gradient(160deg, #1e1b4b, #312e81); color: #e0e7ff; text-align: center; }

/* —— 发帖表单 —— */
.pcn { display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr); }
.pcn-head h1 { margin: 0; font-size: 21px; }
.pcn-head p { margin: 3px 0 0; font-size: 12px; color: var(--ink-3); }
.pcn-kinds { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.pcn-kind {
  display: grid; justify-items: center; gap: 2px; padding: 12px 8px;
  border: 1.5px solid var(--ink-4); border-radius: var(--r-md, 12px);
  font-size: 13px; cursor: pointer; background: var(--surface);
}
.pcn-kind input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-kind span { font-size: 10.5px; color: var(--ink-3); }
.pcn-kind.on { border-color: var(--brand); background: var(--brand-tint); }
.pcn-kind.on b { color: var(--brand-deep); }
.pcn-field { display: grid; gap: 5px; }
.pcn-field > b, .pcn-label { font-size: 12.5px; color: var(--ink-2); }
.pcn-field input[type="text"], .pcn-field input:not([type]), .pcn-field textarea,
.pcn-field input[type="file"] {
  width: 100%; padding: 10px 12px; border: 1px solid var(--ink-4);
  border-radius: var(--r-md, 12px); background: var(--surface);
  font: inherit; font-size: 13.5px;
}
.pcn-field textarea { min-height: 96px; resize: vertical; }
.pcn-hint { font-size: 11px; color: var(--ink-3); }
.pcn-block.is-hide { display: none; }
.pcn-tpls { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.pcn-tpl { display: grid; gap: 4px; cursor: pointer; position: relative; min-width: 0; }
.pcn-tpl input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-tpl > i { font-style: normal; font-size: 11px; color: var(--ink-3); text-align: center; }
.pcn-tpl.on .pc-poster { outline: 2.5px solid var(--brand); outline-offset: 2px; border-radius: 6px; }
.pcn-tpl.on > i { color: var(--brand-deep); font-weight: 800; }
/* 派总 2026-10-25 第 6 条：圈子标签不平铺，改横向可滑动胶囊一行 */
.pcn-circles {
  display: flex; flex-wrap: nowrap; gap: 7px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none; padding: 2px 2px 8px; margin: 0 -2px;
}
.pcn-circles::-webkit-scrollbar { display: none; }
.pcn-circles label { position: relative; cursor: pointer; flex-shrink: 0; }
.pcn-circles input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-circles span {
  display: inline-block; padding: 6px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--ink-4); background: var(--surface);
  font-size: 12.5px; font-weight: 700; color: var(--ink-2);
}
.pcn-circles input:checked + span { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-deep); }

/* —— 谁可以看（T58②）：只给谁看 / 不给谁看 才展开挑人 —— */
.pcn-vis-people { margin: 2px 0 4px; }
.pcn-vis-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pcn-vis-chips:empty { display: none; }
.pcn-vis-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 6px 4px 10px; border-radius: var(--r-pill);
  background: var(--brand-soft); color: var(--brand-deep);
  font-size: 12px; font-weight: 700;
}
.pcn-vis-x {
  border: 0; background: transparent; color: inherit; cursor: pointer;
  font-size: 14px; line-height: 1; padding: 2px 4px; border-radius: 50%;
}
.pcn-vis-search {
  width: 100%; margin-top: 6px; padding: 9px 12px;
  border: 1px solid var(--ink-4); border-radius: var(--r-sm);
  background: var(--surface); font-size: 13px; color: var(--ink);
}
.pcn-vis-hits {
  margin-top: 6px; border: 1px solid var(--ink-4); border-radius: var(--r-sm);
  background: var(--surface); max-height: 216px; overflow-y: auto;
}
.pcn-vis-hit {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 9px 12px; border: 0; border-bottom: 1px solid var(--ink-4);
  background: transparent; text-align: left; cursor: pointer;
}
.pcn-vis-hit:last-child { border-bottom: 0; }
.pcn-vis-hit b { font-size: 13px; color: var(--ink); font-weight: 700; }
.pcn-vis-hit span { font-size: 11.5px; color: var(--ink-3); }
.pcn-vis-empty { padding: 10px 12px; font-size: 12px; color: var(--ink-3); }

/* —— 流水账（8 页） —— */
.cc-nav {
  display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 10px;
  scrollbar-width: none; position: sticky; top: 0; z-index: 3;
  background: var(--paper);
}
.cc-nav::-webkit-scrollbar { display: none; }
.cc-nav a {
  flex-shrink: 0; padding: 4px 10px; border-radius: var(--r-pill);
  font-size: 11.5px; font-weight: 800; color: var(--ink-3);
  background: var(--surface-2); border: 1px solid transparent;
}
.cc-nav a.on { color: var(--brand-deep); background: var(--brand-soft); }
.cc-pages { display: grid; gap: 10px; }
.cc-page {
  background: var(--surface); border-radius: var(--r-lg); padding: 13px 13px 14px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .05);
}
.cc-page-head { display: flex; gap: 9px; align-items: center; }
.cc-no {
  width: 26px; height: 26px; border-radius: var(--r-pill); flex-shrink: 0;
  display: grid; place-items: center; background: var(--brand); color: #fff;
  font-size: 12.5px; font-weight: 900;
}
.cc-no.is-empty { background: var(--ink-4); }
.cc-page-head b { font-size: 14.5px; }
.cc-when { display: block; font-size: 11px; color: var(--ink-3); margin-top: 1px; }
.cc-text { margin: 9px 0 2px; font-size: 13px; line-height: 1.75; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }

/* 流水账确认页（发之前先给看一眼会生成什么） */
/* U 波（2026-10-10 第 8 条）布局重设计：8 步从「一列长条」改成 2 列小卡片，
   一眼能看到全貌；没走到的步骤灰卡 + 「无」，不再是那句长说明。 */
.ccv { background: var(--surface); border-radius: var(--r-lg); padding: 13px; box-shadow: 0 1px 4px rgba(0, 0, 0, .05); }
.ccv-order b { font-size: 14.5px; }
.ccv-order span { display: block; margin-top: 3px; font-size: 11.5px; color: var(--ink-3); }
.ccv-pages { list-style: none; margin: 11px 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.ccv-pages li {
  display: flex; gap: 8px; align-items: center; min-width: 0;
  background: var(--surface-2); border-radius: 10px; padding: 7px 9px;
}
.ccv-pages b { font-size: 12px; }
/* ⚠️ 只圈 div 里的说明行 —— 直接写 `.ccv-pages span` 会连步骤圆圈 .cc-no 一起命中
   （U 波踩过：字号被压到 10.5px、grid 居中失效 ⇒ 数字又小又偏）。 */
.ccv-pages div > span { display: block; font-size: 10.5px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* V 波①（派总 2026-10-10）：圆圈里的数字要看得清——圈放大、字号加大 */
.ccv-pages .cc-no { width: 28px; height: 28px; font-size: 14px; }
/* M 波（派总 2026-10-17）：预览页正文——长文最多 3 行省略，别把双列卡片撑爆 */
.ccv-pages .ccv-text {
  margin: 3px 0 0; font-size: 11px; line-height: 1.5; color: var(--ink-2);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; word-break: break-word;
}
.ccv-pages li.is-empty { opacity: .62; }
.ccv-pages li.is-empty b { color: var(--ink-3); }
.ccv-pages li.is-empty div > span { color: var(--ink-3); font-weight: 700; }

/* —— 图片上的气泡 —— */
.pb-fig { margin: 10px 0 0; }
.pb-stage {
  position: relative; border-radius: var(--r-md, 12px); overflow: hidden;
  background: var(--surface-2);
}
.pb-stage img { width: 100%; display: block; }
.pb-dot {
  position: absolute; transform: translate(-50%, -50%);
  width: 22px; height: 22px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; border: 2px solid #fff;
  display: grid; place-items: center; font-size: 10.5px; font-weight: 900;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3); z-index: 2;
  /* 让它浮在整卡可点层之上（详情页有 <a> 铺底时也不被吃掉） */
  text-decoration: none;
}
.pb-ghost {
  position: absolute; transform: translate(-50%, -50%);
  width: 16px; height: 16px; border-radius: var(--r-pill);
  border: 2px dashed #fff; background: rgba(0, 0, 0, .35); z-index: 2; pointer-events: none;
}
.pb-list { display: grid; gap: 6px; margin-top: 8px; }
.pcp-del button {
  display: inline-flex; align-items: center; gap: 3px;
  border: 0; background: none; padding: 5px 2px;
  color: var(--ink-3); font-size: 12px; font-weight: 700; cursor: pointer;
}
.pcp-del button:active { color: var(--coral-deep); }
.pcp-head { display: flex; gap: 10px; align-items: center; }
.pcp-head-in b { font-size: 14px; }
.pcp-meta { display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.pcp-meta a { color: var(--brand-deep); font-weight: 700; }
.pcp-title { margin: 10px 0 4px; font-size: 19px; line-height: 1.4; }
.pcp-content { font-size: 13.5px; line-height: 1.8; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }
.pcp-imgs { display: grid; gap: 4px; margin-top: 6px; }

/* ── 圈子补丁（2026-09-24 门禁补齐）────────────────────── */
.av-txt { display: inline-flex; align-items: center; justify-content: center; font-weight: 800; color: #fff; letter-spacing: .5px; }
.pcp { position: relative; }

/* ── 圈子第二轮（2026-09-24）：小红书式海报 / 胶囊标注 / 评论赞 / 分享 ────── */
/* 海报朝向：竖版 3:4（主形态）/ 横版 4:3；选择器小样固定 16:10 不受朝向影响 */
.pc-poster.po-v { aspect-ratio: 3 / 4; }
.pc-poster.po-h { aspect-ratio: 4 / 3; }
.pc-poster.pc-poster-mini { aspect-ratio: 16 / 10 !important; }

/* 六款小红书式模板（纯 CSS：底色 + 角标装饰，不生成图片） */
.pc-poster.pc-cream { background: linear-gradient(160deg,#fdf9ef,#f6ecd6); color:#4a4034; border:1.5px dashed #d9c9a3; }
.pc-poster.pc-mint { background: linear-gradient(160deg,#e9f7f0,#d2eee0); color:#1f5c46; }
.pc-poster.pc-mint::before { content:''; position:absolute; top:0; left:0; right:0; height:6px; background:#00bda6; }
.pc-poster.pc-peach { background: radial-gradient(circle at 86% 12%, #ffd9c9 0 24%, transparent 25%), linear-gradient(160deg,#fff0e8,#ffe2d3); color:#7c3a2b; }
.pc-poster.pc-sky { background: linear-gradient(180deg,#e8f2fd 62%, #cfe6fa); color:#23527c; }
.pc-poster.pc-sky::after { content:''; position:absolute; left:0; right:0; bottom:0; height:9px; background:linear-gradient(90deg,#8fc1f2,#00bda6); }
.pc-poster.pc-inkred { background:#fffdfb; color:#26221e; border:3px solid #d3452e; }
.pc-poster.pc-inkred b { border-bottom: 3px solid #d3452e; padding-bottom: 6px; }
.pc-poster.pc-forest { background: linear-gradient(160deg,#14453a,#0c312a); color:#f2efe6; }
.pc-poster.pc-forest b { color:#ffd166; }
.pc-poster.pc-forest::after { content:''; position:absolute; right:12px; bottom:34px; width:32px; height:32px; border-radius:50%; border:2px solid rgba(255,209,102,.65); }
/* T16 波（派总 2026-10-21 第 4 条）：小青柠风格六款扩充（与 settings.CIRCLE_POSTER_TEMPLATES 对齐） */
.pc-poster.pc-paper { background: linear-gradient(155deg,#dfc298,#c8a271); color:#3c2e1c; border:1px solid #b8945f; box-shadow: inset 0 0 26px rgba(120,86,44,.30); }
.pc-poster.pc-grass { background: linear-gradient(180deg,#eaf7e6 58%,#cdebbf); color:#2f6b34; }
.pc-poster.pc-grass::after { content:''; position:absolute; left:0; right:0; bottom:0; height:10px; background:linear-gradient(90deg,#7cc46b,#00bda6); }
.pc-poster.pc-heart { background: radial-gradient(circle at 18% 14%, #ffd3e0 0 16%, transparent 17%), radial-gradient(circle at 84% 82%, #ffd3e0 0 12%, transparent 13%), linear-gradient(160deg,#fff0f4,#ffe1ea); color:#a63d5e; }
.pc-poster.pc-yolk { background: linear-gradient(160deg,#fff6d8,#ffe9a8); color:#7a5a12; }
.pc-poster.pc-yolk b { color:#c98a00; }
.pc-poster.pc-court { background: linear-gradient(160deg,#eef4f0,#dfe9e2); color:#1f5c46; border:2px solid #00bda6; }
.pc-poster.pc-court::before { content:''; position:absolute; inset:10px; border:1.5px dashed rgba(0,189,166,.55); border-radius:10px; pointer-events:none; }
.pc-poster.pc-mech { background: linear-gradient(160deg,#22313a,#141f26); color:#e8eef2; }
.pc-poster.pc-mech b { color:#00d9b8; }
.pc-poster.pc-mech::after { content:''; position:absolute; right:12px; bottom:34px; width:34px; height:34px; border:3px dotted rgba(0,217,184,.5); border-radius:50%; }

/* ── T16b（派总 2026-10-21 第 5/6 条）────────────────────── */
/* 选卡缩略图铺真实内置底图（所见即所得）：压一层纱保证小字可读。
   浅色款压白纱；深色款（森绿/朋克）压墨纱，字本来就是浅色的。 */
.pc-poster.pc-poster-mini { position: relative; overflow: hidden; }
.pc-poster.pc-poster-mini[style*="background-image"]::before {
  content: ''; position: absolute; inset: 0; background: rgba(255,255,255,.55); }
.pc-poster.pc-poster-mini.pc-forest[style*="background-image"]::before,
.pc-poster.pc-poster-mini.pc-mech[style*="background-image"]::before {
  background: rgba(12,36,30,.48); }
.pc-poster.pc-poster-mini[style*="background-image"] b,
.pc-poster.pc-poster-mini[style*="background-image"] span { position: relative; z-index: 1; }
.pc-poster.pc-poster-mini[style*="background-image"] { background-size: cover; background-position: center; }

/* 发布/生成图的等待层：品牌青渐变圆环 + 跳动圆点（纯 CSS，无 JS 不出现） */
.pcn-loading { position: fixed; inset: 0; z-index: var(--z-loading); display: grid; place-items: center;
  background: rgba(250,253,252,.7); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.pcn-loading[hidden] { display: none; }
.pcn-loading-card { display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: var(--sp-4xl) var(--sp-5xl) var(--sp-3xl); border-radius: var(--r-lg); background: var(--surface);
  box-shadow: var(--sh-2); }
.pcn-ring { width: 64px; height: 64px; border-radius: 50%;
  background: conic-gradient(from 0deg, #00bda6, #7ce3d4 52%, rgba(0,189,166,.18) 72%, rgba(0,189,166,.06));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px));
  animation: pcn-spin .9s linear infinite; }
@keyframes pcn-spin { to { transform: rotate(360deg); } }
.pcn-loading-txt { font-size: 16px; color: var(--ink); }
.pcn-loading-sub { font-size: 12.5px; color: var(--ink-3, #8a938f); }
.pcn-dots { display: inline-flex; gap: 6px; margin-top: 2px; }
.pcn-dots i { width: 7px; height: 7px; border-radius: 50%; background: #00bda6; opacity: .3;
  animation: pcn-dot 1.1s ease-in-out infinite; }
.pcn-dots i:nth-child(2) { animation-delay: .18s; }
.pcn-dots i:nth-child(3) { animation-delay: .36s; }
@keyframes pcn-dot { 0%, 100% { opacity: .25; transform: translateY(0); }
  45% { opacity: 1; transform: translateY(-4px); } }

/* 实时预览：跟着朝向变画幅，内容区居中 */
.pcn-preview { margin: 4px 0 12px; }
.pc-poster.pc-poster-live { width: 100%; }
.pc-poster.pc-poster-live.po-v { max-width: 340px; aspect-ratio: 3 / 4; margin: 0 auto; }
.pc-poster.pc-poster-live.po-h { max-width: 460px; aspect-ratio: 4 / 3; margin: 0 auto; }

/* 横竖版切换胶囊 */
.pcn-orients { display: flex; gap: 8px; margin: 6px 0 4px; }
.pcn-orient { cursor: pointer; position: relative; }
.pcn-orient input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-orient span { display: inline-block; padding: 6px 16px; border-radius: 999px; border: 1.5px solid var(--line,#e5e7eb); font-size: 13px; font-weight: 700; color: var(--ink-2,#5f6268); }
.pcn-orient.on span { background: var(--brand,#00bda6); border-color: var(--brand,#00bda6); color: #fff; }

/* T 波④：发流水账 · 挑单页（已完成订单列表，点一单去发） */
.spk-list { display: grid; gap: 9px; margin-top: 12px; }
.spk-item {
  display: grid; gap: 3px; padding: var(--sp-lg);
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); text-decoration: none;
}
.spk-item b { font-size: 13.5px; color: var(--ink); line-height: 1.45; }
.spk-item span { font-size: 11.5px; color: var(--ink-3); }

/* 分享按钮（详情页底栏） */
.pc-share { display: inline-flex; align-items: center; gap: 4px; border: 0; background: none; color: var(--ink-2,#5f6268); font-weight: 700; cursor: pointer; font-size: 13.5px; padding: 4px; }

/* 流水账的需求单卡（得物式「商品卡」位） */
.pc-order-card { display: flex; align-items: center; gap: 9px; background: var(--paper-2); border-radius: var(--r-sm); padding: var(--sp-md) var(--sp-lg); margin: 12px 0; color: var(--ink,#26221e); text-decoration: none; }
.pc-order-badge { flex: none; width: 24px; height: 24px; border-radius: 7px; background: var(--jade,#103c37); color: #fff; font-size: 12px; font-weight: 800; display: inline-flex; align-items: center; justify-content: center; }
.pc-order-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; font-size: 13.5px; }
.pc-order-p { flex: none; color: var(--coral,#ff6a45); font-weight: 800; }

/* ======================================================================
   T64 举报 / 拉黑（Wave 3c 齐平第二刀，派总 2026-11-07「小圈子不输小红书/得物」）
   四落点（动态详情、评论行、他人主页、举报表单）共用。`pc-*` 是跨端层，
   app.css 里有逐字相同的一份 —— 两份不一致就是「改一边忘另一边」（闸门 C 项拦这个）。
   ====================================================================== */
/* 一行安静的小字：入口不该比正文更醒目，但要摸得到（热区靠 .pc-report-link 的 padding） */
.pc-post-foot { display: flex; align-items: center; gap: 14px; margin: 10px 0 2px; }
.pc-report-link {
  background: none; border: 0; padding: 6px 0; margin: 0; cursor: pointer;
  font: inherit; font-size: 12px; color: var(--ink-3); text-decoration: none;
}
.pc-report-link:hover { color: var(--danger); text-decoration: underline; }
.pc-report-src {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; font-weight: 600; color: var(--brand-deep); text-decoration: none;
}
/* 理由单选：长相跟筛选胶囊同一套路子 —— input 透明铺满 label 当点击区。
   ⚠️ 不许 display:none 藏 input，那样点不动也提交不出参数（m-fopt 那条老坑）。 */
.pc-rop-list { display: flex; flex-wrap: wrap; gap: 7px; margin: 2px 0 14px; }
.pc-rop { position: relative; display: inline-flex; cursor: pointer; }
.pc-rop input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.pc-rop span {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 12px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font-size: 13px; font-weight: 600; white-space: nowrap;
}
.pc-rop input:checked + span { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.pc-rop input:focus-visible + span { outline: 2px solid var(--brand-deep); outline-offset: 2px; }
.pc-rop-note { display: block; }
.pc-rop-cap { display: block; font-size: 12px; color: var(--ink-3); margin-bottom: 6px; }
.pc-rop-ta {
  box-sizing: border-box; width: 100%; min-height: 76px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--ink);
  font: inherit; font-size: 14px; line-height: 1.6; resize: vertical;
}
.pc-rop-ta:focus { outline: none; border-color: var(--brand); background: var(--surface); }

/* 正文里的 #话题# 绿链 */
.pc-tag { color: var(--brand-deep,#009c8a); font-weight: 800; }

/* 圈子搜索框（#话题# 链接的落点） */
.pc-search { display: flex; align-items: center; gap: 8px; background: #fff; border: 1.5px solid var(--line,#e5e7eb); border-radius: 999px; padding: 8px 14px; margin: 10px 0 4px; }
.pc-search input[type="search"] { flex: 1; min-width: 0; border: 0; outline: none; font-size: 14px; background: none; color: inherit; }
.pc-search .ic { color: var(--ink-3,#9a9da3); }
.pc-search-x { font-size: 12.5px; color: var(--ink-3,#9a9da3); flex: none; }

.ic-xs { width: 12px; height: 12px; }

/* ======================================================================
 * 圈子改版（2026-09-24 派总 4 条）—— 两端共用块（app.css 有一份同样的拷贝，
 * 改这里必须同步那边，两端一致性的病只有成对维护能防）。
 * ---------------------------------------------------------------------- */

/* ---- 图集：得物式轮播（一次只亮一张图）+ 每张图的备注讨论串 ---- */
.pc-gallery { margin: 12px 0 0; }
.pc-gal-car { border-radius: 14px; }
/* N 波①（派总 2026-10-18）：窗口恒定 16:9 —— 竖图横图不再「一个占满屏、一个一小条」。
   竖图由 JS 加载后补 .is-tall → contain 完整装进来、左右留白（见 app.js initGalleryFit）；
   横图 cover 填满。两端（m / core）同口径。
   ⚠️ stage 必须显式 height:100%：img 的 height:100% 参照 stage，stage 高度 auto 时
   形成循环 → 浏览器回退图片自然高度，slide 的 aspect-ratio 被内容撑失效
   （e2e 实测窗口变 1.5 而不是 16:9 —— 派总要的「恒定」就没兑现）。 */
/* T16f-4（派总 2026-10-22）：详情图区从 16:9 小横条放大成**方图 1:1** ——
   与「小青柠」需求详情头图同尺寸同格式；竖图仍走 .is-tall contain 不裁切。
   T18 优化③c（派总 2026-10-26）：显示高度再 ×1.3（1:1 → 1:1.3）。
   图**上下左右居中**由 object-fit 保证（cover 居中裁切、contain 居中留边，
   object-position 默认就是 50% 50%），这里显式写出来，免得下次有人改成 top 又「看着像 bug」。 */
.pc-gal-slide { aspect-ratio: 1 / 1.3; flex: 0 0 100%; }
.pc-gal-slide .pb-stage { height: 100%; cursor: zoom-in; }
.pc-gal-slide .pb-stage img { height: 100%; object-fit: cover; object-position: center; }
.pc-gal-slide img.is-tall { object-fit: contain; }
.pc-gal-empty { margin: 2px 0 0; font-size: 12.5px; color: var(--ink-3,#9a9da3); }

/* ---- 得物式「图片海报框」：纯 CSS 叠在封面图上，pointer-events:none 不挡气泡 ---- */
.pc-frame { position: absolute; inset: 0; display: block; pointer-events: none; font-style: normal; z-index: 1; }
.pc-frame b { font-style: normal; }
.pc-frame-mag::before { content: ''; position: absolute; inset: 0; box-shadow: inset 0 0 0 7px #fff, inset 0 -40px 44px rgba(0,0,0,.3); }
.pc-frame-mag b { position: absolute; top: 14px; left: 16px; right: 16px; color: #fff; font-family: Georgia,'Times New Roman',serif; font-weight: 800; font-size: 24px; letter-spacing: .18em; text-transform: uppercase; line-height: 1.25; text-shadow: 0 2px 10px rgba(0,0,0,.5); }
.pc-frame-film::before { content: ''; position: absolute; inset: 0; box-shadow: inset 0 0 0 12px #fff, inset 0 -52px 0 #fff; }
.pc-frame-film b { position: absolute; left: 16px; right: 16px; bottom: 0; height: 52px; display: flex; align-items: center; background: #fff; color: #26221e; font-weight: 800; font-size: 14px; }
.pc-frame-band::before { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 72px; background: linear-gradient(transparent, rgba(10,12,14,.78)); }
.pc-frame-band b { position: absolute; left: 14px; right: 14px; bottom: 12px; color: #fff; font-weight: 900; font-size: 17px; line-height: 1.4; text-shadow: 0 1px 6px rgba(0,0,0,.5); }

/* 发布页里的框样式小样（选中哪个框就套哪个效果） */
.pc-frame-demo { position: relative; display: block; width: 100%; aspect-ratio: 3/4; border-radius: 10px; overflow: hidden; background: linear-gradient(160deg,#cdeee8,#9adcd2); }
.pc-frame-demo.pc-frame-mag::before { content: ''; position: absolute; inset: 0; box-shadow: inset 0 0 0 3px #fff, inset 0 -14px 16px rgba(0,0,0,.25); }
.pc-frame-demo.pc-frame-mag b { position: absolute; top: 6px; left: 8px; right: 6px; color: #fff; font-family: Georgia,'Times New Roman',serif; font-weight: 800; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; text-shadow: 0 1px 4px rgba(0,0,0,.4); }
.pc-frame-demo.pc-frame-film::before { content: ''; position: absolute; inset: 0; box-shadow: inset 0 0 0 4px #fff, inset 0 -18px 0 #fff; }
.pc-frame-demo.pc-frame-film b { position: absolute; left: 0; right: 0; bottom: 0; height: 18px; background: #fff; color: #26221e; font-size: 10px; font-weight: 800; line-height: 18px; padding: 0 6px; }
.pc-frame-demo.pc-frame-band::before { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 26px; background: linear-gradient(transparent, rgba(0,0,0,.7)); }
.pc-frame-demo.pc-frame-band b { position: absolute; left: 0; right: 0; bottom: 0; padding: 4px 6px; color: #fff; font-size: 10px; font-weight: 900; }

/* ---- 视频帖 ---- */
.pcp-video { margin: 12px 0 0; }
.pcp-video video { width: 100%; max-height: 70vh; display: block; border-radius: 14px; background: #000; }

/* ---- 小红书式引号装饰（文字海报详情 / 写想法输入卡） ---- */
.pc-poster-full { position: relative; }
.pc-poster-full::before { content: '\201C'; position: absolute; top: 10px; left: 14px; font-family: Georgia, serif; font-weight: 900; font-size: 56px; line-height: 1; opacity: .14; pointer-events: none; }
.pc-poster-full::after { content: '\201D'; position: absolute; bottom: 6px; right: 14px; font-family: Georgia, serif; font-weight: 900; font-size: 56px; line-height: 1; opacity: .14; pointer-events: none; }

/* ======================================================================
 * App 专属（2026-09-24）：发布动作面板 / 详情页底部互动条 / 发帖页新版式
 * ---------------------------------------------------------------------- */

/* ---- 发布动作面板（小红书同款 bottom sheet） ---- */
.m-sheet[hidden] { display: none; }
.m-sheet-mask { position: fixed; inset: 0; z-index: var(--z-sheet); background: var(--scrim); border: 0; padding: 0; cursor: pointer; }
.m-sheet-panel { position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-sheet) + 1); background: var(--surface); border-radius: var(--r-sheet) var(--r-sheet) 0 0; padding: var(--sp-xl) var(--sp-xl) calc(var(--sp-lg) + var(--safe-b)); display: grid; gap: 2px; box-shadow: var(--sh-sheet); }
.m-sheet-title { padding: var(--sp-2xs) var(--sp-2xs) var(--sp-sm); font-size: 14px; color: var(--ink-2); }
.m-sheet-item { display: flex; align-items: center; gap: 12px; padding: var(--sp-lg) var(--sp-md); border-radius: var(--r-sm); color: var(--ink); font-weight: 700; font-size: 15px; }
.m-sheet-item .ic { color: var(--brand-deep); flex: none; }
.m-sheet-item:active { background: var(--surface-2); }
.m-sheet-item span { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.m-sheet-item i { font-style: normal; font-weight: 500; font-size: 11.5px; color: var(--ink-3); }
/* 发需求 = 面板最后一条（派总 2026-09-24 晚第 5 条 + 第 6 条）：
   和内容卡同构，但**功能不一样**（平台主业务、钱进担保池的入口）——
   用品牌青绿实底 + 白字做强强调，一眼和「发动态」几类区分开。
   ⚠️ 选择器必须带 .m-style 前缀压过它（.m-style 定义在本文件更靠后的
   白底/边框，同特异性会按源顺序把它盖掉 —— 曾经就是这样样式静默失效的）。
   T54（派总 2026-11-02 重开「发视频」）后上面是四张内容卡 = 2×2，
   这里 `grid-column: 1/-1` 让它独占通宽一行 —— 不然 5 个格子里最后那个
   只占左半边，右边留一块白坑（面板看着像没排完）。 */
.m-style.m-sheet-demand {
  grid-column: 1 / -1;
  border: 0;
  background: linear-gradient(135deg, var(--brand), #00a892);
  box-shadow: var(--sh-brand);
}
.m-style.m-sheet-demand .ic { color: #fff; }
.m-style.m-sheet-demand b { color: #fff; }
.m-style.m-sheet-demand i { color: rgba(255, 255, 255, .85); opacity: 1; }

/* 帘子里点样式卡直接进创作（派总 2026-09-24 晚第 5 条）：
   三张内容卡 + 右下角「发需求」= 2×2，整卡是链接，点哪进哪。 */
.m-sheet-styles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.m-style {
  position: relative; display: flex; flex-direction: column; gap: 3px;
  padding: 12px 12px 10px; border-radius: 16px;
  border: 1.5px solid var(--line-2, #e5e7eb);
  background: var(--surface); cursor: pointer;
  text-decoration: none; -webkit-tap-highlight-color: transparent;
}
.m-style:active { background: var(--surface-2); }
.m-style .ic { color: var(--brand-deep); width: 20px; height: 20px; }
.m-style b { font-size: 14px; font-weight: 800; color: var(--ink); }
.m-style i { font-style: normal; font-size: 11px; color: var(--ink-3); line-height: 1.4; }
.m-sheet-cancel { margin-top: 6px; padding: var(--sp-lg); border-radius: var(--r-pill); border: 0; background: var(--surface-2); color: var(--ink-2); font: inherit; font-weight: 700; cursor: pointer; }
/* T35（派总 2026-10-29）：发布页退出确认弹层的三颗主按钮（抽屉沿用 m-sheet） */
.pcn-close-act { margin-top: 2px; padding: 13px; border: 0; border-radius: 999px; font: inherit; font-weight: 800; font-size: 15px; cursor: pointer; }
.pcn-close-act--save { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.pcn-close-act--save:active { background: var(--brand-deep); }
.pcn-close-act--drop { background: var(--danger-soft); color: var(--danger); }
.pcn-close-act--drop:active { background: var(--danger); color: #fff; }
/* 有互动条的页面正文别被压住 */
/* ---- 发帖页新版式（小红书「写想法」+ 得物模板格子） ---- */
.pcn-top { display: flex; align-items: center; gap: 10px; padding: 2px 0 12px; }
.pcn-x { width: 38px; height: 38px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--surface-2); color: var(--ink-2); }
.pcn-top-t { flex: 1; min-width: 0; font-size: 16px; text-align: center; padding-right: 38px; }
.pcn-go { flex: none; border: 0; background: var(--brand); color: #fff; font-weight: 900; font-size: 13.5px; padding: 9px 18px; border-radius: 999px; cursor: pointer; box-shadow: var(--sh-brand); }
/* 发布按钮沉到创作页最底部（派总 2026-09-24 晚第 5 条：纯编辑界面）
   M 波⑥：左边并排一个「存草稿」（ghost 款），发布仍是品牌色主按钮。 */
.pcn-foot { margin-top: 20px; padding: 4px 0 calc(24px + var(--safe-b)); display: flex; gap: 8px; }
.pcn-go--big { display: block; width: 100%; padding: 14px; font-size: 15.5px; border-radius: 999px; }
.pcn-foot .pcn-go--big, .pcn-foot .pcn-save { flex: 1; width: auto; }
.pcn-save {
  border: 1.5px solid var(--line); background: var(--surface); color: var(--ink-2);
  font-weight: 800; font-size: 14px; padding: 14px 12px; border-radius: 999px; cursor: pointer;
}
.pcn-save.is-done { border-color: var(--brand); color: var(--brand-deep); }
.pcn-modes { display: flex; gap: 6px; margin-bottom: 12px; }
.pcn-mode { position: relative; flex: 1; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 4px; padding: 8px 4px; border-radius: 999px; background: var(--surface); color: var(--ink-2); font-size: 12.5px; font-weight: 700; box-shadow: var(--sh-1); cursor: pointer; white-space: nowrap; }
.pcn-mode input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pcn-mode.on { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.pcn-shots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 12px; }
/* M 波④（派总 2026-10-17）：图片矩阵 = 3 列 × 2 行（最多 6 张）；
   长按拖动排序时禁掉系统长按菜单（iOS 呼出框/安卓文字选择）。 */
.pcn-prev { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.pcn-prev.is-drag { z-index: 2; box-shadow: 0 8px 22px rgba(15, 20, 24, .28); transform: scale(1.04); transition: transform .12s; }
.pcn-prev.is-over { outline: 2px solid var(--brand); outline-offset: 1px; }
/* 预览容器本身不占格（display:contents），让每张图直接当九宫格的一枚格子 */
.pcn-previews[hidden] { display: none; }
/* K 波⑭（派总 2026-10-17）：「拍照/相册」改成大「+」号按钮（口径同发需求页 K 波⑧）。
   空态通宽一条；有图后缩成九宫格末尾一枚小「+」；满 6 张 JS 收起。 */
.pcn-shot {
  aspect-ratio: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 0;
  border: 1.5px dashed rgba(16, 60, 55, .3); border-radius: 14px;
  background: var(--surface-2); color: var(--brand-deep);
  font: inherit; cursor: pointer;
}
.pcn-shot .ic { width: 30px; height: 30px; }
.pcn-shot b { font-size: 14px; font-weight: 800; }
.pcn-shots.has-prev .pcn-shot {
  grid-column: auto; aspect-ratio: 1; padding: 0;
  flex-direction: column; gap: 4px; border-radius: 14px;
}
.pcn-shots.has-prev .pcn-shot .ic { width: 24px; height: 24px; }
.pcn-shots.has-prev .pcn-shot b { display: none; }
.pcn-shot[hidden] { display: none; }
.pcn-file { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pcn-live { display: block; }
.pcn-live-title, .pcn-live-body { display: block; width: 100%; border: 0; background: transparent; font: inherit; color: inherit; padding: 0; margin: 0; outline: none; }
.pcn-live-title { font-weight: 800; font-size: 17px; margin: 8px 0 10px; }
.pcn-live-body { font-size: 14.5px; line-height: 1.7; resize: none; min-height: 170px; }
/* M 波⑤（派总 2026-10-17）：正文再高 2 个字符 —— 海报卡 120→170px（约 +2 行），
   图文/视频模式的正文 textarea（默认只有 2 行）也一并垫到 4 行高度。 */
.pcn textarea[name="content"] { min-height: 100px; }
.pcn-live-author { opacity: .7; }
.pcn-quote { font-style: normal; font-size: 44px; line-height: 1; opacity: .16; font-weight: 900; font-family: Georgia, serif; }
.pcn-frames { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-bottom: 12px; }
.pcn-frame { position: relative; display: flex; flex-direction: column; gap: 4px; text-align: center; cursor: pointer; }
.pcn-frame input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pcn-frame i { font-style: normal; font-size: 11px; color: var(--ink-3); }
.pcn-frame .pc-frame-demo { outline: 2px solid transparent; outline-offset: 1px; }
.pcn-frame.on i { color: var(--brand-deep); font-weight: 800; }
.pcn-frame.on .pc-frame-demo { outline-color: var(--brand); }

/* ---- 选完立刻看见（派总 2026-09-24 晚：选图/选视频没反馈 = 以为失败了） ---- */
/* 图片九宫格预览：缩略图 + × 删除 + 每张一个「标注」输入框 */
.pcn-previews { display: contents; }
.pcn-prev {
  position: relative; margin: 0; border-radius: 14px; overflow: hidden; aspect-ratio: 1;
  background: var(--surface); box-shadow: var(--sh-1);
  /* 这一格**本来就可点**（点缩略图=换上台/放大查看），标成可点是如实描述它的行为。
     ⚠️ 但它**挡不住** Blink 的触控吸附（真触屏探针实测两种直觉修法都无效：加 cursor:pointer、
     加 role=button+tabindex，54px 胶片格的中心照样被吸附到右上角那颗 × ⇒
     「点一下放大」在手机上变成「删掉这张」）。真管用的是下面把 × 缩小并贴到真角落
     （`.pcn-shots.has-prev .pcn-prev-x`），让格子中心离那颗按钮的框有 10px 以上。 */
  cursor: pointer;
}
.pcn-prev img { display: block; width: 100%; height: 100%; object-fit: cover; background: var(--surface-2); }
.pcn-prev-cover {
  position: absolute; top: 6px; left: 6px; z-index: 1;
  padding: 2px 8px; border-radius: 999px;
  background: rgba(15, 20, 24, .55); color: #fff;
  font-style: normal; font-size: 10px; font-weight: 800;
}
.pcn-prev-x {
  position: absolute; top: 6px; right: 6px; z-index: 1;
  width: 24px; height: 24px; border: 0; border-radius: 50%;
  background: rgba(15, 20, 24, .55); color: #fff;
  font-size: 15px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}

/* ==============================================================
   T59①（派总 2026-11-04 第 1 条「上传后直接进入预览，预览界面下方有编辑菜单」）
   发图文 / 发文字第③步 的第①屏 = 预览台 + 编辑菜单 + 缩略胶片（三件套）
   --------------------------------------------------------------
   为什么把九宫格降级：原来这一步是一面 3×2 的格子墙，「预览」其实只是缩略图 ——
   要看大图还得再点一下，而编辑（裁切/涂鸦/写字）藏在那一层的第二屏里。
   三件套的分工是**一屏一件事**：
     · 台子（`.pcn-stage`）= 当前这一张的大图，`contain` 不裁切 —— 所见即发出去的那张；
     · 菜单（`.pcn-emenu`）= 对当前这一张能做的动作，做不了的整颗收掉（不给死钮）；
     · 胶片（`.pcn-shots.has-prev`）= 选哪一张 + 末尾续加，一行放得下 6 张（390px 实量 364px），
       所以关键动作不靠横滑才找得到（设计原则 6）。
   台子底色用墨青 `#101418`（全站唯一的「压暗看内容」色，同视频舞台），
   不是纯黑 —— 纯黑会把白底卡片图吃掉一圈。
   ============================================================== */
.pcn-stage {
  position: relative; height: clamp(240px, 44vh, 380px);
  margin: 0 0 10px; border-radius: 18px; overflow: hidden;
  background: #101418; box-shadow: var(--sh-1); cursor: pointer;
}
.pcn-stage[hidden] { display: none; }
.pcn-stage img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  /* ⚠️ 不许写 background:#fff —— 台子自己的墨底就是留边，图再垫一层白会把
     「这张图的真实比例」糊成一条白带（发文字的卡片本来就是白底，这里跟着白就分不出了） */
}
.pcn-stage img[hidden] { display: none; }
.pcn-stage-tag {
  position: absolute; z-index: 2; left: 10px; top: 10px;
  padding: 3px 9px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .9); color: #101418;
  font-size: 11px; font-weight: 800; font-style: normal;
}
.pcn-stage-tag[hidden] { display: none; }
.pcn-stage-count {
  position: absolute; z-index: 2; right: 10px; bottom: 10px;
  padding: 2px 9px; border-radius: var(--r-pill);
  background: rgba(16, 20, 24, .55); color: #fff;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.pcn-stage-nav {
  position: absolute; z-index: 2; top: 50%; transform: translateY(-50%);
  width: 34px; height: 44px; border: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center; border-radius: 12px;
  background: rgba(16, 20, 24, .45); color: #fff;
}
.pcn-stage-nav[hidden] { display: none; }
.pcn-stage-nav.is-prev { left: 8px; }
.pcn-stage-nav.is-next { right: 8px; }
.pcn-stage-nav.is-prev .ic { transform: scaleX(-1); }
.pcn-stage-nav .ic { width: 20px; height: 20px; }
/* 视觉 34×44，热区靠伪元素扩到 44×60（设计原则 6：窄屏触控不小于 44px） */
.pcn-stage-nav::after { content: ''; position: absolute; inset: -8px -5px; }

/* 台子下面的编辑菜单：三颗等宽、图标 + 动作名，动作名直接写在钮上 */
.pcn-emenu { display: flex; gap: 8px; margin: 0 0 12px; }
.pcn-emenu[hidden] { display: none; }
.pcn-emb {
  flex: 1 1 0; min-width: 0; min-height: 44px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  border: 0; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: var(--sh-1); font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.pcn-emb[hidden] { display: none; }
.pcn-emb .ic { width: 17px; height: 17px; color: var(--brand-deep); flex: none; }
.pcn-emb.is-danger .ic { color: var(--danger-ink); }
.pcn-emb:active { transform: translateY(1px); }

/* 胶片：空态还是那一条通宽大「+」（选完它缩进末尾）；有图改横向一条。
   ⚠️ 两轴都要写死：只写 overflow-x 时 CSS 把另一轴**算成 auto**（铁律 42①），
   纵向多出来的 8px 内边距就变成一条看不见的竖向滚动。 */
.pcn-shots:not(.has-prev) { grid-template-columns: 1fr; }
.pcn-shots:not(.has-prev) .pcn-shot { aspect-ratio: 16 / 9; min-height: 168px; }
.pcn-shots.has-prev {
  display: flex; align-items: flex-start; gap: 8px;
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
  padding: 2px 2px 8px; margin-bottom: 10px;
}
.pcn-shots.has-prev::-webkit-scrollbar { display: none; }
.pcn-shots.has-prev .pcn-prev { flex: 0 0 auto; width: 54px; height: 54px; aspect-ratio: auto; }
.pcn-shots.has-prev .pcn-shot { flex: 0 0 auto; width: 54px; height: 54px; aspect-ratio: auto; }
.pcn-shots.has-prev .pcn-prev.is-active { outline: 2px solid var(--brand); outline-offset: 2px; }
/* 台子已经标了「封面」，胶片上这颗缩到角标大小，别把 54px 的小格糊满 */
.pcn-shots.has-prev .pcn-prev-cover { top: 3px; left: 3px; padding: 1px 5px; font-size: 9px; }
/* 胶片上的这颗 × 是**次要入口**（主删除路径是台子下面那排菜单里的「删除」），所以它让路：
   20px@3px 时它到格子中心的距离只有 4px，Blink 触控吸附判定"离手指最近的按钮"就是它，
   于是手机上"点缩略图放大"变成"删掉这张"（真触屏探针：中心 touchstart.target=pcn-prev-x）。
   收到 16px 并贴到 1px 的角上，中心到它的框隔 10px 以上，吸附就落在格子本身。 */
.pcn-shots.has-prev .pcn-prev-x { width: 16px; height: 16px; top: 1px; right: 1px; font-size: 11px; }
/* 发文字第③步的卡片是 3:4 的成图，胶片里给它一格竖的，一眼认得出那不是照片 */
.pcn-shots.has-prev .pcn-prev.is-card { width: 44px; height: 58px; }

/* --------------------------------------------------------------
   T59②（派总 2026-11-04 第 1、2 条）发视频第①步 = 同一块预览台 + 同一排编辑菜单
   --------------------------------------------------------------
   台子的几何与图文一致（圆角 18、墨底 #101418），唯一的差别是**不许给 video 定高**：
   `video-editor.js` 把叠层那层按 `pcnVPreview` 的 offsetTop / offsetHeight 钉在 `#pcnVStage` 里
   （该文件 166 行有注释说明为什么不能整屏铺），元素盒必须和「真正画出来的那块」等高 ——
   一上 `height:100%` + `object-fit:contain` 就有了黑边，每一层字会整体偏移。
   所以这一格的高度仍由视频自己的比例长出来（`max-height` 收在 56vh），台子的墨底就是留边。 */
.pcn-stage--v { height: auto; display: flex; justify-content: center; cursor: default; }
.pcn-stage--v video { display: block; width: 100%; max-height: 56vh; background: transparent; }
/* 读数（「12″ · 3.4MB」「上传中 80%」「封面用的就是这一帧」）挪到台子**上沿**：
   原生 controls 占着下沿，压在它上面等于把话藏进按钮缝里。 */
.pcn-stage--v .pcn-stage-count { top: 10px; bottom: auto; left: 10px; right: auto; }

/* 剪辑台入口（含「存一份带字的视频」那两颗，第 ① 步）/ 配乐（第 ② 步，T59② 跟着标题正文
   搬过去 —— 理由见 circle_new.html 第 ① 步那段注释）—— 这几颗换上台子下面那一排的长相
   （同圆角、同影、同 44px 热区、动作名写在钮上）。**标记与接线一个都没动**：
   `data-mve-open` / `data-mvx-run` / `data-bgm-open` 仍由各自的 JS 绑，样式只改形。
   ⚠️ 一律用「子代」选择器（`>` 一路写到底），有两个理由：
     ① bgm.css / video-edit.css 在 base.html 里排在 m.css **之后**，同名同权重它会赢，
        多写两层类不只是抢权重，是把判据写成「谁挂在发布页这一格里」；
     ② 剪辑台打开时 `video-editor.js` 会把 `._bgm_picker` 那一整块**搬进**抽屉里
        （`.mve-bgm-slot`）—— 搬进去之后它就不该再吃这套浅色胶囊（那一屏是深色台），
        子代选择器正好只命中「还在原位」的那一刻。 */
.pcn-vacts--bgm { margin-top: 12px; }   /* 第 ② 步里紧跟在工具条后面，留一格呼吸 */
.pcn-vacts > .mve { margin-top: 0; }
.pcn-vacts > .mve > .mve-bar { gap: 8px; padding: 0; margin: 0 0 8px; }
.pcn-vacts > .mve > .mve-bar > .mve-open,
.pcn-vacts > .mve > .mve-bar > .mve-exp { flex: 1 1 0; min-width: 0; }
.pcn-vacts > .mve > .mve-bar > .mve-exp { display: grid; gap: 6px; }
.pcn-vacts > .mve > .mve-bar > .mve-exp > .mve-exp-btn { width: 100%; }
.pcn-vacts > .bgm-field { margin-top: 0; padding: 0; background: none; border-radius: 0; }
.pcn-vacts > .bgm-field > .bgm-bar { gap: 8px; margin: 0 0 8px; }
.pcn-vacts > .bgm-field > .bgm-bar > .bgm-open { flex: 1 1 0; min-width: 0; }

/* 三颗 + 台子下面那排共用的一副长相：44px 热区、图标 + 动作名（与上面的 `.pcn-emb` 同一份数） */
.pcn-vacts > .mve > .mve-bar > .mve-open,
.pcn-vacts > .mve > .mve-bar > .mve-exp > .mve-exp-btn,
.pcn-vacts > .bgm-field > .bgm-bar > .bgm-open {
  min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 6px;
  border: 0; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: var(--sh-1); font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
  white-space: nowrap;   /* 钮上的字宁可让整排挤一下，也不许在钮里折成两行 */
}
.pcn-vacts .mve-open .ic,
.pcn-vacts .mve-exp-btn .ic,
.pcn-vacts .bgm-open .ic { width: 17px; height: 17px; color: var(--brand-deep); flex: none; }
.pcn-vacts > .mve > .mve-bar > .mve-open[disabled] { opacity: .45; cursor: default; }
/* 配乐原来是「一条灰底板上摆一颗钮」；收起时它其实只是一颗钮 ⇒ 那块面跟着**展开**才出现，
   平时不在编辑菜单底下再垫一块灰。 */
.pcn-vacts > .bgm-field > .bgm-panel[open] {
  padding: var(--sp-md) var(--sp-lg); background: var(--surface); border-radius: var(--r-sm); box-shadow: var(--sh-1);
}
/* 空态那颗「添加视频」与图文那颗「添加图片」同尺寸（三种流程一套语言的起点） */
.pcn-vpick { margin-bottom: 12px; }
.pcn-vpick .pcn-shot { aspect-ratio: 16 / 9; min-height: 168px; }

/* 视频预览：选完直接内嵌播放，不满意一键重选 */
.pcn-vprev { margin-top: 12px; }
.pcn-vprev video {
  display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: contain;
  border-radius: 14px; background: #101418;
}
.pcn-vclear {
  margin-top: 8px; border: 1.5px solid var(--line-2, #e5e7eb); border-radius: 999px;
  background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: 12.5px; font-weight: 700; padding: 7px 14px; cursor: pointer;
}

/* 「海报模板」模式：得物式大格子墙 —— 先挑模板，挑完往下面的大卡里填字。
   （上面的 16/10 !important 是给小样的，这里用更高优先级 + !important 覆盖。） */
.pcn-tpls--xl { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.pcn-tpls--xl .pc-poster.pc-poster-mini { aspect-ratio: 3 / 4 !important; padding: 16px 14px; }
.pcn-tpls--xl .pc-poster-mini b { font-size: 16px; }
.pcn-tpls--xl .pc-poster-mini span { font-size: 11.5px; }
.pcn-tpls--xl .pcn-tpl i { font-size: 12px; }

/* 「写文字」模式：模板收进默认合上的抽屉（小红书的做法 —— 重点写字，模板可选） */
.pcn-adv { margin-top: 14px; border: 1.5px solid var(--line-2, #e5e7eb); border-radius: 16px; background: var(--surface); }
.pcn-adv summary {
  list-style: none; display: flex; align-items: center; gap: 8px;
  padding: 12px 14px; cursor: pointer;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
}
.pcn-adv summary::-webkit-details-marker { display: none; }
.pcn-adv summary .ic { color: var(--brand-deep); }
.pcn-adv-chev { margin-left: auto; transition: transform .15s ease; color: var(--ink-3); }
.pcn-adv[open] .pcn-adv-chev { transform: rotate(180deg); }
.pcn-adv-in { padding: 2px 14px 14px; border-top: 1px solid var(--line-2, #e5e7eb); }
/* 铁律 18 的保险：个别老 WebView 合上的 details 里内容不会自动藏，手动兜住 */
.pcn-adv:not([open]) .pcn-adv-in { display: none; }

/* ----------------------------------------------------------------------
   「我的」页底部的精简页脚（2026-09-24，方案 B）
   ----------------------------------------------------------------------
   ⚠️ 2026-10-05 派总第 6 条：**不再固定显示**。
   以前它是 `position:sticky` 吸在底栏上方（当时怕被五格导航压住半截），
   结果它一直挂在屏幕下方占着一块、还抢走了底栏上方的视觉空间。
   现在改回**普通文档流**：排在「退出登录」按钮之后，居中、灰色、小字，
   只在把页面滚到底时自然出现 —— 想看就看，不想看不碍事。
   只在这一页出现（templates/m/me.html），别的页面不挂。
   ---------------------------------------------------------------------- */
.m-foot {
  margin: 22px 0 4px;
  padding: 0 6px;
  text-align: center;
}
.m-foot-brand { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.m-foot-brand:active { opacity: .6; }
.m-foot-brand .brand-mark { display: block; opacity: .5; }
.m-foot-name { font-size: 12.5px; font-weight: 800; color: var(--ink-3); letter-spacing: .2px; }
.m-foot-slogan { margin: 4px 0 0; font-size: 11.5px; color: var(--ink-4); line-height: 1.6; }
.m-foot-links {
  display: flex; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 8px; justify-content: center;
}
.m-foot-links a { font-size: 11.5px; font-weight: 600; color: var(--ink-3); text-decoration: none; }
.m-foot-links a:active { color: var(--brand-deep); }
.m-foot-icp { margin: 6px 0 0; font-size: 11px; color: var(--ink-4); }
.m-foot-icp a { color: var(--ink-4); text-decoration: underline; }
.m-foot-legal {
  margin: 4px 0 0;
  display: flex; flex-wrap: wrap; gap: 2px 10px; justify-content: center;
  font-size: 10.5px; color: var(--ink-4);
}
/* 窄屏两行挤不下时，第二行换个方向排，别把字压成一团 */
@media (max-width: 380px) {
  .m-foot-legal { flex-direction: column; }
  /* 极窄屏（≤380px）：顶栏塞不下「小青柠」三个字 —— tab 里文字藏起、只留 logo 图标，
     tab 缩回小方块（跟 2026-09-24 纯图标版的尺寸一致）。 */
  .m-top-all-t { display: none; }
  .m-top-all { padding: 0; width: 30px; justify-content: center; }
  .m-top-all .m-mark { margin: 0; }
}

/* ----------------------------------------------------------------------
   底栏第一格的品牌位 + 顶栏「圈子」入口（2026-09-24 晚，派总定的对调）
   ----------------------------------------------------------------------
   底栏：logo 代替「房子」图标 —— 未选中置灰、选中恢复彩色（img 没法换色，
   用 filter 做灰化）；文字仍写「发现」（页面功能名不变）。
   顶栏：原 logo 位换成「圈子」文字入口，图标用 Lucide 的 users。 */
.m-tab .m-tab-mark {
  width: 22px; height: 22px; display: block;
  filter: grayscale(1); opacity: .55;
  transition: filter .15s ease, opacity .15s ease;
}
.m-tab.on .m-tab-mark { filter: none; opacity: 1; }
/* 底栏第一格 = 品牌位「小青柠 ↔ 小圈子」互切（2026-10-05 派总第 2 条）：
   这一格**永远指向另一边**，所以没有 .on 选中态（它不再表示「我在哪一页」），
   改用「彩色 mark + 品牌色文字」跟另外四格区分。
   ⚠️ .m-tab-brand 以前只在 _tabbar.html 里挂着、CSS 里从来没定义（audit_css 2026-10-05 报出来），补在这里。 */
.m-tab-brand { color: var(--brand-deep); }
.m-tab-brand .m-tab-mark { filter: none; opacity: 1; }
.m-title .ic, .m-brand .ic {
  width: 18px; height: 18px; vertical-align: -3.5px; margin-right: 3px;
}

/* ======================================================================
 * App「发需求」单页（2026-09-24 晚，派总第 7 条：照闲鱼「发闲置」做减法）
 * 旧 11 步向导的 .wz-* 样式保留（网页版结构不同，别删）——这一段全是 .pub-*。
 * ---------------------------------------------------------------------- */
.pub-x { width: 36px; height: 36px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--surface-2); color: var(--ink-2); }
.pub-top-t { flex: none; font-size: 16px; font-weight: 900; color: var(--ink); }
.pub-top-sp { flex: 1; }
.pub-draft-btn { flex: none; border: 0; background: none; color: var(--ink-2); font: inherit; font-size: 13px; font-weight: 700; padding: 6px 8px; cursor: pointer; }
.pub-top-go {
  flex: none; border: 0; background: var(--brand); color: #fff; font: inherit;
  font-size: 13px; font-weight: 900; padding: 8px 16px; border-radius: 999px;
  cursor: pointer; box-shadow: var(--sh-brand);
}
.pub-draft-tip {
  display: flex; align-items: center; gap: 8px; margin: 0 2px 12px;
  padding: var(--sp-md) var(--sp-lg); border-radius: var(--r-sm); font-size: 13px; color: var(--ink-2);
  background: rgba(200, 149, 44, .1); border: 1px solid rgba(200, 149, 44, .35);
}
.pub-draft-tip .ic { color: var(--gold); flex: none; width: 18px; height: 18px; }
.pub-draft-tip span { flex: 1; min-width: 0; }
.pub-draft-tip a { font-weight: 800; color: var(--brand-deep); text-decoration: none; }
/* K 波⑦（派总 2026-10-17）：草稿提示右侧「×」删除 */
.pub-draft-x {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: 8px;
  background: rgba(200, 149, 44, .16); color: var(--gold); cursor: pointer;
}
.pub-draft-x:active { transform: scale(.9); }
.pub-draft-x .ic { width: 14px; height: 14px; }

.pub-card {
  background: var(--surface); border-radius: var(--r); box-shadow: var(--sh-1);
  padding: var(--sp-lg); margin-bottom: 12px;
}
.pub-desc {
  display: block; width: 100%; min-height: 120px; border: 0; resize: vertical;
  background: none; font: inherit; font-size: 15px; line-height: 1.6; color: var(--ink);
}
.pub-desc::placeholder { color: var(--ink-3); }
.pub-title-row {
  display: flex; align-items: center; gap: 8px; margin-top: 8px; padding-top: 10px;
  border-top: 1px dashed var(--line);
}
.pub-title-tag {
  flex: none; font-size: 11.5px; font-weight: 800; color: var(--brand-deep);
  background: rgba(0, 189, 166, .12); border-radius: 6px; padding: 3px 7px;
}
.pub-title-row input { flex: 1; min-width: 0; border: 0; background: none; font: inherit; font-size: 14.5px; font-weight: 700; color: var(--ink); }
.pub-title-row input::placeholder { color: var(--ink-3); font-weight: 500; }
/* 标题预览（派总 2026-09-24 第 3 条 a）：右边那行灰字会随着描述实时变，
   让人在点发布之前就知道标题长什么样。超出一行就省略号，别把卡片撑高。 */
.pub-title-auto {
  flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pub-title-auto.is-set { color: var(--ink); font-weight: 700; }

/* 图片上传 + 数量和交期（U 波 2026-10-10 第 12 条重排）：
   原来三样挤一行（九宫格 + 两个输入框），窄屏上「拍照 / 相册」被压成一小格、
   输入框也局促。改成两行：拍照九宫格占一整行；数量 / 交期并排铺满第二行，
   输入框变得又宽又好点。 */
.pub-shots-row { display: block; }
.pub-shots { margin-bottom: 10px; }
.pub-shot-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.pub-shot-fields .m-label { font-size: 11.5px; }
.pub-shot-fields .m-input { font-size: 13px; padding: 8px 10px; }

/* 「添加收件人 / 需求人信息」胶囊（第 3 条 d）：
   它就是那一折叠段的 summary 行，整行可点。 */
.pub-add-addr {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 4px;
  height: 30px; padding: 0 12px; border-radius: var(--r-pill);
  background: var(--brand-soft); color: var(--brand-deep);
  font-size: 12.5px; font-weight: 800; white-space: nowrap;
}
.pub-add-addr .ic { width: 14px; height: 14px; }
#sec-addr > summary .pub-sec-val { margin-left: 6px; max-width: 42%; }
/* K 波⑫（派总 2026-10-17）：摘要行右侧「管理地址」文字钮（跳 m:addresses） */
.pub-addr-manage {
  margin-left: 8px; flex: none;
  font-size: 12px; font-weight: 700; color: var(--brand-deep);
  white-space: nowrap; text-decoration: underline;
  -webkit-text-decoration-color: rgba(0, 156, 138, .4);
}
/* K 波⑬（派总 2026-10-17）：仿顺丰/京东的「智能识别」大框 —— 粘贴整段地址
   自动拆省/市/区/街道 + 姓名 + 电话。按需展开：JS 挂上后默认只显示这一块，
   四级联动收起（点「手动填写 ↓」再展开）；没 JS 时两级全铺开（见下方 is-smart）。 */
.pub-addr-smart { margin-bottom: 12px; }
.pub-addr-pastebox {
  display: flex; align-items: flex-start; gap: 8px;
  padding: var(--sp-md) var(--sp-lg); border-radius: var(--r-sm);
  background: var(--surface); border: 1.5px solid transparent;
}
.pub-addr-pastebox:focus-within { border-color: var(--brand); background: #fff; }
.pub-addr-pastebox .ic { width: 18px; height: 18px; color: var(--brand-deep); flex: none; margin-top: 2px; }
.pub-addr-pastebox textarea {
  flex: 1; border: 0; background: none; resize: none;
  font-size: 14px; line-height: 1.6; color: var(--ink); outline: none;
}
.pub-addr-pastebox textarea::placeholder { color: var(--ink-3, #9aa0a6); font-size: 13px; }
.pub-addr-manual {
  margin-top: 8px; border: 0; background: none; padding: 0;
  font-size: 12.5px; font-weight: 700; color: var(--brand-deep);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.pub-sec-in.is-smart .pub-addr-cascade { display: none; }
.pub-sec-in.is-smart .pub-addr-cascade.is-manual { display: block; }

.pub-shots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
/* K 波⑧（派总 2026-10-17）：「拍照/相册」改成大「+」号按钮。
   空态：通宽一条大按钮（页面顶部第一眼就是它）；
   有图：缩成九宫格末尾的一枚小「+」（JS 给 .pub-shots 加 has-prev）；
   满 6 张：JS 直接 hidden（[hidden] 要显式压过 display:grid）。 */
.pub-shot {
  aspect-ratio: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 0;
  border: 1.5px dashed rgba(16, 60, 55, .3); border-radius: 14px;
  background: var(--surface-2); color: var(--brand-deep);
  font: inherit; cursor: pointer;
}
.pub-shot .ic { width: 30px; height: 30px; }
.pub-shot b { font-size: 14px; font-weight: 800; }
.pub-shots.has-prev .pub-shot {
  grid-column: auto; aspect-ratio: 1; padding: 0;
  flex-direction: column; gap: 4px; border-radius: 14px;
}
.pub-shots.has-prev .pub-shot .ic { width: 24px; height: 24px; }
.pub-shots.has-prev .pub-shot b { display: none; }
.pub-shot[hidden] { display: none; }
.pub-prev { position: relative; aspect-ratio: 1; border-radius: 14px; overflow: hidden; background: var(--surface-2); }
.pub-prev img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pub-prev-x {
  position: absolute; top: 4px; right: 4px; width: 22px; height: 22px;
  border: 0; border-radius: 50%; background: rgba(15, 20, 24, .6); color: #fff;
  font-size: 13px; line-height: 1; cursor: pointer;
}

.pub-more { margin-top: 10px; }
.pub-more > summary {
  list-style: none; cursor: pointer; font-size: 13px; font-weight: 800; color: var(--brand-deep);
  padding: 6px 2px 0; user-select: none;
}
.pub-more > summary::-webkit-details-marker { display: none; }
.pub-more[open] > summary { padding-bottom: 8px; }
.pub-stock-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.pub-stock-grid label { position: relative; aspect-ratio: 1; border-radius: 12px; overflow: hidden; }
.pub-stock-grid img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pub-stock-grid input { position: absolute; top: 5px; left: 5px; width: 18px; height: 18px; margin: 0; }
.pub-stock-grid input:checked + img { outline: 2.5px solid var(--brand); outline-offset: -2.5px; }

.pub-kinds { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px; }
.pub-kind { position: relative; }
.pub-kind input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pub-kind span {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 11px 0; border-radius: 12px; background: var(--surface-2);
  font-size: 14px; font-weight: 800; color: var(--ink-2); cursor: pointer;
  border: 1.5px solid transparent;
}
.pub-kind input:checked + span {
  background: rgba(0, 189, 166, .12); color: var(--brand-deep);
  border-color: var(--brand);
}
.pub-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.pub-chip { position: relative; }
.pub-chip input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pub-chip span {
  display: inline-block; padding: 8px 14px; border-radius: 999px; cursor: pointer;
  background: var(--surface-2); font-size: 13px; font-weight: 700; color: var(--ink-2);
  border: 1.5px solid transparent; -webkit-tap-highlight-color: transparent;
}
.pub-chip input:checked + span { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.pub-chip input:focus-visible + span { border-color: var(--brand); }

/* K 波⑪（派总 2026-10-17）：标签 chips —— 系统自动生成 1~3 个（可 × 掉）
   + 输入框（回车/逗号手动加）。chips 容器用 display:contents，chip 和
   输入框直接当 .pub-tagbox 的弹性子项排（同 pcn-shots 的技巧）。 */
.pub-tagbox { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pub-tag-chips { display: contents; }
.pub-tag-chip {
  display: inline-flex; align-items: center; gap: 2px;
  height: 30px; padding: 0 4px 0 11px;
  border-radius: 999px;
  background: var(--brand-soft); color: var(--brand-deep);
  font-size: 13px; font-weight: 700; line-height: 1;
}
.pub-tag-x {
  border: 0; background: none; padding: 0 5px; margin: 0;
  color: inherit; font-size: 15px; font-weight: 700; line-height: 1;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.pub-tag-x:active { opacity: .6; }
.pub-tagbox .m-input { flex: 1; min-width: 140px; }

.pub-price-row { display: flex; align-items: baseline; gap: 6px; margin-bottom: 12px; }
.pub-price-yen { font-size: 24px; font-weight: 900; color: var(--coral); }
.pub-price-row input {
  width: 130px; border: 0; background: none; font: inherit;
  font-size: 26px; font-weight: 900; color: var(--coral);
}
.pub-price-row input::placeholder { color: var(--ink-3); font-weight: 700; }
/* K 波⑩（派总 2026-10-17）：「可议价/一口价」移到价格右侧、同一行 */
.pub-neg-inline { margin-left: auto; flex: none; }
.pub-neg-inline .pub-chip { padding: 5px 10px; font-size: 12px; }
/* K 波⑨（派总 2026-10-17）：选了「由圆梦方出价」—— 价格框整行禁用，
   价格等圆梦者交方案时给（发布不冻钱）。 */
.pub-price-row.is-off { opacity: .45; pointer-events: none; }
/* X 波②（派总 2026-10-15）：出价超上限 —— 红字报警 + 价格框红边（框内字转深红），
   提交被前端拦下、停在编辑页让人改对，不自动存草稿退出。 */
.pub-price-err { margin: -4px 0 10px; font-size: 12.5px; font-weight: 800;
  color: #d2452c; }
.pub-price-row input.is-bad { color: #d2452c;
  box-shadow: inset 0 -2px 0 0 #d2452c; }
/* X 波②：出价封顶 = 一口价，「可议价」置灰不可点 */
.pub-chip.is-off { opacity: .45; pointer-events: none; }
/* Y 波⑤（派总 2026-10-15）：任何输入不恰当 = 红字 + 红框当场警示。
   通用版挂在 .m-input / .m-textarea 上（发布页价格框的 .is-bad 见上）。 */
.m-input.is-bad, .m-textarea.is-bad, .m-select.is-bad {
  border-color: #d2452c; color: #d2452c;
}
.pub-neg-lock { margin: 8px 0 0; font-size: 12px; font-weight: 700; color: #d2452c; }
.pub-calc { margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: var(--surface-2); }
.pub-calc-row { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; color: var(--ink-2); padding: 2px 0; }
.pub-calc-row b { color: var(--ink); font-weight: 800; }
.pub-calc-total { border-top: 1px dashed var(--line); margin-top: 6px; padding-top: 8px; }
.pub-calc-total span { color: var(--ink); font-weight: 800; }
.pub-calc-total b { color: var(--coral); font-size: 16px; font-weight: 900; }

.pub-adv > summary { font-size: 14.5px; color: var(--ink); padding: 4px 2px; }
.pub-sum-hint { margin-left: 8px; font-size: 11.5px; font-weight: 500; color: var(--ink-3); }
.pub-adv-in { padding-top: 10px; }
.pub-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.pub-subhead { margin: 16px 2px 6px; font-size: 13.5px; font-weight: 900; color: var(--ink); }
.pub-subhead-sub { color: var(--ink-2); font-weight: 700; font-size: 12.5px; }
.pub-picked { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; min-height: 20px; }
.pub-pick-tag { display: inline-block; padding: 3px 10px; border-radius: 999px; background: rgba(0, 189, 166, .12); color: var(--brand-deep); font-size: 12px; font-weight: 800; }
.pub-hidden-chk { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pub-addrs { display: grid; gap: 8px; margin-bottom: 8px; }
.pub-addr { position: relative; display: block; }
.pub-addr input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pub-addr-in {
  display: block; padding: 10px 12px; border-radius: 12px; background: var(--surface-2);
  cursor: pointer; border: 1.5px solid transparent;
}
.pub-addr input:checked + .pub-addr-in { border-color: var(--brand); background: rgba(0, 189, 166, .08); }
.pub-addr-top { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.pub-addr-top b { color: var(--ink); }
.pub-mono { font-size: 12px; color: var(--ink-3); }
.pub-addr-in em { display: block; margin-top: 2px; font-style: normal; font-size: 12.5px; color: var(--ink-3); }
.pub-urgent { display: flex; gap: 10px; padding: 10px 12px; border-radius: 14px; background: var(--surface-2); cursor: pointer; }
.pub-urgent input { margin-top: 3px; }
.pub-urgent-in { display: block; min-width: 0; }
.pub-urgent-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pub-urgent-top b { font-size: 13.5px; color: var(--ink); }
.pub-urgent-in em { display: block; margin-top: 4px; font-style: normal; font-size: 12px; color: var(--ink-3); line-height: 1.55; }
.pub-draft-status { display: block; min-height: 18px; margin: 2px 4px 0; font-size: 11.5px; color: var(--ink-3); }

.pub-foot { padding: 8px 0 calc(16px + var(--safe-b)); }
.pub-go {
  display: block; width: 100%; border: 0; background: var(--brand); color: #fff;
  font: inherit; font-size: 16px; font-weight: 900; padding: 14px;
  border-radius: 999px; cursor: pointer; box-shadow: var(--sh-brand);
}
.pub-go:active { transform: translateY(1px); }
.pub-foot-note { margin: 8px 6px 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.55; text-align: center; }

.pub-toast {
  position: fixed; left: 50%; bottom: 96px; transform: translate(-50%, 12px);
  z-index: 80; max-width: 86vw; padding: var(--sp-md) var(--sp-2xl); border-radius: var(--r-pill);
  background: rgba(15, 20, 24, .86); color: #fff; font-size: 13px; font-weight: 700;
  opacity: 0; pointer-events: none; transition: all .25s;
}
.pub-toast.on { opacity: 1; transform: translate(-50%, 0); }
.pub { display: block; }
/* 来源地多选 chip：勾选态由 input:checked + span 控制（同 .pub-chip） */
.pub-chk span { padding: 6px 12px; font-size: 12.5px; }

/* ---- 发需求单页：折叠段（闲鱼式 —— 没填的地方只是一行字） ---- */
.pub-sec {
  background: var(--surface); border-radius: 18px; box-shadow: var(--sh-1);
  margin-bottom: 10px; overflow: hidden;
}
.pub-sec > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
  padding: 15px 14px; user-select: none; -webkit-tap-highlight-color: transparent;
}
.pub-sec > summary::-webkit-details-marker { display: none; }
.pub-sec-t { display: flex; align-items: center; gap: 6px; font-size: 14.5px; font-weight: 900; color: var(--ink); }
.pub-req { font-style: normal; font-size: 10.5px; font-weight: 800; color: var(--coral); background: rgba(255, 106, 69, .12); border-radius: 5px; padding: 1px 5px; }
.pub-sec-val { margin-left: auto; font-size: 12.5px; color: var(--ink-3); text-align: right; max-width: 55%; }
.pub-sec-val.is-set { color: var(--brand-deep); font-weight: 800; }
.pub-sec > summary::after {
  content: ''; flex: none; width: 7px; height: 7px; margin-left: 8px;
  border-right: 2px solid var(--ink-3); border-bottom: 2px solid var(--ink-3);
  transform: rotate(-45deg); transition: transform .2s;
}
.pub-sec[open] > summary::after { transform: rotate(45deg); }
.pub-sec[open] > summary { border-bottom: 1px solid var(--line); }
.pub-sec-in { padding: 12px 14px 14px; }
.pub-sec.is-bad { box-shadow: 0 0 0 2px var(--coral) inset; }

/* ---- 选城市页（闲鱼式，2026-09-30 派总第 3 条） ----
   大字「您的位置」+ 重新定位 + 周边城市/按省分组的胶囊网格。
   点任何城市立即生效（写 session 回来源页），选中定位城市时胶囊/大字前是准星图标。 */
.loc-hero {
  display: flex; align-items: center; gap: 10px;
  margin: 4px 2px 6px; padding: 14px;
  background: var(--surface); border-radius: 14px; box-shadow: var(--sh-1);
}
.loc-hero-city { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); min-width: 0; }
.loc-hero-city .ic { width: 18px; height: 18px; color: var(--brand); flex-shrink: 0; }
.loc-hero-city b { font-size: 22px; font-weight: 900; letter-spacing: -.02em; }
.loc-hero-city.is-none { color: var(--ink-3); }
.loc-hero-city.is-none b { font-size: 17px; }
.loc-now { padding: 2px 8px; border-radius: var(--r-pill); background: var(--brand-soft); color: var(--brand-deep); font-size: 11px; font-weight: 800; flex-shrink: 0; }
.loc-refresh {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  border: 0; background: none; color: var(--brand-deep);
  font-size: 13px; font-weight: 800; cursor: pointer; padding: 6px 4px; flex-shrink: 0;
}
.loc-refresh:disabled { color: var(--ink-3); }
.loc-refresh:active { transform: scale(.95); }
.loc-hint { margin: 0 2px; font-size: 12px; color: var(--ink-3); }
.loc-prov { display: block; margin: 12px 2px 6px; font-size: 12.5px; color: var(--ink-3); font-weight: 700; }
.loc-group { margin-bottom: 4px; }
.loc-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.loc-grid a {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 14px; border-radius: var(--r-pill);
  background: var(--surface); box-shadow: var(--sh-1);
  font-size: 13.5px; font-weight: 700; color: var(--ink);
}
.loc-grid a:active { background: var(--paper-2); }
/* T27：locate 页 IP 兜底估出的城市只高亮不代选 —— 点不点由用户决定 */
.loc-grid a.loc-guess, a.loc-guess { box-shadow: 0 0 0 2px var(--brand) inset; color: var(--brand-deep, var(--brand)); }
.loc-grid a .ic { color: var(--brand); }

/* ======================================================================
   两大板块的两种气质（派总 2026-10-05）
   ----------------------------------------------------------------------
   同一个 App 里住着两种内容，用户不该觉得「这俩是一个产品凑出来的」：

     · 小圈子（m-skin-cir）：年轻、活泼、轻松、多样化、生活化
       —— T51① 起底色回全站暖白（不再整页铺暖粉），活泼交给圆角更大、
          阴影更软、标题更粗、胶囊更圆、多彩分类胶囊、留白更松。

     · 小青柠需求池（m-skin-qn）：简约、温暖、专注、明快
       —— 底色更素净偏冷白、圆角收敛、阴影更浅更紧、标题字重降一档
          （少抢眼 = 让人专心看需求本身）、胶囊规整、价格更大更醒目。

   三条纪律（改这一节之前先读）：
   1. **不许动 :root 里的任何一个令牌**。app.css 与 m.css 的 :root 必须逐字相同，
      audit_mobile_tokens.py 逐条比对；在这里另起一套颜色 = 手机端和网页端分家。
      下面用的全部是**继承令牌**（--ink-2 / --brand-soft / --coral …）加 scoped 覆盖。
   2. **不许改盒模型**。`.m-ftab`（需求池三档胶囊）与 `.pc-cat`（小圈子分类胶囊）
      共用同一套尺寸，是 2026-09-30 派总定的口径，有单测钉着
      （test_the_two_entry_menus_share_one_pill_size）。所以这里只改**颜色**，
      改「形状」一律通过给它们各自的皮肤作用域加 border-radius / 字重，
      绝不改这两条基础规则本身。
   3. **只在这两种皮肤里生效**。m-skin-mid（消息/我的/订单等中间页）走中性，
      不许被社区的活泼色污染 —— 交易页要的是「稳」。
   开关在 templates/m/base.html 的 <body class="m-skin-{{ TOP_TAB }}">，
   判定口径复用 core/context_processors.py 的 TOP_TAB（不另判一次）。
   ====================================================================== */

/* —— 小圈子：大圆角 + 软阴影，底色回全站暖白 —— */
body.m-skin-cir {
  /* T51①（派总 2026-10-30「粉底收敛」）：不再整页铺暖粉底（原 --paper-cir
     已退役）—— 正文回全站 --paper 暖白，两种板块不会再「一个像相亲、一个像开会」；
     圈子的「活泼」交给保留的这些：大圆角、软阴影、多彩分类胶囊、海报粉橘渐变。 */
  --surface-2: #fbf3ea;
  /* 圆角整体放大：年轻、轻松、不端着的观感 */
  --r-sm: 14px;
  --r: 21px;
  --r-lg: 30px;
  --r-xl: 38px;
  /* 阴影更软、铺得更开（活物的影子是散的，硬物的影子是紧的） */
  --sh-1: 0 1px 2px rgba(26, 26, 29, .04), 0 10px 22px -12px rgba(26, 26, 29, .18);
  --sh-2: 0 2px 8px rgba(26, 26, 29, .06), 0 26px 48px -26px rgba(26, 26, 29, .28);
}

/* —— 小青柠需求池：素净底 + 收敛圆角 + 浅阴影 —— */
body.m-skin-qn {
  /* 底色仍偏暖（不是冷调的淡紫白 —— 冷白配珊瑚价会显廉价，违了「温暖」），
     但比 :root 的暖白更亮更素：干净 = 简约，明快 = 亮。 */
  --paper: var(--paper-qn);
  --paper-2: var(--paper-2-qn);
  --surface-2: #f7f4f1;
  /* 正文墨色也调暖一点点：纯冷黑（#1a1a1d）配珊瑚价格会打架 */
  --ink: #241f1c;
  --ink-2: #635c57;
  /* 圆角收回一档：简约 = 少一点装饰性的弧度 */
  --r-sm: 11px;
  --r: 16px;
  --r-lg: 22px;
  --r-xl: 30px;
  /* 阴影更浅更紧：卡片「贴」在纸上，而不是浮在纸上 —— 专注、不跳 */
  --sh-1: 0 1px 2px rgba(36, 31, 28, .03), 0 4px 12px -8px rgba(36, 31, 28, .10);
  --sh-2: 0 2px 5px rgba(36, 31, 28, .04), 0 18px 36px -22px rgba(36, 31, 28, .20);
}

/* ======================================================================
   一、小圈子侧：把「年轻 / 活泼 / 多样 / 生活化」落到实处
   ====================================================================== */

/* ① 分类胶囊每个圈子一个颜色 —— 「多样」最直接的信号。
   盒模型仍来自 .pc-cat 基础规则（不许在这里写 padding/min-height，
   见本节纪律 2）；这里只给不同序号的胶囊不同颜色，
   颜色全部取自既有令牌，不新造色 —— 新造色明天就会变成第二个真源。
   ⚠️ 第一版只换了底色，实测**太淡、看不出多样**（截图里四颗几乎一个样），
   所以现在给每颗也配一个**同色系深色图标**（currentColor 走 color）
   + 未选中时加一圈同色系描边，三样一起才看得出「彩」。 */
body.m-skin-cir .pc-cat { font-weight: 800; }

/* ② 「最新 / 热门」：L 波①（派总 2026-10-09）——与小青柠首页「附近/最新/热门」
   **同格式**（细字标签 + 选中 brand 底线），原来的整颗胶囊切换已删。
   格式统一由基础 .pc-tab 提供，这里不再有任何覆盖。 */
body.m-skin-cir .pc-tabs { gap: 14px; }

/* ③ 动态卡：更大的圆角（--r-lg 已放大）再叠一点「贴纸感」——
   白卡压在一层更浅的暖底上，图片像贴上去的照片，不是像网页里的图片。 */
body.m-skin-cir .pc-card { background: var(--surface); }
body.m-skin-cir .pc-card-title {
  font-size: 13.5px; font-weight: 800; line-height: 1.5;
  letter-spacing: -.005em;                     /* 放松一点：字距别太紧 */
}
body.m-skin-cir .pc-card-body { padding: 9px 11px 11px; }
/* T52（派总 2026-10-31）：卡片缝减半 12 → 6 —— 「呼吸感」过了头就是松散，
   两列之间和上下卡片之间的缝一起收，瀑布流重新紧凑起来。 */
body.m-skin-cir .pc-feed, body.m-skin-cir .pc-col { gap: 6px; }

/* ④ 点赞 / 评论这类小字在小圈子里权重抬一档：这一页是「看别人的生活」，
   别人的反应本身就是内容主体的一部分。 */
body.m-skin-cir .pc-card-foot { margin-top: 9px; }
body.m-skin-cir .pc-card-by { font-size: 11px; }
body.m-skin-cir .pc-card-by .av { width: 21px; height: 21px; font-size: 10.5px; }
/* 圈子标签用嫩芽绿（活泼的高亮），区别于需求卡的青绿 */
body.m-skin-cir .pc-card-circle {
  background: var(--lime-soft); color: var(--lime-ink); font-weight: 800;
}

/* ⑤ 无图时的「分类插画牌」：小圈子这块底色更亮一档、图标更大（活泼） */
body.m-skin-cir .pc-card-cover {
  background: linear-gradient(150deg, #fff4e8, var(--coral-soft));
  color: var(--coral-deep);
}
body.m-skin-cir .pc-card-cover .ic { width: 34px; height: 34px; }
body.m-skin-cir .pc-card-cover .stack { font-size: 12.5px; font-weight: 800; }

/* ⑥ 顶栏那颗「小圈子」tab 选中时：整颗深墨青，替掉全站通用的青绿底线 ——
   站在小圈子时，头顶也是「社区」的口气。 */
body.m-skin-cir .m-ttab.on { color: var(--jade); }
body.m-skin-cir .m-ttab.on::after { background: var(--jade); }

/* ======================================================================
   二、小青柠需求池侧：把「简约 / 温暖 / 专注 / 明快」落到实处
   ====================================================================== */

/* ① 三档胶囊：规整、克制。选中态是**品牌青绿**（行动色），
   保持全站口径；只把未选中的压得更素、更安静。 */
body.m-skin-qn .m-ftab { font-weight: 700; }
body.m-skin-qn .m-ftab:not(.on) {
  background: var(--surface); color: var(--ink-2); box-shadow: none;
  border: 1px solid var(--line-2);              /* 用细线代替阴影：更简约 */
}
/* ② 需求卡：标题字重降一档（600 已经在基础规则里，这里再压一点视觉噪声）、
   价格放大 —— 「明快」= 一眼先看见「多少钱、我要什么」。 */
body.m-skin-qn .m-dc-title { font-weight: 600; letter-spacing: -.015em; }
/* T16g-0：qn 换肤的 26px 只管数字价格 —— 不豁免的话「你来出价」也被放大
   （特异性压过 .is-quote 的 17px），四个汉字视觉比价格数字还大一号（派总截图）。 */
body.m-skin-qn .m-dc-price:not(.is-quote) { font-size: 26px; }
body.m-skin-qn .m-dc-body { padding: 9px 10px 11px; }
/* 卡片缝比小圈子紧一格：这一页是「办事」，不是「逛」 */
/* ③ 「匹配你的擅长」小标签：需求页的推荐位要清楚但不能抢戏 */
body.m-skin-qn .m-dc-why .m-tag { font-weight: 800; }

/* ④ 顶栏「小青柠」tab 选中：青绿底线 = 全站品牌口径，一个字都不改。 */

/* ======================================================================
   三、顶栏 tab 组：两页各自的强调色（很小，但决定了「我在哪块」的第一印象）
   ====================================================================== */
body.m-skin-cir .m-topswitch { background: #f4e7da; }
body.m-skin-qn  .m-topswitch { background: #edeaf0; }

/* ======================================================================
   两大板块 · 第二档（派总 2026-10-05 授权「可以按你的建议执行」）
   ----------------------------------------------------------------------
   第一档把两块的分开了（底色/圆角/阴影/胶囊），这一档往**细节气质**再推一格：

     · 小圈子（年轻/活泼/多样/生活化）—— 加彩色、加圆、加「贴纸感」：
         ① 卡片里的文字海报**跟着卡片圆角走**（改前是 3:4 直角块贴在大圆角卡上，
            四角戳在外面，看着像没做完）；顺手给海报字加一点手写体的松。
         ② 「流水账 / 视频」角标改成**彩色**而不是半透明黑块（黑块太沉）。
         ③ 卡片按下去时轻轻「缩一点」——网页版的 :active 反馈，手机上多半没感觉。

     · 小青柠（简约/温暖/专注/明快）—— 减装饰、让内容更整齐：
         ④ 筛选/类型胶囊改成「**连线段**」：未选中只留一条底线，选中底线加粗变青绿。
            （比「每颗都带个框」安静 —— 简约的真谛是减元素，不是换颜色。）
         ⑤ 卡片之间的缝**再收 1px**（8→7）：这一页是办事，一屏多看一条是一条。
         ⑥ 角标改成**实心小圆点式的轻底**，不压图（明快 = 少遮挡）。

   ⚠️ 仍然不许动 :root、不许改胶囊盒模型、每条规则都带 body.m-skin-* 前缀
   （这三条纪律由 tests.py 的 TwoBoardsTwoPersonalitiesTests 机械守着）。
   ====================================================================== */

/* —— 小圈子 ①：卡片里的海报跟着卡片圆角走 —— */
/* T 波⑤（派总 2026-10-10）：卡片圆角收敛 —— 原来 --r-lg=30px 太圆（「汤圆卡」），
   收到 --r-sm=14px：还是软的，但利落了。海报内层跟着收到 12px（同一条线）。
   T52（派总 2026-10-31）：圆角再砍半 14 → 7 —— 卡片缝收窄后圆角太大显得「泡」，
   半径取 var(--r-sm) 的一半，海报内层照旧跟着走（-2px 同一条线）。 */
body.m-skin-cir .pc-card { border-radius: calc(var(--r-sm) / 2); }
body.m-skin-cir .pc-card .pc-poster { border-radius: calc(var(--r-sm) / 2 - 2px); }
/* 竖版海报在双列瀑布流里太高了（3:4 会把一屏全占掉）→ 收成 4:5，
   刚好露出一张封面 + 两行标题，滑起来是「一屏好几条」而不是「一屏两条」。 */
body.m-skin-cir .pc-card .pc-poster.po-v { aspect-ratio: 4 / 5; }
body.m-skin-cir .pc-card .pc-poster.po-h { aspect-ratio: 5 / 4; }
body.m-skin-cir .pc-card .pc-poster b { letter-spacing: -.01em; }
body.m-skin-cir .pc-card .pc-poster i { opacity: .55; }   /* 署名淡一点，别抢标题 */

/* —— 小圈子 ②：角标底改奶油白玻璃（二轮⑦：文字用默认灰黑，不再 coral 红色） —— */
body.m-skin-cir .pc-card-kind {
  background: rgba(255, 250, 245, .92);          /* 奶油白玻璃 */
  color: var(--ink-2);
  box-shadow: 0 1px 4px rgba(26, 26, 29, .16);
}
body.m-skin-cir .pc-card .m-badge-float {
  background: rgba(255, 250, 245, .92);
  color: var(--ink-2);
}

/* —— 小圈子 ③：按下去轻轻缩一点（活泼的手感）—— */
body.m-skin-cir .pc-card:active { transform: scale(.985); }

/* —— 小青柠 ④：三档胶囊改成「连线段」—— */
/* ⚠️ 这里**绝对不许**写 min-height / padding / border-radius / min-width：
   `.m-ftab` 的盒模型是 2026-09-30 派总定的口径（「两个入口下方的菜单胶囊同尺寸同手感」），
   有单测 test_the_two_entry_menus_share_one_pill_size 逐个键比对 .pc-cat 与 .m-ftab；
   改了它就会把「两个入口一样大」这条规矩打破（我自己写完这条当场被那条单测拦下来了）。
   所以「连线段」只做两件事：**去掉底色与阴影**（减元素）+ **加一条底线**（加元素），
   盒子本身一点不动 —— 靠「有没有底色/有没有底线」区分，而不是靠大小。 */
body.m-skin-qn .m-ftab {
  background: transparent; box-shadow: none;
  border: 1px solid transparent;          /* 占位 1px：让尺寸与基础规则完全一致 */
  border-bottom: 2px solid var(--line-2);
}
body.m-skin-qn .m-ftab.on {
  background: transparent; color: var(--ink); box-shadow: none;
  border-color: transparent;
  border-bottom: 3px solid var(--brand);
  margin-bottom: -1px;                    /* 底线加粗 1px，但整排高度不变 */
}
/* 「筛选」那颗保持有边框（它是按钮不是 tab，形状本来就该是胶囊） */
body.m-skin-qn .m-fbtn {
  background: var(--surface); box-shadow: none;
  border: 1px solid var(--line-2);
}

/* —— 小青柠 ⑤：卡片缝 8 → 7 —— */
body.m-skin-qn .m-feed, body.m-skin-qn .m-feed-col { gap: 7px; }

/* —— 小青柠 ⑥：卡片角标改轻底，不压图 —— */
body.m-skin-qn .m-dc-badge { opacity: .92; }
body.m-skin-qn .m-dc-fav {
  background: rgba(255, 255, 255, .96);
  box-shadow: 0 1px 3px rgba(36, 31, 28, .10);
}

/* ======================================================================
   小圈子分类标签与分类菜单（派总 2026-10-05 第 3 条）
   ----------------------------------------------------------------------
   ① 每条内容的**分类标签胶囊移到封面左上角**，同「流水账」角标同一位置；
   ② 分类菜单由「多色循环」改为**单色**（同「茶水间」那一份色相）。

   ⚠️ ② 这次改单色是有道理的（上一波我做多色循环派总看过了，要求收回）：
      六个胶囊六个颜色，看着热闹但**没有一个是品牌色**，反而把「茶水间」那
      份沉稳的色相拉低了 —— 一排花色里没有主色。现在统一成单色 + 选中态加深，
      页面安静下来，也更像一个「分类栏」而不是「装饰」。
   ====================================================================== */

/* ① L 波②（派总 2026-10-09）：分类标签**高低一致** —— 形态角标（视频/流水账）
   和分类胶囊收进同一个定位容器 .pc-card-tags（absolute 只挂在容器上），
   容器内 flex 并排。原来的「有形态角标时胶囊掉到 top:30px」是高低不一的根因。 */
.pc-card-tags {
  position: absolute; z-index: 3;      /* 要浮在整卡可点层(.pc-card-link z-index:1)之上 */
  top: 6px; left: 6px;
  display: flex; align-items: center; gap: 4px;
  max-width: 86%;                       /* 长名字（避坑提醒）不撑破封面 */
}
.pc-card-kind { flex-shrink: 0; }
/* 基础规则给过 kind 一个 absolute（视频帖单用时自定位）——进容器后必须归位，
   不然它会挣脱 flex 排布、飞到卡片左上角和容器叠两层。 */
.pc-card-tags .pc-card-kind { position: static; }
.pc-card-cat {
  display: inline-flex; align-items: center; gap: 3px;
  min-width: 0;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: rgba(255, 250, 245, .92);  /* 奶油白玻璃，和形态角标同一套底 */
  color: var(--ink-2);
  font-size: 10px; font-weight: 800; line-height: 1.5;
  text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  box-shadow: 0 1px 4px rgba(26, 26, 29, .16);
}
.pc-card-cat .ic { width: 11px; height: 11px; flex-shrink: 0; }
.pc-card-cat:active { transform: scale(.97); }

/* ② L 波①（派总 2026-10-09）：分类菜单与**小青柠首页的菜单同格式**——
   白底胶囊（surface + 细边框 + 阴影，与 .m-ftab 同手感）+ 选中态 brand 式底线。
   原来的「浅绿整条底 + 墨青字」和后来的三色循环 / !important 覆盖块一并删除
   （覆盖块是用来压三色循环的，三色循环没了它也就没了存在意义）。
   点缀色仍用茶水间的墨青（--jade），跟小青柠的 brand 区分气质。 */
/* T17③：内边距归零 —— 左右 12px 由吸顶容器 .pc-menubar 的 padding 提供，
   这里再写一遍会把整排胶囊右移 12px（历史上就是这 12px 让两个入口的胶囊没对齐）。 */
.pc-cats { background: transparent; border-radius: 0; padding: 0; }
.pc-cat {
  background: var(--surface); border: 1px solid var(--line-2);
  color: var(--ink-2); box-shadow: var(--sh-1);
}
.pc-cat .ic { color: var(--jade); }
.pc-cat:not(.on):hover { background: var(--surface); }
.pc-cat.on {
  background: var(--surface); border-color: var(--line-2);
  color: var(--ink); box-shadow: var(--sh-1);
  border-bottom: 3px solid var(--jade);
  margin-bottom: -1px;                    /* 底线加粗 1px，整排高度不变（同 qn .m-ftab 手法） */
}
.pc-cat.on .ic { color: var(--jade); }
/* 正文里那个旧圈子标签已经搬去封面了，这里只兜住详情页等仍在用它的模板 */
body.m-skin-cir .pc-card-circle { background: transparent; color: var(--jade); padding: 0; }

/* ======================================================================
   圆梦单：求物品/求服务两套流程的界面（派总 2026-10-05）
   ====================================================================== */

/* ① 阶段条上被跳过的格：灰色 + 不点亮（名字后面的「（跳过）」由模板写）
   为什么用灰掉而不是隐藏：跳过的这一步**是流程的一部分**，藏起来的话
   需求方会以为「怎么从商榷直接就验收了，中间少了一环」。 */
/* 跳过的步骤（派总 2026-10-11）：文字灰 + 删除线，但进度段保持绿色 ——
   「这步没走，但单子确实推进到了这里」，条子不灰、字划掉。 */
/* L 波③（派总 2026-10-17 晚拍板，推翻 J 补丁的「跳过格灰条」）：
   所有进度条一律绿色；跳过只体现在文字上（灰字 + 删除线，见下一条）。 */
/* Q3 波②（派总 2026-10-20 截图再批）：**亮绿有个前提 —— 这一格已经走过**
   （i < stage_index）。以前 is-skip 无条件点亮，商榷还没谈完「制作」就是绿的，
   看起来像已经在制作；现在模板只给走过的跳过格挂 is-skip，
   没走到的挂 is-wait-skip（灰点 + 删除线预告，见下一条）。 */
.m-step.is-skip i { background: var(--brand); }
.m-step.is-skip span { color: var(--ink-4); text-decoration: line-through; text-decoration-thickness: 1px; }
/* Q3 波②：还没走到的跳过格 —— 圆点保持默认灰，只给文字删除线预告「这格会被跳过」。 */
.m-step.is-wait-skip span { color: var(--ink-4); text-decoration: line-through; text-decoration-thickness: 1px; }
/* Y⑤（派总 2026-10-11）：违约单不清零 —— 最后一格改「XX违约」，红条红字。
   这单是走完了（前面步骤照常亮绿灯），只是结局是违约，不是流单回原点。 */
.m-step.is-breach i { background: var(--coral) !important; }
.m-step.is-breach span { color: var(--coral); font-weight: 800; }

/* ② 方案里的选择区（勾选 + 新报价） */
.m-plan-opts { margin-top: 10px; }
.m-plan-opt {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 13.5px; line-height: 1.5;
}
.m-plan-opt input { width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--brand); }
.m-plan-opt b { font-weight: 900; }

/* ③ 方案历史：每一版一张小卡，状态用左边一道色条区分 */
.m-plans { display: grid; gap: 8px; margin-top: 10px; }
.m-plan-item {
  padding: var(--sp-md) var(--sp-lg); border-radius: var(--r-sm);
  background: var(--surface-2); border-left: 3px solid var(--ink-4);
}
.m-plan-item.is-pending { border-left-color: var(--warn); }
.m-plan-item.is-accepted { border-left-color: var(--brand); }
.m-plan-item.is-rejected { border-left-color: var(--coral); }
.m-plan-item-head { display: flex; align-items: center; gap: 6px; font-size: 12px; }
/* J 波①（派总 2026-10-09）：「提交时间」单独成行 —— 灰字，时间带**灰色下划线**；
   K 波②：时间**居右**（flex 推到行尾），商榷卡（方案）、进度更新卡、发货卡共用这一个样式。 */
.m-plan-submitat { margin-top: 4px; color: var(--ink-3); font-size: 12px; display: flex; align-items: baseline; }
.m-plan-submitat b {
  margin-left: auto; font-weight: 600; color: var(--ink-2);
  text-decoration: underline; text-decoration-color: var(--ink-4);
  text-underline-offset: 3px;
}
.m-plan-item-head b { font-size: 13px; font-weight: 900; }
.m-plan-state { font-weight: 800; }
.m-plan-state.st-pending { color: var(--warn); }
.m-plan-state.st-accepted { color: var(--brand-deep); }
.m-plan-state.st-rejected { color: var(--coral-deep); }
.m-plan-at { margin-left: auto; color: var(--ink-4); font-size: 11px; }
.m-plan-text { margin-top: 6px; font-size: 13px; line-height: 1.6; white-space: pre-wrap; }
.m-plan-price { margin-top: 6px; font-size: 12.5px; color: var(--ink-2); }
.m-plan-price b { font-size: 15px; color: var(--coral); font-weight: 900; }
.m-plan-reject {
  margin-top: 6px; padding: 6px 8px; border-radius: var(--r-xs);
  background: var(--danger-soft); color: var(--danger);
  font-size: 12px; line-height: 1.5;
}
/* K 波④（派总 2026-10-09）：附图缩略图**横向平铺**——3 列等宽网格铺满卡宽（不再 54~88px 小块）。
   方案附图 / 进度图 / 交付凭证共用；编辑区勾删图的 <label> 也吃同一套格子。 */
.m-plan-imgs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 8px; }
.m-plan-imgs img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--r-xs); cursor: zoom-in; }
.m-plan-imgs a { display: block; }
/* 编辑方案：已传图带「删除勾选」（2026-10-08 任务 C）——
   勾选框压在缩略图左上角，勾中 = 这张将随提交一起删掉：图变灰 + 珊瑚色描边。 */
.m-img-del { position: relative; display: block; }
.m-img-del input {
  position: absolute; left: 4px; top: 4px; z-index: 2;
  width: 17px; height: 17px; margin: 0; accent-color: var(--coral);
}
.m-img-del input:checked + img { opacity: .35; outline: 2px solid var(--coral); outline-offset: -2px; }
.m-plan-decide { margin-top: 12px; }

/* ④ 超时延期那一块 */
.m-ext { margin-bottom: 10px; }
.m-ext-box {
  display: block; padding: var(--sp-lg); border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 12.5px; line-height: 1.6;
}
.m-ext-box b { display: block; font-size: 13.5px; margin-bottom: 3px; }
.m-ext-box.is-warn { background: var(--warn-soft); }
.m-ext-box.is-pending { background: var(--warn-soft); }
.m-ext-box.is-ok { background: var(--brand-tint); }
.m-ext-box.is-no { background: var(--danger-soft); color: var(--danger); }

/* ⑤ 制作进度 */
.m-mk { margin-top: 6px; }
/* J 波②：进度条目改成纵向 —— 提交时间行（灰下划线）→ 描述文字 → 附图，全部居左，
   排布与「商榷 · 方案/物品描述」同款（原来时间和文字挤一行、图被挤到右边）。 */
.m-mk-item {
  padding: 8px 0; border-bottom: 1px solid var(--line);
  font-size: 12.5px;
}
.m-mk-note { margin: 4px 0 0; line-height: 1.5; }
/* K 波④：进度图也走统一网格（包一层 .m-plan-imgs，样式与方案附图同款）。 */
.m-mk-item .m-plan-imgs { margin-top: 6px; }

/* M 波②（派总 2026-10-17）：交付卡的两个选项按钮（进度上报 / 圆梦交付）。
   纯 <details> 实现（铁律：没有 JS 也不坏），展开哪边哪边高亮品牌色。 */
.m-opt-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.m-opt { min-width: 0; }
.m-opt-tabs details > summary {
  list-style: none; cursor: pointer; text-align: center;
  padding: 10px 8px; border-radius: 10px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  font-weight: 700; font-size: 13.5px; color: var(--ink-2);
  -webkit-user-select: none; user-select: none;
}
.m-opt-tabs details > summary::-webkit-details-marker { display: none; }
.m-opt-tabs details[open] > summary {
  background: var(--surface-2); border-color: var(--brand); color: var(--brand-deep);
}
.m-opt-panel { margin-top: 10px; }
.m-opt-panel .m-field { margin-top: 8px; }

/* N 波⑫（派总 2026-10-18）：两个选项 = 两个单选 tab，共用下方一组表单。
   radio 视觉隐藏但**可聚焦可点**（同 m-fopt 口径：不许 display:none ——
   那样 label 点击选不中、键盘也 tab 不到）；选中态纯 CSS（:checked + label），
   没有 JS 也照常能切。两个提交按钮各带 formaction，字段同一套。 */
.m-opt-tabs.is-radio { margin-top: 12px; }
.m-opt-tabs.is-radio input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.m-opt-tabs.is-radio .m-opt-tab {
  list-style: none; cursor: pointer; text-align: center;
  padding: 10px 8px; border-radius: 10px;
  background: var(--surface-2); border: 1.5px solid var(--line);
  font-weight: 700; font-size: 13.5px; color: var(--ink-2);
  -webkit-user-select: none; user-select: none;
}
.m-opt-tabs.is-radio input:checked + .m-opt-tab {
  background: var(--surface-2); border-color: var(--brand); color: var(--brand-deep);
}
.m-opt-tabs.is-radio input:focus-visible + .m-opt-tab {
  outline: 2px solid var(--brand); outline-offset: 2px;
}

/* .m-plan-hist：方案历史那整块卡（templates/m/_order_plan_hist.html 的根节点）。
   与页面里其它卡一致留 14px 上间距。 */
.m-plan-hist { margin-top: 14px; }

/* ======================================================================
   圆梦单整页三态（派总 2026-10-05）
   ----------------------------------------------------------------------
   · **已结束**的步骤：内容折叠（`details.is-todo` 反过来：已结束用 `m-step-fold`），
     仍按步骤顺序从上到下排 —— 要能回看当时谈了什么、干了什么；
   · **还没开始**的步骤：只给一个标题占位卡（`is-todo`），点不了、也不该看到空表单；
   · **正在进行**的步骤：可编辑、可上传、可聊一聊（`is-now`）。

   ⚠️ 折叠用 `<details>` 而不是 JS：没 JS 也能展开看内容（无障碍也免费）。
*/
.m-step-card.is-done { background: var(--surface-2); }
/* J 波③（派总 2026-10-09）：步骤卡头部的状态胶囊**左右必须对齐**。
   病根：胶囊靠 margin-left:auto 推右，但右侧还有一颗折叠箭头，
   各卡标题长短不一 + 箭头占位，胶囊就一卡一个位置。
   修法：标题 flex:1 吃掉剩余空间（胶囊被推到箭头左侧固定位置），
   箭头绝对定位钉在卡的最右；所有卡统一留 26px 右内边距 ——
   没箭头的「还没开始 / 进行中」卡也留，胶囊位置全站一致。 */
.m-step-card .m-sec-head { position: relative; padding-right: 26px; }
.m-step-card .m-sec-head > b { flex: 1 1 auto; }
.m-step-card .m-step-caret {
  position: absolute; right: 0; top: 50%;
  transform: translateY(-50%); margin: 0;
}
/* I 波②（派总 2026-10-09）：已完成的步骤卡**行间距减半**（14px → 7px）。
   为什么：订单走完后页面上会叠四五张「已完成」的折叠卡，14px 一张接一张，
   中间那条白带比卡片本身还抢眼，整页看着散。压到 7px 后一屏能多看一张卡。
   ⚠️ 卡片上写着内联 style="margin-top:14px"，普通类选择器压不住内联，必须 !important。 */
.m-step-card.is-done { margin-top: 7px !important; }
.m-step-fold > summary { list-style: none; cursor: pointer; }
.m-step-fold > summary::-webkit-details-marker { display: none; }
.m-step-fold > .m-sec-head { margin-bottom: 0; }
.m-step-fold[open] > .m-step-summary .m-step-caret { transform: translateY(-50%) rotate(180deg); }
.m-step-caret { margin-left: auto; transition: transform .18s; }
/* 已结束那步展开后，内容与标题之间要留白 */
.m-step-fold[open] > *:not(summary) { margin-top: 10px; }

/* 步骤状态标签：已完成 / 进行中 / 还没开始 */
.m-step-tag {
  margin-left: auto; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--line); color: var(--ink-3);
  font-size: 11px; font-weight: 800; white-space: nowrap;
}
/* N 波⑦⑧（派总 2026-10-18）：步骤卡头右侧的「这一步几号发生的」——
   交易记录时间线并入各卡后，每个节点的历史时间点就长在卡头这里。
   放在 b（flex:1）和 m-step-tag 之间：标题越长它越靠左贴标题，位置自然。 */
.m-step-time { font-size: 11px; font-weight: 600; color: var(--ink-3);
  white-space: nowrap; flex-shrink: 0; }
.m-step-tag.is-now { background: var(--brand); color: #fff; }
/* 「还没开始」的占位卡整体压暗，一眼看出「这里还没到」 */
.m-step-card.is-todo { background: var(--surface-2); opacity: .6; }
.m-step-card.is-todo .m-sec-head b { color: var(--ink-3); }
/* 进行中的那张卡给一道左边框，强调「现在在这儿」 */
.m-step-card.is-now { box-shadow: inset 3px 0 0 var(--brand); }

/* ======================================================================
   交付表单精简 + 服务完成证明（派总 2026-10-05）
   ====================================================================== */

/* ——「服务完成证明」卡 —— */
.m-proof { margin-top: 14px; }
.m-proof .m-sec-head { margin-bottom: 2px; }
.m-proof-item {
  padding: 10px 0; border-bottom: 1px solid var(--line);
}
.m-proof-item .m-mk-at { margin-bottom: 2px; }
.m-proof-files { display: grid; gap: 6px; margin-top: 8px; }
.m-proof-file {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--ink-2);
  font-size: 12.5px; text-decoration: none;
}
.m-proof-file b { flex: 1; min-width: 0; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-proof-file .meta { color: var(--ink-4); font-size: 11px; flex-shrink: 0; }
/* 提交表单：几类材料各自一块，不要挤在一起（手机上一次只选一个文件最省事） */
.m-proof-form { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line-2); }
.m-proof-form .m-field { margin-top: 10px; }
.m-proof-form .m-field:first-child { margin-top: 0; }

/* ——「去发货 / 无需发货」两个按钮：比原来三颗更宽、更好点 —— */
/* ⚠️ 派总 2026-10-05：只留两个（去发货 / 无需发货），点了「无需发货」直接能提交。
   两颗等宽铺满（原来三颗挤在一行、每颗都很窄难点）。 */
.m-ship-modes { display: flex; gap: 8px; }
.m-ship-modes > label { flex: 1; }
.m-ship-modes > label > span {
  justify-content: center; width: 100%;
  padding: 11px 8px; font-size: 13.5px; font-weight: 800;
}
/* 收发件人块：地址属于「人」不属于「快递公司」——
   切换快递公司/发货方式时它一直在外面，不会被折叠、不会变灰（派总 2026-10-05）。 */
.m-parties { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.m-parties .p {
  padding: 10px; border-radius: var(--r-sm); background: var(--surface-2);
}
.m-parties .p > b { display: block; font-size: 12px; color: var(--ink-3); }

/* ==================== W 波 2026-10-10 · 编辑需求图块编辑器 + 加价卡 ==================== */
.ed-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px;
}
.ed-tile {
  position: relative; aspect-ratio: 1 / 1; border-radius: var(--r-sm);
  overflow: hidden; background: var(--surface-2); cursor: pointer;
}
.ed-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ed-tile.is-cover { box-shadow: inset 0 0 0 2.5px var(--coral); }
.ed-tile.is-drag { box-shadow: inset 0 0 0 2.5px var(--coral), 0 8px 18px rgba(16,60,55,.28); transform: scale(1.06); z-index: 5; }
/* T18 优化③：换序改成共享模块的「拖起 + 目标高亮」口径（原来是拖动中实时挪节点，
   和另外三处宫格手感不一样），所以这里补上 is-over。 */
.ed-tile.is-over { outline: 2px solid var(--brand); outline-offset: 1px; }
.ed-cover {
  position: absolute; left: 0; bottom: 0; padding: 2px 7px;
  font-size: 10.5px; font-weight: 800; color: #fff;
  background: rgba(16, 60, 55, .78); border-radius: 0 var(--r-sm) 0 0;
  display: none;
}
.ed-tile.is-cover .ed-cover { display: block; }
.ed-del {
  position: absolute; right: 4px; top: 4px; width: 22px; height: 22px;
  border: 0; border-radius: 50%; background: rgba(0, 0, 0, .55);
  color: #fff; display: grid; place-items: center; padding: 0; cursor: pointer;
}
.ed-del .ic { width: 12px; height: 12px; }
.ed-add {
  aspect-ratio: 1 / 1; border: 1.5px dashed var(--line, #cfd8d6); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--ink-3); display: grid; place-items: center;
  padding: 0; cursor: pointer;
}
.ed-add .ic { width: 24px; height: 24px; }
.ed-choices { display: grid; gap: 8px; margin-bottom: 10px; }
.ed-choices .att-act { border: 1px solid var(--line, #dfe7e5); border-radius: var(--r-sm); }
/* Y 波③（派总 2026-10-15）：需求单修改页「价格 - 议价方式」同一行。
   左边价格占大头，右边议价 chips 收窄；窄屏也不换行（两个格子各留最小宽）。 */
.ed-price-row { display: flex; gap: 12px; align-items: flex-end; flex-wrap: nowrap; }
.ed-price-cell { flex: 1 1 55%; min-width: 0; }
.ed-neg-cell { flex: 1 1 45%; min-width: 0; }
.ed-neg-cell .pub-chips { margin-top: 2px; }

/* ==================== W 波 2026-10-10 · 圈子用户名/流水账胶囊/备注折叠 ==================== */
.pc-user { color: #0b5a54; font-weight: 700; text-decoration: none; }
/* 二轮⑦（派总 2026-10-12）：is-story / is-ledger 的彩色底已删 ——
   左上角标签一律回落到 .pc-card-kind 的默认灰黑，不再红/青抢眼。 */

/* X① 后详情页实动作容器；派总 2026-10-12 第 ① 条：重排为等宽三栏（收藏 | 分享 | 删除） */
.pcp-stats { display: flex; align-items: stretch; margin-top: 14px;
  border-top: 1px solid var(--line, #ececec); }
.pcp-stat { flex: 1; display: inline-flex; align-items: center; justify-content: center;
  gap: 5px; border: 0; background: none; color: var(--ink-2, #5f6268);
  font-weight: 700; cursor: pointer; font-size: 13.5px; padding: 13px 4px; text-decoration: none; }
.pcp-stat + .pcp-stat { border-left: 1px solid var(--line, #ececec); }
.pcp-stat .ic { fill: none; }
.pcp-stat.on { color: var(--coral); }
.pcp-stat.on .ic { fill: currentColor; }

/* ============ 评论 / 回复（派总 2026-10-12 第 ① 条） ============ */
.pcp-comments { margin-top: 18px; }
.pcp-cmt-title { font-size: 15px; font-weight: 800; margin: 0 0 10px;
  display: flex; align-items: center; gap: 6px; }
.pcp-cmt-count { color: var(--ink-3, #9a9da3); font-weight: 700; font-size: 13px; }
.pcp-cmt-list { display: flex; flex-direction: column; gap: 16px; }
.pcp-cmt-empty { color: var(--ink-3, #9a9da3); font-size: 13px; text-align: center;
  padding: 14px 0; margin: 0; }
.pcp-cmt { display: flex; gap: 10px; }
.pcp-cmt-ava { flex: 0 0 auto; }
.pcp-cmt-ava .av { width: 36px; height: 36px; border-radius: 50%; object-fit: cover;
  display: block; font-size: 13px; }
.pcp-cmt-body { flex: 1; min-width: 0; }
.pcp-cmt-meta { display: flex; align-items: baseline; gap: 8px; }
.pcp-cmt-meta b { font-size: 13.5px; color: var(--jade, #103c37); font-weight: 800; }
.pcp-cmt-meta b a { color: inherit; text-decoration: none; }
.pcp-cmt-meta span { font-size: 11px; color: var(--ink-3, #9a9da3); }
.pcp-cmt-text { margin: 3px 0 6px; font-size: 14px; line-height: 1.5;
/* Z6⑬ 多级评论：回复的回复前缀「回复 @谁：」—— 深青弱化成次要信息，
   跟后面的正文同字号，不抢视线。 */
.pcp-cmt-rto { color: #0b5a54; font-weight: 700; }
/* Z6⑬ 多级评论：回复的回复前缀「回复 @谁：」—— 深青弱化成次要信息，
   跟后面的正文同字号，不抢视线。 */
  color: var(--ink); white-space: pre-wrap; word-break: break-word; }
.pcp-cmt-acts { display: flex; align-items: center; gap: 16px; }
.pcp-cmt-like { display: inline-flex; align-items: center; gap: 4px; border: 0;
  background: none; color: var(--ink-3, #9a9da3); cursor: pointer; font-size: 12.5px;
  font-weight: 700; padding: 0; }
.pcp-cmt-like .ic { fill: none; }
.pcp-cmt-like.on { color: var(--coral); }
.pcp-cmt-like.on .ic { fill: currentColor; }
.pcp-cmt-reply { border: 0; background: none; color: var(--ink-3, #9a9da3);
  cursor: pointer; font-size: 12.5px; font-weight: 700; padding: 0; }
.pcp-cmt-replies { margin-top: 14px; display: flex; flex-direction: column; gap: 14px;
  padding-left: 12px; border-left: 2px solid var(--line, #ececec); }
.pcp-cmt--reply .av { width: 30px; height: 30px; font-size: 11px; }

/* R7（派总 2026-10-21 晚）：评论配图改**小缩略图**（72px 小方格，最多 4 个一行），
   点击进全站灯箱（data-gallery）看大图、左右翻阅。 */
.pcp-cmt-imgs { display: flex; flex-wrap: wrap; gap: 6px;
  margin: 2px 0 8px; }
.pcp-cmt-imgs img { width: 72px; height: 72px; object-fit: cover;
  border-radius: 8px; display: block; background: var(--paper-2, #f3f2ee);
  cursor: zoom-in; }

/* R7：删自己的评论（跟「回复」同款灰字，点了 AJAX 就地摘节点） */
.pcp-cmt-del { border: 0; background: none; color: var(--ink-3, #9a9da3);
  cursor: pointer; font-size: 12.5px; font-weight: 700; padding: 0; }

/* R5⑥：评论输入卡的选图预览行（发送前本地缩略，可单张 × 掉） */
.pcp-cmt-imgprev { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pcp-cmt-imgcell { position: relative; width: 56px; height: 56px; }
.pcp-cmt-imgcell img { width: 100%; height: 100%; object-fit: cover;
  border-radius: 8px; display: block; background: var(--paper-2, #f3f2ee); }
.pcp-cmt-imgx { position: absolute; top: -5px; right: -5px; width: 18px; height: 18px;
  border: 0; border-radius: 50%; background: rgba(43, 46, 51, .78); color: #fff;
  font-size: 12px; line-height: 16px; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center; }

/* 评论输入行 + 表情面板 */
.pcp-cmt-form { position: relative; display: flex; align-items: flex-end; gap: 8px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line, #ececec); }
.pcp-emoji-btn { flex: 0 0 auto; border: 0; background: none; font-size: 20px;
  line-height: 1; cursor: pointer; padding: 6px 2px; }
.pcp-cmt-input { flex: 1; min-width: 0; resize: none; border: 1px solid var(--line, #d8dade);
  border-radius: 18px; padding: 9px 14px; font-size: 14px; line-height: 1.4;
  max-height: 120px; font-family: inherit; }
.pcp-cmt-input:focus { outline: none; border-color: var(--brand); }
.pcp-cmt-cancel { flex: 0 0 auto; border: 0; background: none; color: var(--ink-3);
  font-size: 13px; cursor: pointer; padding: 6px; }
.pcp-cmt-send { flex: 0 0 auto; border: 0; background: var(--brand); color: #fff;
  font-weight: 800; font-size: 13.5px; padding: 9px 16px; border-radius: 18px; cursor: pointer; }
.pcp-cmt-send:disabled { opacity: .5; }
.pcp-cmt-login { display: block; margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--line, #ececec); color: var(--brand); font-weight: 700;
  text-decoration: none; font-size: 13.5px; text-align: center; }
.pcp-emoji-panel { position: absolute; left: 0; right: 0; bottom: calc(100% + 6px);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--sh-2); padding: var(--sp-sm); display: grid;
  grid-template-columns: repeat(8, 1fr); gap: 2px; max-height: 160px; overflow-y: auto; z-index: var(--z-sticky); }
.pcp-emoji-panel[hidden] { display: none; }
.pcp-emoji { border: 0; background: none; font-size: 20px; line-height: 1; cursor: pointer;
  padding: 4px; border-radius: 8px; }
.pcp-emoji:active { background: var(--line, #ececec); }

/* ==================== 二轮 2026-10-12 · 派总 ②④⑤⑥⑦ ==================== */

/* —— ② 顶栏「关注」胶囊（三轮②改描边款：青边白底，派总 2026-10-12）——
   招式照 .m-btn-line：inset box-shadow 画 1.5px 青边，**不碰盒模型** ——
   描边款视觉上更轻，但 padding/尺寸一动不动，顶栏不会跳。 */
.pcp-follow-form { flex-shrink: 0; margin-left: 8px; }
.pcp-follow {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 58px; height: 30px; padding: 0 14px;
  border: 0; border-radius: var(--r-pill);
  background: var(--surface); color: var(--brand-deep);
  box-shadow: inset 0 0 0 1.5px var(--brand);
  font-size: 13px; font-weight: 800; cursor: pointer; white-space: nowrap;
}
.pcp-follow:active { background: var(--brand-soft, #e6f7f4); }
.pcp-follow.on { background: var(--brand-soft, #e6f7f4); color: var(--brand-deep); }

/* —— ② 底部固定条：评论框 + 点赞 + 收藏 —— */
.pcp { padding-bottom: calc(64px + var(--safe-b) + 12px); }  /* 给固定条让位 */
.pcp-dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  background: var(--paper);
  border-top: 1px solid var(--line, #ececec);
  padding: 8px 12px calc(var(--safe-b) + 8px);
}
/* 展开态（三轮①，派总截图批「两个说点什么」）：假框那一行让位，
   只留真正的输入卡；整条固定条浮起一点，跟页面内容分层。 */
.pcp-dock.is-open { box-shadow: 0 -8px 28px rgba(16, 60, 55, .12); }
.pcp-dock.is-open .pcp-dock-bar { display: none; }
.pcp-dock-bar { display: flex; align-items: center; gap: 14px; }
.pcp-dock-box {
  flex: 1; min-width: 0; text-align: left;
  height: 36px; padding: 0 14px;
  border: 0; border-radius: var(--r-pill);
  background: var(--paper-2, #f3f2ee); color: var(--ink-3);
  font-size: 13.5px; cursor: pointer;
}
.pcp-dock-act { flex-shrink: 0; }
/* T34（派总 2026-10-29）：「动态设置」钮的类直接挂在 button 自身（无父级包裹），
   原选择器匹配不到它 → 一直吃浏览器默认灰底 outset 边框（改齿轮后裸奔更难看）。补上同挂式。 */
.pcp-dock-act button, button.pcp-dock-act {
  display: inline-flex; align-items: center; gap: 4px;
  border: 0; background: none; cursor: pointer;
  color: var(--ink-2); font-size: 12.5px; font-weight: 700;
  padding: 4px 2px;
}
.pcp-dock-act .ic-sm { width: 20px; height: 20px; }
.pcp-dock-act.pcp-like.on button { color: var(--coral); }
.pcp-dock-act.pcp-fav.on button { color: var(--coral); }
/* 展开后的输入区 = 一张白卡（圆角 + 轻投影）：输入框去边框长在卡里，
   focus-within 时卡片描一圈青边 —— 一眼知道正在这条里打字。
   form 加 position:relative 是为了让表情面板（absolute）贴在卡片上方。
   ⚠️ N 波⑨（派总 2026-10-18）：form 必须是**纵向 flex** —— 之前不是，
   textarea 的 `flex:1` 找不到 flex 父级就失效，宽度退回默认 cols（约左半边），
   表现就是「输入框只有左半边能打字」。textarea 也补 width:100% 双保险。 */
.pcp-dock-expand { padding-bottom: 0; }
.pcp-dock-expand form {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-radius: 16px;
  box-shadow: var(--sh-1);
  padding: 8px 12px 6px;
}
.pcp-dock-expand form:focus-within { box-shadow: inset 0 0 0 1.5px var(--brand), var(--sh-1); }
.pcp-dock-expand .pcp-cmt-input {
  width: 100%;
  border: 0; background: transparent; padding: 6px 2px; border-radius: 10px;
}
.pcp-dock-expand .pcp-cmt-input:focus { border: 0; }
.pcp-dock-tools { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.pcp-dock-tools .pcp-dock-grow { flex: 1; }
.pcp-tool {
  border: 0; background: none; cursor: pointer;
  font-size: 18px; line-height: 1; padding: 4px 6px; border-radius: 8px;
}
.pcp-tool:active { background: var(--paper-2, #f3f2ee); }
.pcp-tool.pcp-mic.on { color: var(--coral); animation: pcp-pulse 1.1s infinite; }
/* T29②（派总 2026-10-29）：评论「添加地点」那颗图钉选完地点后保持高亮，
   让人看得见这条评论挂了地点（chip 在输入框下面，眼睛不一定扫得到）。
   ⚠️ 必须写死属性选择器：`.pcp-tool.on` 会连带把录音中的麦克风也刷成品牌绿底。 */
.pcp-tool[data-cmt-loc-toggle].on { color: var(--brand-deep); background: var(--brand-soft, #e6f7f4); }
@keyframes pcp-pulse { 50% { opacity: .45; } }
.pcp-mention-panel {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px;
  max-height: 132px; overflow-y: auto; z-index: var(--z-sticky);
}
.pcp-mention-panel[hidden] { display: none; }
.pcp-mention {
  border: 0; background: var(--brand-soft, #e6f7f4); color: var(--brand-deep);
  font-size: 12.5px; font-weight: 700; padding: 5px 10px;
  border-radius: var(--r-pill); cursor: pointer;
}
.pcp-del-form { margin-top: 12px; text-align: center; }
.pcp-del-form button {
  border: 0; background: none; cursor: pointer;
  color: var(--ink-3); font-size: 12.5px; text-decoration: underline;
}

/* —— ⑤ 头像面板两步：先三选一 → 再出 50 格 —— */
.av-step[hidden] { display: none; }
.av-opts { display: flex; gap: 10px; margin: 4px 0 12px; }
.av-opt {
  flex: 1; display: grid; justify-items: center; gap: 6px;
  padding: 16px 6px 12px; border: 1px solid var(--line, #ececec);
  border-radius: 14px; background: var(--paper-2, #f3f2ee);
  color: var(--ink); font-size: 13.5px; font-weight: 800; cursor: pointer;
}
.av-opt:active { background: var(--brand-soft, #e6f7f4); }
.av-opt .ic { width: 24px; height: 24px; color: var(--brand-deep); }
.av-step-back { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.av-back {
  display: inline-flex; align-items: center; gap: 2px;
  border: 0; background: none; cursor: pointer;
  color: var(--brand-deep); font-size: 13.5px; font-weight: 800; padding: 4px 2px;
}
.av-back .ic { width: 16px; height: 16px; transform: rotate(180deg); }
.av-step-back .av-sheet-sub { margin: 0; }


/* ==================== 第四波（派总 2026-10-13） ==================== */
/* ① 订单页需求卡里的「需求详情」文字：成交行下方、用户信息上方。 */
.m-demdesc {
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line);
}
.m-demdesc b {
  display: block; font-size: 11.5px; color: var(--ink-3); font-weight: 800;
  letter-spacing: 0.02em;
}
.m-demdesc p {
  margin: 4px 0 0; font-size: 13px; line-height: 1.7; color: var(--ink-2);
  white-space: pre-wrap; word-break: break-word;
}
/* ② 站内分享卡片：聊天里 link 消息带首图缩略图时的长相（_bubble.html）。 */
.m-sharecard {
  display: flex; gap: 8px; align-items: center; text-decoration: none;
  color: inherit; border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--sp-sm); background: var(--paper); max-width: 260px;
}
.m-sharecard img {
  width: 52px; height: 52px; border-radius: 8px; object-fit: cover; flex-shrink: 0;
}
.m-sharecard .sc-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.m-sharecard .sc-body b {
  font-size: 13px; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
}
.m-sharecard .sc-body .sc-src { font-size: 11px; color: var(--ink-3); }
/* ③ 分享抽屉：站内好友名单面板（_share.html / share.js）。 */
.sh-inner { border-top: 1px dashed var(--line); margin-top: 12px; padding-top: 12px; }
.sh-inner-head { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.sh-inner-head b { font-size: 13px; }
.sh-inner-head .sh-x { margin-left: auto; }
.sh-friends { display: flex; flex-direction: column; gap: 4px; max-height: 260px; overflow-y: auto; }
.sh-friend .sh-friend-sub { font-size: 11px; color: var(--ink-3); }
.sh-empty { font-size: 12px; color: var(--ink-3); text-align: center; padding: 14px 0; }

/* ============ 第六波③：分享抽屉好友平铺（圆形头像+下方昵称，横向滑动） ============
   ⚠️ 第七波①修正：选择器必须带 .sh-sheet 提高特异性 —— 两端共用的 share.css
   也在加载序列里且排在 m.css 之后，同样写着 .sh-friends{flex-direction:column}
   （网页版竖排兜底）。不带前缀的话同特异性后加载者赢，手机端横排被悄悄盖回纵向。 */
.sh-sheet .sh-friends { display: flex; flex-direction: row; gap: 10px; max-height: none;
  overflow-x: auto; overflow-y: hidden; padding: var(--sp-2xs) var(--sp-2xs) var(--sp-sm); -webkit-overflow-scrolling: touch; }
.sh-friend {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 4px 2px; border: 0; border-radius: 12px; background: none;
  cursor: pointer; width: 60px; flex-shrink: 0; text-align: center;
}
.sh-friend:active { background: var(--soft, #f3f6f5); }
.sh-friend img, .sh-friend .sh-av-fb {
  width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
  background: var(--soft, #eef2f1); display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; color: var(--ink-3);
}
.sh-friend .sh-friend-name {
  font-size: 11px; font-weight: 700; max-width: 60px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sh-friend .sh-friend-sub { display: none; }

/* 第六波④⑤：收藏 on 态星形实心 + 底部评论项 */
.pcp-dock-act.pcp-fav.on .ic { fill: currentColor; }
.pcp-cmt-jump { position: relative; z-index: 2; margin: 0; }
.pcp-cmt-jump { display: inline-flex; align-items: center; gap: 3px; color: var(--ink-3); font-size: 11px; font-weight: 800; background: none; border: 0; cursor: pointer; }

/* 第八波①（派总 2026-10-13）：需求详情底栏左下按钮 = 与小圈子内容底部（pcp-dock-act）
   同一款视觉：图标 + 小字横排、无底无框；分享只留图标。
   ⚠️ 不吃 .m-actions > .m-btn 的 flex:1（这些不是 m-btn），左下紧凑、spacer 推右。 */
.m-actions .m-dock-act {
  display: inline-flex; align-items: center; gap: 4px;
  border: 0; background: none; cursor: pointer; text-decoration: none;
  color: var(--ink-2); font-size: 12.5px; font-weight: 700;
  padding: 4px 2px; position: relative; white-space: nowrap;
}
.m-actions .m-dock-act .ic-sm { width: 20px; height: 20px; }
/* P 波③（派总 2026-10-19）：未读角标挪离「聊一聊」文字。
   Q 波①（派总 2026-10-20）：改成**圆形数字小角标** —— 上次只挪了位置没换形状，
   padding 胶囊横条压在图标上。现在对齐 .m-act-dot 基础款（本文件 798 行）的圆形
   形态：16px 正圆（一位数），两位数自动放宽成小胶囊；grid 居中，数字不再把字盖住。
   Q3 波①（派总 2026-10-20 截图再批）：角标挂到**「聊一聊」整颗按钮的右侧、
   偏上 0.2 个字符**（top:-0.2em 即 0.2 字高）—— 原来挂在图标正上方，
   派总要求挪到按钮右上角。锚点从 left 改为 right（left 置 auto，
   防止 left+right 同时生效把绝对定位元素拉伸成横条 —— Q 波①同款坑）。 */
.m-actions .m-dock-act .m-act-dot {
  position: absolute; top: -0.2em; left: auto; right: -3px;
  min-width: 16px; height: 16px; padding: 0 4px;
  display: grid; place-items: center;
  box-sizing: border-box; line-height: 1;
  font-style: normal; font-size: 10px; font-weight: 800;
  background: var(--coral); color: #fff; border-radius: 999px;
}
/* 派总 2026-10-20 优化：已发布需求「聊一聊」角标只显示红点、不显示数字 */
.m-actions .m-dock-act .m-act-dot.is-dot {
  min-width: 0; width: 9px; height: 9px; padding: 0; font-size: 0;
  right: -2px; top: -0.1em;
}

/* ================= 第九波（派总 2026-10-13） ================= */
/* ② 标题行：可编辑输入框 + AI 生成按钮（复用旧 .pub-title-row input 基础样式） */
.pub-title-input, .pub-title-row input { flex: 1; min-width: 0; border: 0; background: none; font: inherit; font-size: 14.5px; font-weight: 700; color: var(--ink); }
.pub-title-ai {
  border: 0; background: none; cursor: pointer; flex: none;
  color: var(--brand-deep); font-size: 12.5px; font-weight: 800;
  padding: 4px 6px; white-space: nowrap;
}
.pub-title-ai:active { opacity: .7; }
/* ③ 分类「＋ 其他」展开的行内输入 */
.pub-cat-other-btn span { color: var(--brand-deep); font-weight: 800; border: 1px dashed var(--brand); background: none; }
.pub-cat-other { display: flex; gap: 6px; width: 100%; align-items: center; }
.pub-cat-other .m-input { flex: 1; min-width: 0; height: 36px; padding: 0 10px; }
.pub-cat-other .pub-cat-ok { flex: none; height: 36px; padding: 0 14px; }

/* ==================== 第十波（2026-10-14） ==================== */
/* ① 聊一聊搬进帖子详情底部固定条（输入框左侧） */
.pcp-dock-chat-form { flex-shrink: 0; display: flex; }
.pcp-dock-chat {
  display: inline-flex; align-items: center; gap: 5px;
  height: 32px; padding: 0 12px;
  border: 1px solid rgba(0, 189, 166, .45); border-radius: var(--r-pill);
  background: rgba(0, 189, 166, .07); color: var(--brand-deep);
  font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.pcp-dock-chat .ic-sm { width: 15px; height: 15px; }
.pcp-dock-chat:active { background: rgba(0, 189, 166, .16); }
/* ③ 信用分明细：分数列定宽右对齐，余数小字跟齐（无详情行也上下对齐） */
.m-li-log .m-log-amt { min-width: 58px; }
/* ④ 仲裁庭：提示+统计卡包进松绿圆角框（仿「我的」页 .m-mehead 头衔框） */
.court-hero {
  background: linear-gradient(135deg, var(--jade) 0%, #1c5550 62%, #24645d 100%);
  border-radius: var(--r-lg); padding: 14px; margin-bottom: 4px;
  color: #fff; position: relative; overflow: hidden;
}
.court-hero::after {
  content: ''; position: absolute; right: -34px; top: -46px;
  width: 148px; height: 148px; border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 189, 166, .42), transparent 68%);
  pointer-events: none;
}
.court-hero-in { position: relative; z-index: 1; }
.court-hero .m-secure b { color: #fff; }
.court-hero .m-secure span { color: rgba(255, 255, 255, .78); }
.court-hero .m-secure .ic { color: #7fe0d3; }
.court-stat.hero { background: rgba(255, 255, 255, .1); box-shadow: none; }
.court-stat.hero b { color: #fff; }
.court-stat.hero span { color: rgba(255, 255, 255, .72); }
/* ② 聊天小纸条：2×2 四张入口卡（TA/我的 · 需求/圈子） */
.rel-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.rel-card {
  position: relative; display: flex; flex-direction: column; align-items: flex-start;
  gap: 6px; padding: 12px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--surface);
  cursor: pointer; text-align: left; color: var(--ink);
}
.rel-card:active { background: var(--paper-2, #f3f2ee); }
.rel-card .ic { width: 20px; height: 20px; color: var(--brand); }
.rel-card b { font-size: 13.5px; font-weight: 800; }
.rel-card .rel-n {
  position: absolute; right: 10px; top: 10px;
  font-size: 11px; font-weight: 800; color: var(--brand-deep);
  background: rgba(0, 189, 166, .12); border-radius: var(--r-pill);
  padding: 1px 7px;
}
.rel-back {
  margin-top: 8px; width: 100%; height: 34px;
  border: 0; border-radius: var(--r-pill);
  background: var(--paper-2, #f3f2ee); color: var(--ink-2, #444);
  font-size: 12.5px; font-weight: 700; cursor: pointer;
}
/* ⑦ 收藏/关注按钮统一口径（派总 2026-10-14）：
   去掉圆形背景；未收藏 = 绿线白星 / 未关注 = 绿线白心，带柔和青绿发光；
   已收藏 = 黄色实心星（金光），已关注 = 红色实心心（红光）。
   覆盖面：需求卡 .m-dc-fav（白圆底在此去除）、圈子卡 .pc-fav、
   需求详情 .m-media-fav、帖子底栏 .pcp-fav / .pcp-like。 */
.m-dc-fav,
.pc-fav,
.m-media-fav {
  background: none !important; border: 0 !important; box-shadow: none !important;
}
.m-dc-fav .ic,
.pc-fav .ic,
.m-media-fav .ic,
.pcp-dock-act.pcp-fav .ic,
.pcp-dock-act.pcp-like .ic {
  color: var(--brand); fill: #fff;
  filter: drop-shadow(0 0 5px rgba(0, 189, 166, .45));
}
/* Z6②（派总 2026-10-15）：已收藏不再用金黄 —— 统一红色实心，跟点赞的爱心一个色。 */
.m-dc-fav.on .ic,
.pc-fav.on .ic,
.m-media-fav.on .ic,
.pcp-dock-act.pcp-fav.on .ic {
  color: var(--coral); fill: var(--coral);
  filter: drop-shadow(0 0 6px rgba(255, 106, 69, .5));
}
.pcp-dock-act.pcp-like.on .ic {
  color: var(--coral); fill: var(--coral);
  filter: drop-shadow(0 0 6px rgba(255, 106, 69, .5));
}
/* 关注胶囊（文字钮）：Z6⑫（派总 2026-10-15）关注中的红色描边改回品牌绿 ——
   红色在这儿会被误读成「警告 / 取关」，绿色才是平台的正向色。 */
.pcp-follow.on { color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); }
/* Z8③（派总 2026-10-16）：全站「聊一聊」按钮统一 —— 绿色边框 + 浅绿色填充。
   基准 = .pcp-dock-chat（圈子帖子底栏）的胶囊样式；这里给
   ① 需求详情底栏聊天钮 .m-chat-act（demand.html 四个身份分支）
   ② 订单页需求卡胶囊 .m-chat-pill（_peer.html）
   补齐同一张脸；Web 端 .db-side-chat 的对应规则在 app.css。
   注意：同底栏的「分享」钮不加框 —— 派总只点了聊一聊。 */
.m-actions .m-chat-act,
.m-chat-pill {
  border: 1px solid rgba(0, 189, 166, .45);
  background: rgba(0, 189, 166, .07);
  border-radius: var(--r-pill);
  color: var(--brand-deep);
  padding: 5px 12px;
}
.m-actions .m-chat-act:active,
.m-chat-pill:active { background: rgba(0, 189, 166, .16); }
/* Z7①（派总 2026-10-16）：聊天窗口能放大、放大后缩不回 —— 根因是 iOS 的老毛病：
   聚焦**字号小于 16px** 的输入框时，iOS 会自作主张把页面放大（好让字看得清）；
   而 Z5② 已经禁掉了捏合缩放，结果就是被卡死在放大状态、怎么都缩不回去。
   修法：只在 iOS 上把输入控件提到 16px（这是 iOS 生态的标准代价，微信也这么干）。
   用 @supports(-webkit-touch-callout) 圈定 —— 只有 iOS Safari/WebView 认它，
   Android 和电脑上这段完全不生效，字号视觉一像素都不变。 */
@supports (-webkit-touch-callout: none) {
  .m-chat-input,
  .m-input, .m-textarea, .m-select,
  .pcp-cmt-input,
  .m-searchbar input,
  .mv-search input,          /* T57③ 沉浸页顶部那条搜索框：同一条 iOS 自动放大血案 */
  .pc-search input[type="search"],
  .pub-title-row input, .pub-title-input,
  .pub-shot-fields .m-input,
  .pcn-field input[type="text"], .pcn-field input:not([type]), .pcn-field textarea {
    font-size: 16px !important;   /* 原字号 13~15px，全在 iOS 会触发自动放大的区间 */
  }
}
/* ⑫ 流水账配图：发布页九宫格 + 详情页 3 列裁切铺满 */
.story-thumb {
  position: relative; width: 86px; height: 86px;
  border-radius: 10px; overflow: hidden;
}
.story-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.story-del {
  position: absolute; right: 2px; top: 2px; 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;
}
.cc-own-imgs {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  margin-top: 10px;
}
.cc-own-imgs img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: 10px; display: block; background: var(--surface-2);
}
/* ⑫ 发布页同款「＋添加」格（发流水账配图复用） */
.pub-shot-add {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; width: 86px; height: 86px;
  border: 1.5px dashed rgba(16, 60, 55, .3); border-radius: 10px;
  color: var(--ink-3, #9a9da3); cursor: pointer; background: var(--surface-2, #f3f2ee);
}
.pub-shot-add .ic { width: 20px; height: 20px; }
.pub-shot-add span { font-size: 11px; }
#story-shots { display: flex; flex-wrap: wrap; gap: 8px; }

/* ================= 第十波⑤：聊天（时间归并/撤回/引用/长按/多选） ================= */
.m-msg.is-recalled .m-recalled,
.m-recalled { font-size: 11px; color: var(--ink-3); font-style: italic;
  background: transparent; padding: 2px 4px; }
/* K 波⑮（派总 2026-10-17）：聊天引用改微信风 —— 半透明白底圆角框 + 缩略图；
   昵称一行，引用句对齐在昵称下方（老版「昵称 内容」挤一行 + 深色底整组拆除）。
   白底在对方白气泡和我的绿气泡里都看得见（描边一道，不靠底色硬撑）。 */
.m-quote {
  display: flex; align-items: center; gap: 7px;
  max-width: 100%; margin-bottom: 4px; padding: 5px 9px;
  border-radius: 8px; border: 1px solid rgba(0,0,0,.07);
  background: rgba(255,255,255,.78);
  color: var(--ink); font-size: 12px; line-height: 1.45;
  -webkit-tap-highlight-color: transparent;
}
.m-quote-tx { display: flex; flex-direction: column; min-width: 0; }
.m-quote b { font-weight: 600; color: var(--brand-deep); }
.m-quote-body { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-quote-thumb { width: 36px; height: 36px; border-radius: 6px; object-fit: cover; flex: none; }
.m-chat-img { max-width: min(64vw, 260px); max-height: 300px; border-radius: 14px;
  display: block; object-fit: cover; cursor: zoom-in; }
.m-replybar { display: flex; align-items: center; gap: 8px; padding: 6px 14px 0;
  font-size: 12px; color: var(--ink-2); }
.m-replybar .rb-body { flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
  border-left: 2px solid var(--brand); padding-left: 6px; }
.m-replybar .rb-x { border: 0; background: none; color: var(--ink-3); padding: 2px; }
.mm-item { display: block; width: 100%; border: 0; background: none;
  padding: 13px 18px; font-size: 14.5px; text-align: left; color: var(--ink); }
.mm-item + .mm-item { border-top: 1px solid var(--line, rgba(0,0,0,.06)); }
.mm-item.mm-danger { color: #e5484d; }
.m-msg.msel-target { cursor: pointer; }
.m-bubbles.msel .m-msg { pointer-events: auto; }
.m-msg.picked .who, .m-msg.picked .bubble, .m-msg.picked .m-chat-img {
  outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 14px; }
.m-mselbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; gap: 12px; padding: 12px 16px
  calc(12px + var(--safe-b));
  background: var(--card, #fff); border-top: 1px solid rgba(0,0,0,.08); }
.m-mselbar .ms-n { flex: 1; text-align: center; font-size: 13px; color: var(--ink-2); }
.m-mselbar button { border: 0; border-radius: 999px; padding: 8px 18px;
  font-size: 13.5px; background: var(--brand); color: #fff; }
.m-mselbar button.danger { background: #e5484d; }

/* ================= 第十波⑥：消息列表（管理/左滑） ================= */
.m-mg-btn { border: 0; background: none; color: var(--brand-deep);
  font-size: 13.5px; padding: 4px 6px; }
.mg-check { display: none; flex: 0 0 auto; width: 20px; height: 20px;
  border-radius: 50%; border: 1.6px solid var(--ink-3); margin-top: 2px; }
body.mg-on .mg-check { display: inline-block; }
.m-li.picked .mg-check { background: var(--brand); border-color: var(--brand);
  box-shadow: inset 0 0 0 3px #fff; }
body.mg-on .sw-acts { display: none; }
.pin-flag { display: inline-block; font-style: normal; font-size: 10px;
  color: var(--brand-deep); border: 1px solid var(--brand-deep);
  border-radius: 4px; padding: 0 4px; margin-left: 6px; vertical-align: 1px; }
.sw-wrap { position: relative; }
.sw-acts { position: absolute; top: 0; right: 0; bottom: 0; display: flex; z-index: 0; }
.sw-acts button { width: 64px; border: 0; color: #fff; font-size: 12.5px;
  background: #8aa39b; padding: 0; }
.sw-acts button.danger { background: #e5484d; }
/* 派总 2026-10-14：左滑「标为未读」用浅绿色（同进账绿系，区别于默认灰绿与删除红） */
.sw-acts button.green { background: var(--ok); }
/* X 波①（派总 2026-10-15）：管理模式重排 —— 大类勾选圈 + 右上角操作组。
   原来那条固定底部浮条工具条、分类头「全选本类」小钮，整条拆除（死功能即拆）。 */
.mg-ring { display: none; flex: 0 0 auto; width: 20px; height: 20px;
  border-radius: 50%; border: 1.6px solid var(--ink-3); margin-right: 8px; }
body.mg-on .mg-ring { display: inline-block; }
.mg-ring.on { background: var(--brand); border-color: var(--brand);
  box-shadow: inset 0 0 0 3px #fff; }
.mg-top { display: inline-flex; align-items: center; gap: 4px; }
.mg-top button { border: 0; background: none; color: var(--brand-deep);
  font-size: 12.5px; font-weight: 700; padding: 4px 5px; white-space: nowrap; }
.mg-top button.danger { color: #e5484d; }

/* 派总 2026-10-14 晚第 3 条：长按消息菜单 = 微信式浮动小卡片（不再是底部大面板）。
   出现在长按位置附近，白底圆角+轻投影，无遮罩，点外面/滚动即收。 */
.mm-pop { position: fixed; z-index: var(--z-pop); min-width: 108px; padding: 4px 0;
  background: #fff; border-radius: var(--r-sm); box-shadow: var(--sh-2);
  border: 1px solid var(--line); }
.mm-pop .mm-item { display: block; width: 100%; text-align: left; padding: 10px 18px;
  border: 0; background: none; font-size: 14px; font-weight: 700; color: var(--ink);
  line-height: 1.2; }
.mm-pop .mm-item:active { background: var(--surface-2, #f6f5f2); }
.mm-pop .mm-item.mm-danger { color: var(--danger); }
.sw-wrap .m-li { position: relative; z-index: 1; background: var(--card, #fff);
  transition: transform .18s ease; }
.m-mselbar .ms-cancel { background: var(--ink-3, #98a29d); }
.m-mselbar .ms-del { font-weight: 700; }

/* ===== V 波（派总 2026-10-14 bug 文档 21 条）追加样式 ===== */
/* V 波⑧：列表行整行可点的铺满链接（学需求卡片的 .m-dc-link） */
.m-demand-row.m-has-link { position: relative; }
.m-row-link { position: absolute; inset: 0; z-index: 1; }
/* V 波①⑥：即时校验的错误行 + 输入框红边 */
.m-live-err { color: #d2452c; font-weight: 700; }
.m-input.is-bad { border-color: #d2452c; }
/* V 波⑪：帖子卡上「来自哪个城市」的小字 */
.pc-user-city { font-size: 10.5px; color: var(--ink-3); margin-left: 5px; }

/* ================= W 波（派总 2026-10-14 晚） ================= */
/* W③：撤回提示居中整行（隐藏头像，微信式灰字居中） */
.m-msg.is-recalled { display: block; text-align: center; }
.m-msg.is-recalled .who { display: none; }
.m-msg.is-recalled .m-recalled { display: inline-block; font-style: normal;
  background: rgba(0,0,0,.05); border-radius: 999px; padding: 3px 12px; }
/* 派总 2026-10-15：引用布局重做成微信式 —— 引用块进**气泡内部**顶端（文字消息），
   图片/卡片消息用 .m-qgrp 包一组、引用块贴在内容正上方同侧对齐。
   旧版「引用独占一行 + margin 缩进」整组拆除（头像孤行 + 气泡被顶到下一行，不像微信）。 */
.m-qgrp { display: grid; gap: 5px; min-width: 0; max-width: min(74%, 320px); justify-items: start; }
.m-msg.me .m-qgrp { justify-items: end; }
/* W⑦：标签当场生成的小片 */
.m-tagchips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.m-tagchips:empty { display: none; }
.m-chip { font-size: 11.5px; color: var(--brand-deep);
  background: var(--brand-soft, rgba(0,189,166,.1)); border-radius: 999px;
  padding: 2px 10px; }
.m-chip-more { color: #d2452c; background: rgba(210,69,44,.08); }
/* W⑫：看图灯箱（单击图片全屏看）。T16i-2 收口：灯箱长按也禁系统菜单
   （派总 2026-10-23 口径是「所有」——想存图后续可加站内「保存图片」按钮） */
.m-lightbox { position: fixed; inset: 0; z-index: var(--z-lightbox); background: var(--scrim-media);
  display: flex; flex-direction: column; align-items: center; justify-content: center; }
.m-lightbox img { max-width: 100%; max-height: calc(100% - 60px);
  object-fit: contain; border-radius: 6px; background: #000;
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.m-lightbox-hint { margin-top: 14px; font-size: 12px; color: rgba(255,255,255,.75); }

/* ================= X 波（派总 2026-10-15） ================= */
/* X③：首页「小圈子 ↔ 小青柠」跟手滑动 —— 露在对面的板块预览层。
   左滑时从右侧推进来、右滑时从左侧，跟着手指横移；松手过阈值才真切换。
   T18 优化⑤（派总 2026-10-26「切换白屏 / 闪错误 logo」）三处改动：
   ① z-index 从 40 改成 **-1**：这一层是**对面板块的底**，不是盖在内容上面的卡片。
      原来它压在 .m-main 与顶栏之上，横滑一大片就被它糊住 ⇒ 用户看到「整屏被拖走 +
      一个大 logo」；现在它垫在所有内容底下、页面画布底色之上，只在手指让出来的那条缝里
      露出来。（用 -1 而不是给 .m-pan 建层叠上下文：后者会把 main 里面的灯箱/弹层
      一起封在 z=2 里，反而盖不住底栏 —— 层叠上下文一动，全站浮层层序都要重排。）
   ② top 从 0 改到顶栏下沿：顶栏（一级标签）不许被预览层遮。
   ③ 底色用**目标板块**的纸色（.sk-cir/.sk-qn）而不是通用的 surface-2，
      所以露出来那条缝看着就是「下个板块已经在那儿了」，不是白屏。 */
/* T18 优化⑤（派总 2026-10-26）：垫底预览层。原来 z-index:40 盖在内容与顶栏之上，
   那就是「切板块时糊满屏的白屏 + 一个大 logo」；现在改成**垫在内容底下**（负 z），
   旧页滑出去的 240ms 里露出来的是「对面那块板」：目标板块的纸色 + 同款空位骨架。
   top 从顶栏**下沿**开始（--top-h + --safe-t 再加顶栏那 1px 下边框），不许压住一级标签。
   T20③（派总 2026-10-27 第 3 条）两处收口：
   ① 宽度从 78%/max-340 改成**整屏宽**：原来右边永远留 86px 没被盖住，
      那一条露的是**旧板块**的纸色（小青柠侧 #fbf9f7 近乎纯白）= 「还是会有白色」；
   ② 中间的 logo + 板块名图形删掉（app.js 不再生成 .brand-preview-ic / b）。 */
.brand-preview { position: fixed; top: calc(var(--top-h) + var(--safe-t) + 1px); bottom: 0;
  left: 0; right: 0; width: 100%;
  z-index: -1; display: flex; align-items: center; justify-content: center;
  background: var(--paper); opacity: 0; pointer-events: none;
  transition: transform .18s ease, opacity .18s ease; }
/* 板块纸色：十六进制只在 body 那一份（见上面「双板皮肤」令牌），这里只引用 */
/* T51①：小圈子底色回全站暖白后，sk-cir 预览不再有专属纸色（回落通用 --paper）；
   sk-qn 仍保留（需求池底色没动）。 */
.brand-preview.sk-qn  { --paper: var(--paper-qn);  --paper-2: var(--paper-2-qn); }
.brand-preview.from-left { transform: translateX(-101%); }
.brand-preview.from-right { transform: translateX(101%); }
.brand-preview.is-in.from-left { transform: translateX(0); opacity: 1; }
.brand-preview.is-in.from-right { transform: translateX(0); opacity: 1; }
.brand-preview-in { display: flex; flex-direction: column; align-items: center; gap: 10px;
  width: 100%; padding-top: 26px; }
/* 两板首页都是双列瀑布流：缝里先摆上同款空位，看着就是「那块板已经在那儿」，
   而不是「一块白垫在内容后面」。 */
.brand-preview-sk { display: grid; grid-template-columns: 1fr 1fr; gap: 9px;
  width: 100%; max-width: 300px; margin: 6px 0 0; padding: 0 14px; }
.brand-preview-sk i { border-radius: var(--r-sm, 12px); background: var(--paper-2); }
.brand-preview-sk i:nth-child(odd) { height: 96px; }
.brand-preview-sk i:nth-child(even) { height: 74px; }
/* X③：从缓存秒开后，后台拉到新内容 —— 顶部浮条（点它才真去最新版） */
.brand-fresh { position: fixed; left: 50%; top: calc(64px + var(--safe-t));
  transform: translate(-50%, -8px); z-index: 80;
  border: 0; border-radius: 999px; padding: 7px 16px;
  font-size: 12.5px; font-weight: 800; color: #fff; background: var(--brand);
  box-shadow: 0 6px 18px rgba(0,0,0,.18); opacity: 0;
  transition: opacity .22s ease, transform .22s ease; }
.brand-fresh.is-in { opacity: 1; transform: translate(-50%, 0); }

/* ==================== Z 波② · 统一支付密码弹层 ====================
   参考支付宝/微信支付：底部升起的面板 + 6 个圆点回显 + 自绘数字键盘。
   两端共用 app.js 的 DOM 结构，样式各自一份（m.css / app.css）。 */
.pay-sheet { position: fixed; inset: 0; z-index: var(--z-pop); }
.pay-sheet .pay-mask {
  position: absolute; inset: 0; background: var(--scrim);
}
.pay-sheet .pay-panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--surface); border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  padding: var(--sp-xl) var(--sp-xl) calc(var(--sp-lg) + var(--safe-b));
  text-align: center;
  animation: payUp var(--dur-3) var(--ease-out); box-shadow: var(--sh-sheet);
}
@keyframes payUp { from { transform: translateY(40%); opacity: .5; } to { transform: none; opacity: 1; } }
.pay-sheet .pay-x {
  position: absolute; top: 10px; right: 12px; width: 30px; height: 30px;
  border: 0; background: none; color: var(--ink-3); font-size: 20px; line-height: 1;
}
.pay-sheet .pay-title { font-size: 16px; font-weight: 900; color: var(--jade, #103c37); }
.pay-sheet .pay-sub { margin-top: 4px; font-size: 12px; color: var(--ink-3); }
.pay-sheet .pay-dots {
  display: flex; justify-content: center; gap: 12px; margin: 16px 0 6px;
}
.pay-sheet .pay-dots i {
  width: 12px; height: 12px; border-radius: 50%;
  border: 1.5px solid var(--line, #cfd8d6); background: transparent;
  transition: background .12s, border-color .12s;
}
.pay-sheet .pay-dots i.on { background: var(--jade, #103c37); border-color: var(--jade, #103c37); }
.pay-sheet .pay-msg { min-height: 18px; margin: 2px 0 0; font-size: 12.5px; font-weight: 800; color: #1f8f5f; }
.pay-sheet .pay-msg.is-bad { color: #d2452c; }
.pay-sheet .pay-forgot { display: inline-block; margin-top: 2px; font-size: 12px; color: var(--ink-3); }
.pay-sheet .pay-keys {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 12px;
}
.pay-sheet .pay-keys button {
  height: 46px; border: 0; border-radius: var(--r-sm); background: var(--surface-2, #f2f6f5);
  font-size: 20px; font-weight: 800; color: var(--ink, #12332e);
}
.pay-sheet .pay-keys button:active { background: var(--brand-soft, #e2f5f1); }
.pay-sheet .pay-keys .pay-k-ghost { font-size: 15px; color: var(--ink-3); }

/* ---- Z3②（派总 2026-10-15 拍板）：AI 按品类估价的一行参考价 ----
   只是参考不是闸门：拿不到（没配 AI / 网络差）整行不出现。 */
.pub-ai-hint {
  margin: 6px 0 0;
  color: var(--brand-deep, #0b5a54);
  cursor: pointer;
}
.pub-ai-hint:active { opacity: .7; }

/* ================= P 波（派总 2026-10-19 截图 11 张） ================= */
/* ⑧ 定位：详情页正文下方灰字那行 pcp-loc（小红书式）一直在 —— 老地名要显示。
   T29①（派总 2026-10-28「全站的定位功能全部下架」）把发布页那一路的样式
   （pcn-loc 输入行 / pcn-loc-btn 定位按钮 / pcn-pois 与 pcn-poi 地点候选）
   和评论框的地点行整组撤下。
   T29②（派总 2026-10-29 重新上线）**没有把它们搬回来**：那一行现在是两端共用的
   partials/_loc_field.html + static/css/loc.css 的 .lc-field*（网页版发动态、
   发需求、资料页「在哪儿」也吃同一份）。本文件里不再留发布页的定位样式 ——
   留一份就是两端各写一遍，那正是「三个入口一起失效却没人说得清为什么」的起点。 */

/* ================= Q3 波⑥（派总 2026-10-20 截图⑤） ================= */
/* 动态设置：详情底部条输入框左侧的齿轮钮 + 两层底部弹层（设置菜单 / 谁可以看） */
.pcp-setbtn { color: var(--ink-2); }
.pcp-set {
  position: fixed; inset: 0; z-index: var(--z-pop);
  display: flex; align-items: flex-end; justify-content: center;
}
.pcp-set-mask { position: absolute; inset: 0; background: var(--scrim); }
.pcp-set-panel {
  position: relative; z-index: 1; width: 100%; max-width: 720px;
  background: var(--surface); border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  padding: var(--sp-xl) var(--sp-xl) calc(var(--sp-lg) + var(--safe-b));
  display: flex; flex-direction: column; gap: 2px;
  max-height: 78vh; overflow-y: auto; box-shadow: var(--sh-sheet);
}
.pcp-set-t { margin: 0 0 6px; font-size: 14px; font-weight: 800; color: var(--ink); }
.pcp-set-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 4px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 14.5px; font-weight: 700; color: var(--ink);
  text-decoration: none; border-bottom: 1px solid var(--line);
  text-align: left;
}
.pcp-set-item .ic-sm { color: var(--ink-2); }
.pcp-set-item.is-dim { color: var(--ink-3); }
.pcp-set-item.is-danger { color: var(--coral); }
.pcp-set-item.is-danger .ic-sm { color: var(--coral); }
.pcp-set-soon {
  margin-left: auto; font-size: 10.5px; font-weight: 800;
  color: var(--ink-3); background: var(--paper-2);
  border-radius: var(--r-pill); padding: 2px 8px;
}
.pcp-set-cancel {
  margin-top: 10px; height: 42px; border: 0; border-radius: var(--r-pill);
  background: var(--paper-2); color: var(--ink-2);
  font: inherit; font-size: 14px; font-weight: 800; cursor: pointer;
}
.pcp-vis {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 4px; border-bottom: 1px solid var(--line); cursor: pointer;
}
.pcp-vis input { accent-color: var(--brand); width: 18px; height: 18px; flex: none; }
.pcp-vis span { font-size: 14px; font-weight: 700; color: var(--ink); display: flex; flex-direction: column; gap: 1px; }
.pcp-vis span i { font-style: normal; font-size: 11px; font-weight: 500; color: var(--ink-3); }
.pcp-viewers {
  margin-top: 8px; padding: 6px 2px;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.pcp-vuser {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 10px; border: 1px solid var(--line-2); border-radius: var(--r-pill);
  font-size: 12.5px; font-weight: 700; color: var(--ink-2); cursor: pointer;
}
.pcp-vuser input { accent-color: var(--brand); width: 15px; height: 15px; }
.pcp-vuser:has(input:checked) { border-color: var(--brand); color: var(--brand-deep); background: rgba(0, 189, 166, .07); }
.pcp-vempty { width: 100%; margin: 4px 0; font-size: 12px; color: var(--ink-3); }
.pcp-vis-save {
  margin-top: 12px; height: 44px; border: 0; border-radius: var(--r-pill);
  background: var(--brand); color: #fff;
  font: inherit; font-size: 15px; font-weight: 800; cursor: pointer;
}
.pcp-vis-save:active { opacity: .85; }
.pcp-loc {
  display: flex; align-items: center; gap: 5px;
  margin: 10px 2px 0; font-size: 13px; font-weight: 700; color: var(--brand-deep);
}
.pcp-loc .ic-sm { color: var(--brand-deep); flex: none; width: 15px; height: 15px; }

/* ⑨ 发文字（写想法）编辑页小红书式 —— T16f-1（派总 2026-10-22）升级卡片画布：
   标题位/正文位直接摆在最终卡片的对应位置上，输入过程即所见排版。
   T16j（派总 2026-10-24）：标题+正文作为一组**上下居中**（不再标题贴顶），
   正文框高度跟随内容自动生长（JS growXsBody），标题/正文各加大 2 个字号。 */
.pcn.xs-step1 .xs-s1 .pcn-xs-wrap {
  min-height: 48vh; border: 1.5px solid var(--line-2); border-radius: 14px;
  background: #fff; display: flex; flex-direction: column; justify-content: center;
  gap: 8px; padding: 16px 14px 12px; overflow: hidden;
}
.pcn-xs-title {
  display: block; width: 100%; border: 0; background: none;
  font: inherit; font-size: 23px; font-weight: 800; color: var(--ink);
  padding: 2px 2px 8px; outline: none; text-align: center;
}
.pcn-xs-title::placeholder { color: var(--ink-4, #b7bab4); font-weight: 700; }
.pcn-xs-body {
  display: block; width: 100%; border: 0; background: none;
  font: inherit; font-size: 22px; font-weight: 600; line-height: 1.75; color: var(--ink);
  padding: 4px 2px 10px; outline: none; resize: none; text-align: center;
  overflow-y: auto;
}
.pcn-xs-body::placeholder { color: var(--ink-4, #b7bab4); }

/* Q 波⑥（派总 2026-10-20，照小红书视频）+ 三步化（派总 2026-10-25）：「发文字」拆三步 ——
   ① 写想法 ② 选卡片（颜色/字体/横竖版）③ 补图发布（同发图文界面：
   卡片=封面第一格、「+」续加、定位/圈子/发布都在这页）。
   无 JS 时不会切这些类，三步都在同一个表单里，照样能填能发。 */
.pcn.xs-step1 .xs-s2, .pcn.xs-step1 .xs-s3 { display: none; }
.pcn.xs-step2 .xs-s1, .pcn.xs-step2 .xs-s3 { display: none; }
.pcn.xs-step3 .xs-s1, .pcn.xs-step3 .xs-s2 { display: none; }
/* 步间回退小按钮：第②步「‹ 上一步」/ 第③步「‹ 重选卡片」（独占一行，别和标签挤在一起） */
.pcn-step-back {
  display: block; border: 0; background: none; color: var(--ink-2);
  font-size: 13px; font-weight: 700; padding: 2px 0 10px; cursor: pointer;
}
/* 第③步九宫格首格 = 文字卡片封面：3:4 的卡整体放进 1:1 格（contain + 白底垫边），不带 × */
.pcn-prev.is-card img { object-fit: contain; background: #fff; }
.pcn-prev-wait {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--ink-4, #9aa0a6); font-size: 12px; font-weight: 700;
}
/* T16j：正文框高度由 JS growXsBody 跟随内容生长（居中组布局），不再 flex:1 吃满画布 */
/* T16f-1：仅标题 = 正文区藏掉，标题输入框吃满画布（centerXs 算 padding 居中） */
.pcn.lo-title .pcn-xs-body { display: none; }
/* 顶栏「下一步」：品牌色胶囊，跟右上的 × 挤在一起时保持间距 */
.pcn-next {
  border: 0; background: var(--brand); color: #fff; font-weight: 800; font-size: 13px;
  padding: 6px 14px; border-radius: 999px; cursor: pointer; white-space: nowrap;
}
.pcn-next:active { opacity: .8; }
/* 第 ② 步的正文卡片预览：复用海报卡骨架（`pc-poster`），只是内容换成纯文本 */
.pcn-xs-card { margin-top: 4px; }
.pcn-xs-card .pcn-live-body {
  white-space: pre-wrap; word-break: break-word; text-align: left;
  margin: 6px 0 0; border: 0; background: none; padding: 0;
}
.pcn-xs-card .pcn-live-title { display: block; }

/* ==============================================================
   T16c（派总 2026-10-21 五条改版）：发文字布局二选一 + 预览改版
   ============================================================== */
/* ① 布局二选一选项卡（T16d 缩小：不做大卡片，紧凑一行示意即可） */
.pcn-lopts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px;
}
.pcn-lopt { display: grid; gap: 3px; cursor: pointer; position: relative; }
.pcn-lopt input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-lopt-card {
  background: var(--surface); border: 1.5px solid var(--line-2); border-radius: var(--r-xs);
  min-height: 52px; padding: var(--sp-sm) var(--sp-md);
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  overflow: hidden; transition: border-color .15s;
}
.pcn-lopt.on .pcn-lopt-card {
  border-color: var(--brand);
  outline: 2px solid var(--brand); outline-offset: 1.5px;
}
/* T16j：按钮文字直接是「单文字 / 标题+内容」，底部小字注脚已删（连同 <i>/span 规则） */
.pcn-lopt-card b { font-size: 12.5px; font-weight: 800; color: var(--ink); line-height: 1.4; }
.pcn-lopt-card--title { align-items: center; text-align: center; }

/* T16j（派总 2026-10-24）：T16d 预设提示词示意层整个退役 —— 示意文字改写在
   真输入框的 placeholder 上（切布局时 JS 换文案），不再有绝对定位叠字问题，
   T16g-2/3 的 .ht 隐藏补丁随之删除。 */

/* ② 预览卡：正楷观感（手机有楷体就用楷体，最终成图服务端一定是正楷） */
.pcn-xs-card {
  font-family: "LXGW WenKai", "Kaiti SC", STKaiti, KaiTi, "KaiTi_GB2312", serif;
}
/* 预览卡铺真实底图：压一层可读性纱（浅款白纱 / 深款墨纱），质感在卡外全露 */
.pcn-xs-card[style*="background-image"] {
  background-size: cover; background-position: center;
  position: relative; overflow: hidden;
}
.pcn-xs-card[style*="background-image"]::before {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0;
  background: rgba(255, 255, 255, .78);
}
.pcn-xs-card.tone-dark[style*="background-image"]::before {
  background: rgba(12, 34, 30, .70);
}
.pcn-xs-card.tone-dark[style*="background-image"] { color: #f2f7f5; }
.pcn-xs-card[style*="background-image"] > * { position: relative; z-index: 1; }
/* 仅标题：预览卡只显示居中大标题 */
.pcn.lo-title .pcn-xs-card .pcn-live-body { display: none; }
.pcn.lo-title .pcn-xs-card .pcn-live-title {
  text-align: center; font-size: 22px; font-weight: 800; line-height: 1.5;
}

/* ==============================================================
   T16f-2/3（派总 2026-10-22）：第②步即见即所得 + 颜色/字号/字体
   ============================================================== */
/* 即见即所得：真图绝对定位盖住 CSS 兜底卡；is-loading 时兜底卡半透明 */
.pcn-xs-prev { position: relative; }
.pcn-xs-prev-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit; z-index: 2; display: block;
}
.pcn-xs-prev.is-loading .pcn-xs-card { opacity: .55; }
.pcn-xs-prev.is-loading::after {
  content: ""; position: absolute; top: 12px; right: 12px; z-index: 3;
  width: 18px; height: 18px; border-radius: 50%;
  border: 2.5px solid rgba(0, 189, 166, .35); border-top-color: var(--brand);
  animation: pcnSpin .8s linear infinite;
}
@keyframes pcnSpin { to { transform: rotate(360deg); } }
/* 模板缩略图换成真实成图小样（同一条渲染管线出的图） */
.pc-poster.pc-poster-mini.pc-tpl-real { display: block; overflow: hidden; }
.pc-poster.pc-poster-mini.pc-tpl-real img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* 文字颜色色板 —— T58⑤（派总 2026-11-04 第 5 条）自选颜色撤掉，颜色跟模板走；
   .pcn-cpick / .pcn-cswatch 的样式随之删除（模板里已无这两个类名）。 */
/* 字号± 与 字体选择行 */
.pcn-frow { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
.pcn-fsz { display: inline-flex; align-items: center; gap: 0;
  border: 1.5px solid var(--line-2); border-radius: 999px; overflow: hidden; }
.pcn-fsz-btn {
  border: 0; background: none; width: 34px; height: 30px;
  font-size: 16px; font-weight: 800; color: var(--ink); cursor: pointer;
}
.pcn-fsz-btn:disabled { color: var(--ink-4, #b7bab4); cursor: default; }
.pcn-fsz-btn:not(:disabled):active { background: var(--surface-2); }
.pcn-fsz-val { min-width: 44px; text-align: center; font-size: 12.5px; font-weight: 800; color: var(--ink); }
.pcn-fsel { display: flex; flex-wrap: nowrap; gap: 7px; overflow-x: auto;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: 2px 2px 6px; margin: 0 -2px; }
.pcn-fsel::-webkit-scrollbar { display: none; }
.pcn-fopt { position: relative; cursor: pointer; flex-shrink: 0; }
.pcn-fopt input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.pcn-fopt span {
  display: inline-block; padding: 5px 12px; border-radius: 999px;
  border: 1.5px solid var(--line-2); background: #fff;
  font-size: 12.5px; font-weight: 700; color: var(--ink-2); white-space: nowrap;
}
/* ③（派总 2026-10-25）：选择器标签用 @font-face 直接以该字体本身预览。
   2026-11-05 换成 static/fonts/subset/*.woff2（scripts/build_font_subsets.py 按标签文字切）：
   全量 TTF 在这一屏要下 59,513KB（真浏览器实测 8 款，最大单款 24MB），把同屏那条
   card-preview 挤到超时；而标签只画「正楷 / 毛笔」这几个字 ⇒ 九款合计 28.6KB。
   改了 settings.CARD_FONTS 里的标签名要重跑那个脚本。全量 TTF 原样留着给服务端 PIL 渲卡片。 */
@font-face { font-family: "XqnKai"; src: url("../fonts/subset/kai.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnCute"; src: url("../fonts/subset/cute.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnHei"; src: url("../fonts/subset/hei.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnBrush"; src: url("../fonts/subset/brush.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnXiao"; src: url("../fonts/subset/xiao.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnLong"; src: url("../fonts/subset/long.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnZhi"; src: url("../fonts/subset/zhi.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnMaoCao"; src: url("../fonts/subset/maocao.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "XqnHuang"; src: url("../fonts/subset/huang.woff2") format("woff2"); font-display: swap; }
.pcn-fopt span.f-kai { font-family: "XqnKai", "LXGW WenKai", "Kaiti SC", STKaiti, KaiTi, serif; }
.pcn-fopt span.f-cute { font-family: "XqnCute", "ZCOOL KuaiLe", "Yuanti SC", "YouYuan", sans-serif; }
.pcn-fopt span.f-hei { font-family: "XqnHei", "PingFang SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; }
.pcn-fopt span.f-brush { font-family: "XqnBrush", "Ma Shan Zheng", "Kaiti SC", serif; }
.pcn-fopt span.f-xiao { font-family: "XqnXiao", "ZCOOL XiaoWei", "Songti SC", serif; }
.pcn-fopt span.f-long { font-family: "XqnLong", "Long Cang", "Kaiti SC", cursive; }
.pcn-fopt span.f-zhi { font-family: "XqnZhi", "Zhi Mang Xing", "Kaiti SC", cursive; }
.pcn-fopt span.f-maocao { font-family: "XqnMaoCao", "Liu Jian Mao Cao", "Kaiti SC", cursive; }
.pcn-fopt span.f-huang { font-family: "XqnHuang", "ZCOOL QingKe HuangYou", "PingFang SC", sans-serif; }
.pcn-fopt.on span { border-color: var(--brand); color: var(--brand-deep);
  outline: 2px solid var(--brand); outline-offset: 1.5px; font-weight: 800; }
/* 推荐字体：右上角「荐」角标 + 淡青描边，选模板后由 JS 标出 */
.pcn-fopt.is-rec span::after { content: "荐"; position: absolute; top: -6px; right: -4px;
  font-size: 10px; line-height: 1; font-weight: 800; color: #fff; background: var(--brand);
  border-radius: 999px; padding: 2px 4px; font-family: var(--f-sans); }
.pcn-fopt.is-rec:not(.on) span { border-color: var(--brand-soft); }

/* ② 模板缩成一行横滑（距离不够左右滑着选） */
.pcn-tpls--row {
  display: flex; gap: 8px; overflow-x: auto;
  padding: 2px 2px 8px; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.pcn-tpls--row .pcn-tpl { flex: 0 0 auto; width: 88px; scroll-snap-align: start; }
.pcn-tpls--row .pc-poster.pc-poster-mini { aspect-ratio: 3 / 4 !important; padding: 8px; }
.pcn-tpls--row .pc-poster-mini b { font-size: 11px; }
.pcn-tpls--row .pc-poster-mini span { display: none; }
.pcn-tpls--row .pcn-tpl > i { font-size: 10.5px; }

/* ==================== T18③④（派总 2026-10-25）输入框工具条 + 评论附加项 ==================== */
/* 工具条：表情 / @用户 / #话题（Lucide 图标，不再是 emoji 字符） */
/* ⚠️ flex-wrap 必须有：抽屉是 `.ymw-toolpanel { flex: 1 0 100%; order: -1 }`，
   不换行时它挤不进第二行，反而把三颗按钮压成一小条（派总①e「emoji 选择界面显示不对」
   的真形状：面板只有 294px、图标缩到 24px）。 */
.ymw-tools { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 6px; }
.ymw-tool { display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; color: var(--ink-2, #4a4f57);
  padding: 6px; border-radius: 8px; cursor: pointer; }
.ymw-tool:active { background: var(--paper-2, #f3f2ee); }
.ymw-tool.is-on { background: var(--brand-soft, #e6f7f4); color: var(--brand-deep, #007d6d); }
/* T18 优化①e（派总 2026-10-26「emoji 选择界面显示不对！」）：
   三个面板不再是「一个 272px 小浮层压在输入框上 + 一个挂在工具条下面」，
   改成**同一个抽屉**：贴在工具条上方、整行宽、随内容展开、超长自己滚。
   实现：工具条本身是 flex 行，面板 `order:-1` + `flex-basis:100%` 就成第一行的整块。 */
.ymw-toolpanel { position: static; order: -1; flex: 1 0 100%; width: auto; display: block;
  box-sizing: border-box; margin: 0 0 6px; padding: var(--sp-sm);
  max-height: 216px; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); box-shadow: var(--sh-2); }
.ymw-egroup { margin-bottom: 8px; }
.ymw-egroup:last-child { margin-bottom: 0; }
.ymw-egroup-label { margin: 0 0 4px; font-size: 11px; font-weight: 700; color: var(--ink-3, #8a9099); }
.ymw-egroup-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.ymw-topic-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ymw-topic { display: inline-flex; align-items: center; gap: 4px;
  border: 1px solid var(--line, #d8dade); border-radius: var(--r-pill);
  background: var(--paper-2, #f3f2ee); color: var(--ink);
  font: inherit; font-size: 12.5px; font-weight: 700; padding: 5px 10px; cursor: pointer; }
.ymw-topic i { font-style: normal; font-size: 11px; font-weight: 500; color: var(--ink-3, #8a9099); }
.ymw-toolhint { margin: 2px 0 0; font-size: 11.5px; color: var(--ink-3, #8a9099); }
/* @ 候选行：头像 + 昵称（+用户名）+ 好友标记 —— 派总①a「@ 的用户显示用户昵称」 */
.ymw-mention { display: flex; align-items: center; gap: 8px; width: 100%;
  border: 0; background: none; text-align: left; padding: 6px 4px;
  border-radius: 8px; cursor: pointer; font: inherit; color: var(--ink); }
.ymw-mention:active { background: var(--paper-2, #f3f2ee); }
.ymw-mention-av { flex: none; width: 28px; height: 28px; border-radius: 50%;
  overflow: hidden; background: var(--brand-soft, #e6f7f4); color: var(--brand-deep, #007d6d);
  display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 800; }
.ymw-mention-av img { width: 100%; height: 100%; object-fit: cover; }
.ymw-mention-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.ymw-mention-main b { font-size: 13px; font-weight: 700; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis; }
.ymw-mention-main i { font-style: normal; font-size: 11px; color: var(--ink-3, #8a9099); }
.ymw-mention-friend { flex: none; font-style: normal; font-size: 10.5px; font-weight: 700;
  color: var(--brand-deep, #007d6d); background: var(--brand-soft, #e6f7f4);
  padding: 2px 6px; border-radius: var(--r-pill); }

/* 评论：分享面板 / 分享小卡
   （T29② 派总 2026-10-29 定位重新上线：评论地点的**行**没有回来 —— 那颗图钉直接开
     全站共用的选点面板 static/js/loc.js，选完只在下面挂一条 chip。所以这里不再需要
     「地点输入行 + GPS 按钮 + 附近候选」那一组样式，chip 也直接沿用 .pcp-cmt-sharechip。） */
.pcp-cmt-sharepanel { margin-top: 8px; border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: var(--sp-sm); background: var(--surface); }
.pcp-cmt-sharetabs { display: flex; gap: 6px; margin-bottom: 6px; }
.pcp-cmt-sharetag { border: 0; background: var(--paper-2, #f3f2ee); color: var(--ink-2, #4a4f57);
  font-size: 12.5px; padding: 4px 12px; border-radius: var(--r-pill); cursor: pointer; }
.pcp-cmt-sharetag.on { background: var(--brand-soft, #e6f7f4); color: var(--brand-deep); font-weight: 700; }
.pcp-cmt-sharelist { display: grid; gap: 2px; max-height: 216px; overflow-y: auto;
  -webkit-overflow-scrolling: touch; }
/* T18 优化①d（派总 2026-10-26）：面板列表 = 缩略封面 + 标题 + 发布者（两行） */
.pcp-cmt-shareitem { display: grid; grid-template-columns: 34px 1fr auto;
  grid-template-rows: auto auto; align-items: center; column-gap: 8px;
  text-align: left; border: 0; background: none; padding: 6px 4px;
  border-radius: 8px; cursor: pointer; font-size: 13px; }
.pcp-cmt-shareitem:active { background: var(--paper-2, #f3f2ee); }
.pcp-cmt-shareitem .pcp-si-cover { grid-row: 1 / 3; grid-column: 1;
  width: 34px; height: 34px; border-radius: 7px; object-fit: cover; background: var(--paper-2); }
.pcp-cmt-shareitem span.pcp-si-cover { display: flex; align-items: center;
  justify-content: center; color: var(--ink-3); }
.pcp-cmt-shareitem b { grid-row: 1; grid-column: 2; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcp-cmt-shareitem span { grid-row: 2; grid-column: 2; color: var(--ink-3);
  font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcp-cmt-shareitem i { grid-row: 1 / 3; grid-column: 3; font-style: normal; font-size: 11px;
  color: var(--brand-deep); background: var(--brand-soft, #e6f7f4);
  border-radius: 6px; padding: 1px 5px; flex: 0 0 auto; }
.pcp-cmt-shareempty { margin: 6px 2px; color: var(--ink-3); font-size: 12.5px; }
/* 分享名单拉失败时的「点这里重试」（与「还没有发布过动态」是两种状态，见 app.js loadShare） */
.pcp-cmt-shareretry { border: 0; background: none; padding: 0; cursor: pointer;
  color: var(--brand-deep); font-size: 12.5px; text-decoration: underline; }
.pcp-cmt-sharechip { display: flex; align-items: center; gap: 6px; margin-top: 8px;
  padding: 6px 10px; border-radius: 10px; background: var(--brand-soft, #e6f7f4); color: var(--brand-deep);
  font-size: 13px; }
.pcp-cmt-sharechip b { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.pcp-cmt-sharex { border: 0; background: none; color: inherit; font-size: 16px; line-height: 1; cursor: pointer; }
.pcp-cmt-loc, .pcp-cmt-share { display: inline-flex; align-items: center; gap: 4px;
  margin-top: 6px; margin-right: 8px; color: var(--ink-3); font-size: 12px; text-decoration: none; }
.pcp-cmt-loc { color: var(--ink-3); }
/* T18 优化①d：评论里的分享卡改成「左缩略图 + 右两行（标题 / 发布者 · 类型）」的小卡片。
   ⚠️ 它是 <a>，只能 block 级铺开，不能和 `.pcp-cmt-loc` 挤在同一行 inline-flex 里。 */
.pcp-cmt-share { display: flex; align-items: center; gap: 8px; width: 100%;
  box-sizing: border-box; margin-top: 8px; padding: 8px;
  border: 1px solid var(--line, #d8dade); border-radius: 10px;
  background: var(--surface, #fff); color: var(--ink); }
.pcp-cmt-share-cover { flex: none; width: 40px; height: 40px; border-radius: 8px;
  object-fit: cover; background: var(--paper-2, #f3f2ee); }
.pcp-cmt-share-noimg { display: flex; align-items: center; justify-content: center;
  color: var(--ink-3); }
.pcp-cmt-share-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pcp-cmt-share-main b { font-weight: 700; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcp-cmt-share-main span { color: var(--ink-3); font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcp-cmt-loc .ic, .pcp-cmt-share .ic { color: var(--ink-3); }
/* T18③（派总 2026-10-25）：正文 / 评论里的 @用户名 链接 */
.pc-mentioned { color: var(--brand-deep, #009c8a); font-weight: 600; text-decoration: none; }

/* 宫格拖拽态：.pcn-prev（发图文）与 .ed-tile（编辑需求）早有自己的 is-drag/is-over；
   这里补上另外两处（发需求 .pub-prev、评论配图 .pcp-cmt-imgcell），四处手感必须一样。 */
.pub-prev.is-drag, .pcp-cmt-imgcell.is-drag { transform: scale(1.06); z-index: 5;
  box-shadow: 0 8px 18px rgba(16, 60, 55, .28); }
.pub-prev.is-over, .pcp-cmt-imgcell.is-over { outline: 2px solid var(--brand); outline-offset: 1px; }

/* ----------------------------------------------------------------------
   帮助中心 + AI 搜索（2026-10-26，底栏「问一问」入口）
   沿用既有积木（m-card / m-chips / m-input / m-btn / m-field），下面
   只补本页专用件：搜索联想、分类网格、AI 回答卡、文章卡、正文排版。
   ---------------------------------------------------------------------- */
.help-search {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 10px 12px;
}
.help-search .ic { width: 18px; height: 18px; color: var(--ink-3); flex: none; }
.help-search input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: 14.5px; color: var(--ink);
}
.help-search input::placeholder { color: var(--ink-3); }
/* 搜索联想下拉（输入时实时出，跟在搜索框下面） */
.help-sug {
  margin-top: 6px; background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); overflow: hidden;
}
.help-sug[hidden] { display: none; }
.help-sug-item {
  display: block; padding: 10px 12px; text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.help-sug-item:last-child { border-bottom: 0; }
.help-sug-item:active { background: var(--brand-tint); }
.help-sug-item b { display: block; font-size: 13.5px; color: var(--ink); }
.help-sug-item span { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 1px; }
/* 热门问题胶囊条（复用 m-chips，这里只管标签语义） */
/* 分类网格：2 列卡片 */
.help-cats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.help-cat {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 12px; text-decoration: none;
}
.help-cat .ic { width: 20px; height: 20px; color: var(--brand); flex: none; }
.help-cat b { font-size: 13.5px; color: var(--ink); }
.help-cat span { display: block; font-size: 11px; color: var(--ink-3); font-weight: 400; }
/* 用户提问气泡 + AI 回答卡 */
.help-q {
  display: inline-block; align-self: flex-end;
  background: var(--brand); color: #fff; border-radius: var(--r-pill);
  padding: 7px 14px; font-size: 13.5px; font-weight: 700;
}
.help-ai {
  background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 14px; margin-top: 8px;
}
.help-ai-hd {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 800; color: var(--brand-deep); margin-bottom: 8px;
}
.help-ai-hd .ic { width: 15px; height: 15px; }
.help-ai-bd { font-size: 14px; line-height: 1.7; color: var(--ink); white-space: pre-wrap; word-break: break-word; }
.help-ai-foot { font-size: 11px; color: var(--ink-3); margin-top: 10px; }
/* 相关文章卡流（搜索结果 / AI 回答 / 分类页共用） */
.help-arts { display: flex; flex-direction: column; gap: 8px; }
.help-art {
  display: block; background: var(--surface); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 12px 14px; text-decoration: none;
}
.help-art:active { background: var(--brand-tint); }
.help-art b { display: block; font-size: 14px; color: var(--ink); }
.help-art span { display: block; font-size: 12px; color: var(--ink-3); margin-top: 3px; line-height: 1.5; }
.help-art .m-tag { margin-top: 6px; display: inline-block; font-size: 10.5px; }
/* 「没找到」兜底态 */
.help-empty { text-align: center; padding: 20px 0 4px; color: var(--ink-2); font-size: 13.5px; }
/* 追问输入行 */
.help-askrow { display: flex; gap: 8px; margin-top: 10px; }
.help-askrow input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: var(--surface-2);
  border-radius: var(--r-pill); padding: 9px 14px;
  font: inherit; font-size: 13.5px; color: var(--ink);
}
.help-askrow button {
  flex: none; border: 0; border-radius: var(--r-pill); padding: 0 16px;
  background: var(--brand); color: #fff; font: inherit; font-size: 13.5px; font-weight: 800;
}
/* 文章详情页正文排版（body 是 staff 可信任 HTML） */
.help-meta { font-size: 11.5px; color: var(--ink-3); }
.help-body { font-size: 14.5px; line-height: 1.8; color: var(--ink); }
.help-body p { margin: 0 0 10px; }
.help-body ul, .help-body ol { margin: 0 0 10px; padding-left: 20px; }
.help-body li { margin-bottom: 4px; }
.help-body b, .help-body strong { color: var(--ink); }
.help-body table { width: 100%; border-collapse: collapse; font-size: 13px; }
.help-body td { padding: 6px 0; border-bottom: 1px solid var(--line); }

/* ======================================================================
   AI 管家柠柠 · T25（派总 2026-10-27 十条能力）
   图文卡片 / 合规出处 / 正式表格 / 待发附件条 / 选择条扩充 / 设置抽屉
   --------------------------------------------------------------------
   一处口径：卡片与出排在「服务端渲染的历史」和「JS 新加的消息」两条路上长得
   一样，类名两边共用（改结构要同时改 templates/m/_ning_msg_body.html）。
   ====================================================================== */

/* 引用条（第 5 条）：挂在气泡上方，淡淡的一条，不抢正文 */
.m-ning-quote {
  display: flex; align-items: center; gap: 5px;
  max-width: 74%; padding: 5px 9px; border-radius: var(--r-sm);
  background: var(--surface-2); border-left: 3px solid var(--brand-soft);
  font-size: 12px; color: var(--ink-2); line-height: 1.45;
}
.m-ning-quote .ic { width: 13px; height: 13px; color: var(--brand-deep); flex: none; }
.m-ning-quote span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 图文卡片（第 3 条：图 + 三行字 + 可点进页面） */
.m-ning-cards {
  display: flex; flex-direction: column; gap: 8px;
  width: min(340px, 100%); margin-top: 2px;
}
.m-ning-card {
  display: flex; align-items: stretch; gap: 10px;
  padding: var(--sp-md); border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--sh-1); text-decoration: none; color: inherit;
  -webkit-tap-highlight-color: transparent; cursor: pointer;
}
.m-ning-card:active { background: var(--brand-tint); border-color: var(--brand); }
.m-ning-card-static { cursor: default; }
.m-ning-card-cover {
  flex: 0 0 52px; width: 52px; height: 52px; border-radius: var(--r-sm);
  background: var(--brand-soft); color: var(--brand-deep);
  display: grid; place-items: center; overflow: hidden;
}
.m-ning-card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.m-ning-card-cover .ic { width: 22px; height: 22px; }
.m-ning-card-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.m-ning-card-title {
  font-size: 14px; font-weight: 800; color: var(--ink); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.m-ning-card-sub {
  font-size: 11.5px; color: var(--ink-2); line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-ning-card-row {
  display: flex; gap: 5px; font-size: 11px; color: var(--ink-3); line-height: 1.4;
  min-width: 0;
}
.m-ning-card-row b {
  flex: none; font-weight: 700; color: var(--brand-deep);
  background: var(--brand-tint); border-radius: 6px; padding: 0 5px;
}
.m-ning-card-row i { font-style: normal; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-ning-card-tag {
  flex: none; align-self: flex-start; margin-top: 1px;
  font-size: 10px; font-weight: 800; color: var(--brand-deep);
  background: var(--brand-soft); border-radius: var(--r-pill); padding: 2px 7px;
}

/* 合规出处（第 2 条：标明出处，摘录是真原文） */
.m-ning-cites {
  display: flex; flex-direction: column; gap: 6px;
  width: min(340px, 100%); margin-top: 2px;
  padding: 9px 10px; border-radius: var(--r);
  background: var(--surface-2); border: 1px dashed var(--line-2);
}
.m-ning-cites-hd { margin: 0; font-size: 11px; font-weight: 800; color: var(--ink-3); letter-spacing: .02em; }
.m-ning-cite {
  display: flex; flex-direction: column; gap: 1px;
  text-decoration: none; color: inherit; padding: 6px 0;
  border-top: 1px solid var(--line);
}
.m-ning-cite:first-of-type { border-top: 0; padding-top: 2px; }
.m-ning-cite-src { font-size: 10.5px; color: var(--brand-deep); font-weight: 700; }
.m-ning-cite-title { font-size: 13px; font-weight: 800; color: var(--ink); line-height: 1.4; }
.m-ning-cite-quote {
  font-size: 11.5px; color: var(--ink-2); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.m-ning-cite:active .m-ning-cite-title { color: var(--brand-deep); }

/* 正式表格（第 4 条）：气泡里的 Markdown 表格排成真 table，横向可滚、不撑破屏 */
.m-msg .bubble .m-ning-p { margin: 0; }
.m-msg .bubble .m-ning-ul { margin: 2px 0 0; padding-left: 18px; }
.m-msg .bubble .m-ning-ul li { margin-bottom: 2px; }
.m-msg .bubble .m-ning-link { color: var(--brand-deep); text-decoration: underline; word-break: break-all; }
.m-ning-table {
  display: block; width: 100%; max-width: 100%; overflow-x: auto;
  border-collapse: collapse; margin: 6px 0 2px;
  font-size: 12.5px; line-height: 1.5; white-space: normal;
}
.m-ning-table th, .m-ning-table td {
  border: 1px solid var(--line-2); padding: 5px 7px; text-align: left; vertical-align: top;
}
.m-ning-table th { background: var(--brand-tint); color: var(--jade); font-weight: 800; white-space: nowrap; }
.m-ning-table td { color: var(--ink-2); }
/* 表格里不再要气泡那层 pre-wrap：换行由表格结构表达，留着会把单元格撑成两行 */
.m-ning-table tr { white-space: normal; }
.m-msg .bubble code {
  background: var(--surface-2); border-radius: 6px; padding: 1px 5px;
  font-size: 12.5px; color: var(--jade);
}

/* 待发附件条（第 6/7 条）：图 / 定位 / 引用 先挂在输入框上方 */
.m-attach {
  display: flex; flex-direction: column; gap: 6px; flex-shrink: 0;
  padding: 8px 12px 0; background: var(--surface); border-top: 1px solid var(--line);
}
.m-attach[hidden], .m-attach-item[hidden] { display: none; }
.m-attach-item {
  display: flex; align-items: center; gap: 8px;
  padding: var(--sp-xs) var(--sp-sm); border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--line);
}
.m-attach-item .ic { width: 16px; height: 16px; color: var(--brand-deep); flex: none; }
.m-attach-thumb {
  width: 40px; height: 40px; border-radius: 10px; object-fit: cover;
  display: block; flex: none; background: var(--line);
}
.m-attach-name {
  flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-attach-x {
  flex: none; width: 24px; height: 24px; border: 0; border-radius: var(--r-pill);
  background: var(--line); color: var(--ink-2); display: grid; place-items: center; cursor: pointer;
}
.m-attach-x .ic { width: 13px; height: 13px; color: inherit; }
.m-attach-x:active { background: var(--line-2); }

/* 选择条扩充（第 5 条）：六个动作 + 计数，窄屏折行而不许横向溢出 */
.m-selbar { flex-wrap: wrap; row-gap: 6px; }
.m-selbar button { padding: 6px 9px; }
.m-selbar .m-sel-count { flex-basis: 100%; margin-left: 0; text-align: right; font-size: 11px; color: var(--ink-3); }
.m-selbar button:disabled { opacity: .45; cursor: not-allowed; }

/* 设置抽屉（第 8 条）：从底部拉起，聊天页内解决，不新开页面 */
.m-drawer-mask {
  position: fixed; inset: 0; background: var(--scrim); z-index: var(--z-max);
}
.m-drawer {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-max) + 1);
  display: flex; flex-direction: column; max-height: 78svh;
  background: var(--surface); border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  box-shadow: var(--sh-sheet); padding-bottom: var(--safe-b);
}
.m-drawer-hd {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-xl) var(--sp-xl) var(--sp-md); border-bottom: 1px solid var(--line); flex: none;
}
.m-drawer-hd b { font-size: 16px; font-weight: 900; color: var(--ink); }
.m-drawer-x {
  width: 28px; height: 28px; border: 0; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2); display: grid; place-items: center; cursor: pointer;
}
.m-drawer-x .ic { width: 15px; height: 15px; }
.m-drawer-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-lg) var(--sp-xl); display: grid; gap: 14px; }
.m-drawer-field { display: grid; gap: 6px; }
.m-drawer-lb { font-size: 12.5px; font-weight: 800; color: var(--ink-2); }
.m-drawer-row { display: flex; align-items: flex-start; gap: 12px; }
.m-drawer-txt { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.m-drawer-txt b { font-size: 13.5px; color: var(--ink); }
.m-drawer-txt small { font-size: 11.5px; color: var(--ink-3); line-height: 1.5; }
.m-switch {
  flex: none; width: 46px; height: 27px; border-radius: var(--r-pill); border: 0;
  background: var(--line-2); position: relative; cursor: pointer; transition: background .18s;
}
.m-switch-knob {
  position: absolute; top: 3px; left: 3px; width: 21px; height: 21px; border-radius: 50%;
  background: #fff; box-shadow: var(--sh-1); transition: transform .18s;
}
.m-switch.is-on { background: var(--brand); }
.m-switch.is-on .m-switch-knob { transform: translateX(19px); }
.m-drawer-prefs { display: grid; gap: 8px; }
.m-drawer-subhd { display: flex; align-items: center; justify-content: space-between; font-size: 12.5px; font-weight: 800; color: var(--ink-2); }
.m-drawer-subhd button {
  border: 1px solid var(--line-2); background: none; color: var(--danger);
  border-radius: var(--r-pill); padding: var(--sp-2xs) var(--sp-md); font-size: 11.5px; cursor: pointer;
}
.m-pref-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.m-pref {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px; border-radius: var(--r-sm); background: var(--surface-2); border: 1px solid var(--line);
}
.m-pref-txt { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--ink); word-break: break-word; }
.m-pref-hits { flex: none; font-size: 10.5px; color: var(--ink-3); }
.m-pref-x {
  flex: none; width: 22px; height: 22px; border: 0; border-radius: var(--r-pill);
  background: var(--line); color: var(--ink-2); display: grid; place-items: center; cursor: pointer;
}
.m-pref-x .ic { width: 12px; height: 12px; }
.m-pref-x:active { background: var(--danger-soft); color: var(--danger); }
.m-pref-empty { margin: 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.6; }
.m-pref-empty[hidden] { display: none; }
.m-drawer-summary { font-size: 12px; color: var(--ink-2); }
.m-drawer-summary summary { cursor: pointer; font-weight: 800; color: var(--ink-2); font-size: 12.5px; }
.m-drawer-summary p { margin: 8px 0 0; line-height: 1.7; white-space: pre-wrap; color: var(--ink-3); }
.m-drawer-ft { flex: none; padding: var(--sp-md) var(--sp-xl) var(--sp-xl); border-top: 1px solid var(--line); }
.m-drawer-save {
  width: 100%; border: 0; border-radius: var(--r-pill); padding: var(--sp-lg) 0;
  background: var(--brand); color: #fff; font: inherit; font-size: 15px; font-weight: 900; cursor: pointer;
}
.m-drawer-save:active { background: var(--brand-deep); }

/* ======================================================================
   UI 体检波（T50，2026-10-30）：触控热区 / 详情页标题 / 状态提示卡
   1) 触控热区：视觉尺寸一格不动（.m-ftab 的形状有单测钉着），用透明 ::after
      把命中面扩到 ≥40px —— 小热区是拇指误触的头号来源。
      例外：.m-loc（26px）带 overflow:hidden（搜索收起动画用）会把伪元素裁掉，
      且它是通栏宽胶囊、实际可点面积够，这轮不动它。
   2) 详情页 H1 此前是内联裸字号、零长内容防御 —— 长标题/无空格长串会撑破版式。
   3) 「审核中 / 交期已过 / 自动取消」三张状态卡此前是模板内联硬编码色 + emoji 图标，
      改品牌色时会静默残留；统一收成 .m-callout 组件（令牌配色 + Lucide 精灵）。
   ====================================================================== */
.m-dc-fav { position: relative; }
.m-dc-fav::after { content: ""; position: absolute; inset: -8px; }
.m-ftab { position: relative; }
.m-ftab::after { content: ""; position: absolute; left: -2px; right: -2px; top: -7px; bottom: -7px; }
.m-search-x { position: relative; }
.m-search-x::after { content: ""; position: absolute; inset: -7px; }
.m-input-bar .m-iconbtn { position: relative; }
.m-input-bar .m-iconbtn::after { content: ""; position: absolute; inset: -3px; }
.m-input-bar .m-send { position: relative; }
.m-input-bar .m-send::after { content: ""; position: absolute; inset: -3px; }

.m-d-title {
  font-size: 20px; font-weight: 900; letter-spacing: -.02em; line-height: 1.35;
  margin: 9px 0 0; overflow-wrap: anywhere;
}

.m-callout { margin-top: 10px; border-radius: var(--r-sm); padding: 12px 14px; }
.m-callout .m-callout-t {
  display: flex; align-items: center; gap: 5px;
  font-weight: 800; font-size: 14px;
}
.m-callout .m-callout-t .ic { flex: none; }
.m-callout p { margin: 6px 0 0; font-size: 13px; line-height: 1.6; }
.m-callout p b { font-weight: 800; }
.m-callout-warn { border: 1px solid var(--warn); background: var(--warn-soft); color: var(--warn-ink); }
.m-callout-danger { border: 1px solid var(--danger); background: var(--danger-soft); color: var(--danger-ink); }
.m-charter { margin: 0; padding-left: 18px; line-height: 2; font-size: 13.5px; color: var(--ink-2); }
.m-charter li b { color: var(--ink); font-weight: 800; }

/* ======================================================================
   T54 发视频（派总 2026-11-02 第 1、4、5、6 条）
   ----------------------------------------------------------------------
   三段：① 卡片 / 详情页的视频角标与「播不出来」提示；② 发布页选片区；
   ③ `/app/video/<pk>/` 竖屏沉浸流。
   ⚠️ ①③那些只在手机端模板出现的类只写这一份就够了；但 `.pc-card-dur` 来自
      `templates/partials/_post_card.html`（**两端共用的一张卡片**），网页版不加载
      m.css ⇒ 它必须在 app.css 再写一遍，漏一处就是「电脑上没有时长角标」
      （这类错不报 500、只是样式静默失效，audit_css.py 拦的就是它）。
   ====================================================================== */

/* ---- ① 卡片右下角的时长角标 + 详情页「播不出来」那三件 ---- */
.pc-card-dur {
  position: absolute; z-index: 2; right: 7px; bottom: 7px;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: rgba(0, 0, 0, .58); color: #fff;
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
  pointer-events: none;
}
/* 详情页那颗 `<video controls>` 播不出来时（iPhone 的 HEVC 在安卓/Chrome 上放不了）：
   video 不藏（藏了整块塌，用户想重试还得翻页），只把下面那行说明亮出来。 */
.pcp-video { position: relative; }
.pcp-video.is-blocked video { opacity: .25; }
.pcp-vnote {
  display: block; margin-top: 8px; padding: 8px 10px;
  border-radius: var(--r-sm); background: var(--warn-soft); color: var(--warn-ink);
  font-size: 12.5px; line-height: 1.6;
}
.pcp-vdur {
  display: inline-block; margin-top: 8px;
  font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.pcp-vfull {
  display: inline-flex; align-items: center; gap: 4px;
  margin: 8px 0 0 8px; padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; font-size: 12.5px; font-weight: 700;
  vertical-align: top;
}
.pcp-vfull .ic { width: 15px; height: 15px; }

/* ---- T59⑤（派总 2026-11-04 第 5 条）视频详情：上 1/3 固定预览 + 下 2/3 独立滚动 ----
   原来的样子是「上图下文整页滚」：视频跟着正文一起被划走，划到下面评论时画面就没了 ——
   派总不要这个。改成：**画面那一横条钉住不动**，底下（作者行 / 正文 / 评论）在自己的
   那 2/3 屏里往上滑。

   为什么是「一条 `position:fixed` 的画面带 + 正文用 `padding-top` 顶开」，
   而不是把下半截再套一层 `overflow-y:auto` 的滚动容器：
   ① 这一页底下那根互动条（`.pcp-dock`）、图片灯箱、设置弹层**全是 fixed**，而且 app.js
      的评论展开 / @ 候选 / 定位面板都按视口算位置 —— 再造一层滚动容器就要把这些全都
      重新对齐一遍，改一处漏一处（同 T27 聊天页「浮层不许猜 bottom」那一条血案）；
   ② 用户看到的「独立滚动」只要求**画面不动、评论动**：正文在页面滚动时从画面带底下
      划过去、被那块 #000 挡住，视觉结果就是「评论在自己那一屏里上滑」，一个容器都不用新造；
   ③ 少一层滚动容器 = 少一套手势归属（这条页原来就没有下拉刷新，`data-no-pull` 那套不用碰）。
   ⚠️ 带宽与顶栏内的 `.m-top-in` 同一条 `max-width:720px` 居中口径 —— 电脑上打开这一页时
      画面不会比顶栏宽出去一截。 */
.pcp.pcp-vsplit { --pcp-band-h: 33vh; padding-top: var(--pcp-band-h); }
/* 老内核认得 vh 就先用 vh；认得 dvh 的用 dvh（地址栏收放后那才是真的可视高，
   与沉浸流 `.mv-feed` 同一套写法）。 */
@supports (height: 33dvh) { .pcp.pcp-vsplit { --pcp-band-h: 33dvh; } }
.pcp-vsplit .pcp-video {
  position: fixed; z-index: 30;
  top: calc(var(--safe-t) + var(--top-h) + var(--top-line));
  left: 50%; transform: translateX(-50%);
  width: min(100%, 720px); height: var(--pcp-band-h);
  margin: 0; overflow: hidden; background: #000;
  display: grid; place-items: center;   /* 画面那块在黑带里居中（上下左右都可能是黑边） */
}
/* 画面矩形 = 这一块（发布者写的字 `.mov-stage` 按它的比例铺，见模板那段注释）。
   有 `video_w/video_h` 才给比例（`.has-ratio`）：竖屏以带高为准算宽，横屏以带宽为准算高；
   没比例的旧帖退回「铺满整条带」，画面由下面那条 `object-fit:contain` 自己留边。 */
.pcp-vfit { position: relative; width: 100%; height: 100%; }
.pcp-vfit.has-ratio { width: auto; height: 100%; max-width: 100%; }
.pcp-vfit.has-ratio.is-wide { width: 100%; height: auto; max-height: 100%; }
.pcp-vsplit .pcp-video video {
  width: 100%; height: 100%; max-height: none; border-radius: 0; display: block;
  object-fit: contain;      /* 只对「没比例可给」的那种起作用；有比例的宽高比已经锁在块上 */
}
/* 三颗浮在画面上的东西跟着搬进带里（原来它们是视频**下面**的一排 inline 元素 ——
   视频钉住之后那一排还留在正文流里，就会划进正文中间，说不清是谁的时长）。
   原生 `controls` 占着带的下沿，所以时长与「全屏看」都放上沿，两端各一颗。 */
.pcp-vsplit .pcp-vdur {
  position: absolute; left: 10px; top: 10px; margin: 0; padding: 2px 8px;
  border-radius: var(--r-pill); background: rgba(0, 0, 0, .45);
  color: #fff; font-size: 11.5px;
}
.pcp-vsplit .pcp-vfull {
  position: absolute; right: 10px; top: 10px; margin: 0;
  padding: 6px 12px; box-shadow: 0 2px 10px rgba(0, 0, 0, .3);
}
.pcp-vsplit .pcp-vnote {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0;
  border-radius: 0; background: rgba(16, 20, 24, .82); color: #fff;
}
/* 带下面第一样东西与画面留 12px 空气（原来那 12px 是视频自己的上边距，被 fixed 吃掉了）。 */
.pcp-vsplit .pcp-head { padding-top: 12px; }

/* ---- ② 发布页（?mode=video）：选片 → 预览 → 上传读数 ----
   T59②（派总 2026-11-04 第 1 条）把这一屏的 `.pcn-vpick / .pcn-vstage / .pcn-vbar / .pcn-vstat /
   .pcn-vbtn` 换成与发图文同款的 `.pcn-stage--v` + `.pcn-emenu`，样式在上面那段「T59②」里只有
   一份（这里再留一份就是两个真身，改一处另一处不会跟着动）。
   `.pcn-vnote`（播不了的实话）与网页版那几类**照旧**：网页版仍用 `.pcn-vstage` 那套，
   它的样式在 app.css，不在本文件。 */
.pcn-vnote {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--r-sm);
  background: var(--paper-2); color: var(--ink-2); font-size: 12.5px; line-height: 1.6;
}
.pcn-vnote.is-bad { background: var(--danger-soft); color: var(--danger-ink); }

/* ---- ③ 竖屏沉浸流 ----
   滚动用原生 CSS scroll-snap（派总第 6 条「上滑下一条 / 下滑回上一条」）：
   JS 掺进滚动必然一顿一顿，这里只让它管「谁该播」。 */
.m-top.mv-none { display: none; }
/* 沉浸流要**全幅**：.m-main 那条 max-width:720px 在电脑上会留两条白边，视频就不是全屏了。
   下面那四个常量是这一屏下半截的**唯一版面真相**（派总 2026-11-02 第 6、7 条）：
   底部评论框、进度条、右侧竖排（每条视频一份，absolute）与声音钮（整页一份，fixed）
   分属两套定位，要拼成看着齐的一列，只能共用同一组数 —— 改这里，四处一起跟着走。
   ⚠️ 必须挂在 `.mv-main` 上而不是 `.mv-feed`：评论框和声音钮是 `.mv-feed` 的**兄弟**，
      挂在 feed 上它们继承不到（CSS 变量只往下传）。 */
.m-main.mv-main {
  max-width: none; padding: 0;
  /* T56②（派总 2026-11-04 第 2 条「底部文本框改为最底部贴边显示」）：
     条贴在屏幕底边，安全区由条自己的 `padding-bottom` 吃进去 ⇒ 这一组常量算的是
     「条的顶边离屏幕底多远」，所以高度里必须含 `--safe-b`；四处（竖排/声音/文字层/进度条）
     都从它往下推，改条的内边距就改这一处。 */
  /* T59⑦（派总 2026-11-04 第 7 条「文本框显示出来」）：46 → 52 —— 输入框从 34px 加到 40px
     才够「一眼认出这是个能打的框」（热区地板 40px），条上下各 6px 内边距不变。 */
  --mv-bar-h: calc(52px + var(--safe-b));  /* 评论条收起时的实测高度（展开的面板往上长，不占这份预算；52px = 输入排 40px + 上下各 6px，改条的内边距要一起改这里） */
  --mv-btn-h: 56px;     /* 竖排每一颗的高度（.mv-act 写死，见下面那条） */
  --mv-gap: 15px;       /* 竖排颗与颗之间的间距 */
  --mv-rail-b: calc(var(--mv-bar-h) + 2px);   /* 声音钮的底边 = 条顶 + 2px 空气；竖排从它再往上摞 */
}

.mv-feed {
  position: relative;
  height: 100vh;                 /* 兜底：不认 dvh 的老内核 */
  height: 100dvh;                /* dvh 才算得进地址栏收放后的真可视高 */
  overflow-y: auto; overflow-x: hidden;
  scroll-snap-type: y mandatory;
  /* 两轴都写死 + overscroll 关掉外溢：只写 overflow-y 时 CSS 会把另一轴**算成 auto**，
     长文字就把整页撑出横向滚动条（同 T27 聊天页那条血案）。 */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: #000;
}
.mv-item {
  position: relative; height: 100%; overflow: hidden;
  scroll-snap-align: start; scroll-snap-stop: always;
  background: #000;
}
.mv-stage { position: absolute; inset: 0; background: #000; }
.mv-cover, .mv-vid {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
/* T59④（派总 2026-11-04 第 4 条「从一个视频刷到另一个视频还是会黑屏加载」）：
   `.mv-vid` 原来也带着 `background:#000` —— 而它**压在封面图上面**（同 inset:0，DOM 在后）。
   video 在「还没取到数据」的那几秒里自己不画任何东西，于是那块 CSS 黑底就成了挡在
   封面前的实心黑 ⇒ 用户看到的是「黑屏加载中」，而**同一时刻真封面早就在盘上、就在它底下**。
   改成透明：数据没来时透出封面，数据来了画面照旧（视频帧本来就不透光）；
   横屏留的黑边由 `.mv-stage`/`.mv-item` 那两层 #000 提供，不靠这一条。 */
.mv-vid { background: transparent; }
.mv-cover-blank { display: grid; place-items: center; background: #101418; color: rgba(255, 255, 255, .32); }
.mv-cover-blank .ic { width: 54px; height: 54px; }
/* 横屏拍的（发布时存下的 video_w > video_h）：留上下黑边完整显示，不强裁成竖屏 ——
   cover 裁掉的正是画面左右两边的人或物。封面图跟着一起 contain，
   不然「封面裁满、一动变成留边」那一下跳动很显眼。 */
.mv-cover.is-wide, .mv-vid.is-wide { object-fit: contain; }
/* 格式播不出来：video 那块黑没有信息量，藏掉，露出真封面图 + 下面那行实话 */
.mv-item.is-blocked .mv-vid { display: none; }
/* T59④ 加载指示（派总 2026-11-04 第 4 条）：封面透出之后，「正在取这一条的数据」这件事
   得有个说法，否则画面静止看起来像卡住（用户分不清「播完了」「在缓冲」「没声音」）。
   与暂停那颗 `.mv-hold` 同一个位置、同一档 z-index ⇒ 两态天然互斥（JS 切 hidden，
   见 video-feed.js 的 buffering），画面上永远只有一个居中的东西。
   只用一圈细环 + 亮头，不引新颜色、不加底：视频上任何实心块都比信息更抢眼。 */
.mv-spin {
  position: absolute; z-index: 4; left: 50%; top: 50%;
  width: 44px; height: 44px; margin: -22px 0 0 -22px;
  border-radius: 50%; pointer-events: none;
  border: 3px solid rgba(255, 255, 255, .22);
  border-top-color: rgba(255, 255, 255, .92);
  animation: mvSpin .8s linear infinite;
}
@keyframes mvSpin { to { transform: rotate(360deg); } }

.mv-shade {
  position: absolute; z-index: 1; inset: 0; pointer-events: none;
  /* T56④（派总 2026-11-04 第 4 条「视频顶部的留白请删除，确保视频全屏显示」）：
     上面那一段**压暗带**原来从 0 压到 22% 高（给左上角标题和右上角「第几条/共几条」垫底）。
     第 5 条把那颗读数删了、顶部再没有浮在画面上的东西 ⇒ 它就是「顶部凭空多出一条黑」，
     白底视频在上面看起来像没铺满。只留底部那一段（评论与文字层还在白字压画面）。
     ⚠️ 「顶部留白」量的不是布局：`.mv-stage` 本来就 `inset:0` 铺满，量出来 top=0、
        height=可视高 —— 留白来自这层渐变，不是某个 margin（别去动版式，改了也不会有变化）。 */
  background: linear-gradient(0deg, rgba(0, 0, 0, .62) 0, rgba(0, 0, 0, 0) 34%);
}
.mv-blocked {
  position: absolute; z-index: 3; left: 18px; right: 18px; top: 42%;
  margin: 0; padding: 10px 12px; border-radius: var(--r-sm);
  background: rgba(16, 20, 24, .72); color: #fff;
  font-size: 12.5px; line-height: 1.65;
}
.mv-blocked a { color: var(--brand); font-weight: 800; text-decoration: underline; }

/* 派总 2026-11-02 第 5 条：左上角那颗「×」撤了（退出改由**左边缘右滑**承担）。
   派总 2026-11-04 第 5 条：右上角「第几条/共几条」也撤了 ⇒ 上面那一整行（.mv-top / .mv-seq）
   连 markup 带样式一起拆（铁律「死功能即拆」：留一条没人认领的规则，下次谁都说不清它给谁用）。 */

/* T57③（派总 2026-11-04 第 3 条「视频顶部左侧返回、右侧搜索」）：沉浸页顶部这一层。
   · 钉在 `--safe-t` **之下**：第 2 条要的是视频盖住刘海、系统时间/信号/电量浮在画面上，
     两颗钮不能钻进状态栏里去（`top: calc(var(--safe-t) + 8px)`，安全区一变它跟着走）。
   · 通栏但**不吃点击**：`pointer-events:none` + 只给两颗钮 `auto` —— 这一层横跨整条顶边，
     不关掉的话「点画面暂停」在整个顶边失效（video-feed.js 的 tap 判据只排除 a/button/…）。
   · 底色对着画面调：纯白字压在雪景/白墙上会化掉，纯黑块又像贴了一块膏药 ⇒ 深灰半透明 + 模糊。 */
.mv-head {
  position: fixed; z-index: 46; left: 0; right: 0;
  top: calc(var(--safe-t) + 8px);
  display: flex; align-items: center; gap: 8px;
  padding: 0 12px; pointer-events: none;
}
.mv-headbtn {
  pointer-events: auto;
  display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: rgba(20, 24, 28, .42); color: #fff;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  text-decoration: none; flex: 0 0 auto;
}
.mv-headbtn .ic { width: 21px; height: 21px; }
.mv-headbtn:active { background: rgba(20, 24, 28, .62); }
.mv-head-sp { flex: 1; }

/* 搜索输入层：与 `.mv-head` **同一行位置**（`top` 用同一组数），点放大镜时 head 隐、这条显，
   看起来是「原位长出一个输入框」。不做白底 —— 白条会把视频顶部切掉一道白，
   第 2 条要的是画面铺满；深色半透明条与画面融为一体，字仍是白的。 */
.mv-search {
  position: fixed; z-index: 47; left: 12px; right: 12px;
  top: calc(var(--safe-t) + 8px);
  height: 40px; display: flex; align-items: center; gap: 8px;
  padding: 0 6px 0 12px; border-radius: var(--r-pill);
  background: rgba(20, 24, 28, .66); color: #fff;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.mv-search .ic { flex: 0 0 auto; color: rgba(255, 255, 255, .72); }
.mv-search input {
  flex: 1; min-width: 0; height: 100%;
  border: 0; outline: 0; background: transparent;
  color: #fff; font-size: 14px;
}
.mv-search input::placeholder { color: rgba(255, 255, 255, .56); }
.mv-search-go {
  -webkit-appearance: none; appearance: none; border: 0; flex: 0 0 auto;
  padding: 7px 13px; border-radius: var(--r-pill);
  background: var(--brand); color: #fff; font-size: 13px; font-weight: 800;
}
.mv-search-x {
  -webkit-appearance: none; appearance: none; border: 0; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: transparent; color: rgba(255, 255, 255, .78);
}
.mv-search-x:active { background: rgba(255, 255, 255, .14); }

/* 右侧竖排。派总 2026-11-02 第 6 条：整列**上移一个按钮的高度**（给底部评论框让位），
   空出来的那格由声音钮补上 —— 这一列钉在 `--mv-rail-b`（= 评论条顶边 + 2px）之上再摞
   「一颗按钮 + 一个间距」，声音钮钉在 `--mv-rail-b`，于是「转发之下就是声音」
   是同一组常量算出来的，不是肉眼对出来的。T56② 评论条贴边之后，这两条**一个数都没改**，
   跟着 `--mv-bar-h` 一起往下走（派总第 4 条要的视频全屏，底下少了一条 10px 的空隙）。 */
.mv-acts {
  position: absolute; z-index: 3; right: 10px;
  bottom: calc(var(--mv-rail-b) + var(--mv-btn-h) + var(--mv-gap));
  display: flex; flex-direction: column; align-items: center; gap: var(--mv-gap);
}
.mv-face {
  display: block; width: 46px; height: 46px; border-radius: 50%; overflow: hidden;
  border: 2px solid rgba(255, 255, 255, .88); background: rgba(0, 0, 0, .35);
  /* 亮画面（雪景 / 白墙）上白圈会「化」进背景里 —— 补一层暗影把头像从画面里托出来。 */
  box-shadow: 0 2px 10px rgba(0, 0, 0, .38);
}
.mv-face .av { width: 100%; height: 100%; display: grid; place-items: center; font-size: 15px; }
/* T56⑥（派总 2026-11-04 第 6 条「发布者为他人时，头像下方添加一个＋号关注；关注后＋号消失」）：
   头像和那颗 ＋ 是一个整体（`.mv-face-wrap`），所以它在竖排里仍只占**一颗**的位置，
   颗距常量 `--mv-gap` 一点没动 —— 不然加了 ＋ 的那条比别条高 26px，整列对不齐。
   ＋ 贴在头像正下方居中（小红书/抖音同款手势位），白圈深底保证压在亮画面上也看得见。
   已关注的人服务端就不画这个 form（`hidden` 之外还有一层「根本不在 DOM 里」），
   点完之后的收起由 app.js 那颗通用关注逻辑管（`data-follow-context="add"` 那一档）。 */
.mv-face-wrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.mv-follow { -webkit-appearance: none; appearance: none; border: 0; margin: 0; padding: 0; background: transparent; }
.mv-follow button {
  -webkit-appearance: none; appearance: none; margin: 0; padding: 0; cursor: pointer;
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand); color: #fff; border: 2px solid rgba(255, 255, 255, .9);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .38);
}
.mv-follow button .ic { width: 15px; height: 15px; }
.mv-follow button:active { transform: scale(.9); }
/* 高度写死成 --mv-btn-h：这一列的**颗距**必须是确定的，
   否则整页唯一那颗声音钮（fixed，靠同一组常量对位）就会跟「转发」差上几像素 ——
   而带数字的（点赞/收藏/评论）与不带数字的（转发/声音）内容高度本来就不一样。 */
.mv-act {
  -webkit-appearance: none; appearance: none; border: 0; margin: 0; padding: 0;
  width: 52px; height: var(--mv-btn-h); background: transparent; color: #fff; font: inherit;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 3px;
  cursor: pointer; text-decoration: none;
}
/* 派总第 8 条「精致一些」：触屏按下去要给一点反馈。
   原来这一列按下去**什么也不变**（图标是白字压在视频上，没有底），要点两下才确定自己按到了。
   `:active` 只缩 8%、120ms，`transform` 不动布局 ⇒ 整列颗距一点没变（U2/U2b 那些量像素的判据不受影响）。
   ⚠️ 写在 `.mv-act` 而不是 `.mv-act button`：点赞/收藏那颗的类挂在 `<form>` 上，
      而按到的热区是里面的 `<button>` —— 两条都要，否则那两颗按下去没反应。 */
.mv-act, .mv-act button, .mv-face { transition: transform .12s ease-out, opacity .12s ease-out; }
.mv-act:active, .mv-act button:active, .mv-face:active { transform: scale(.92); opacity: .82; }
/* 键盘 / 遥控器焦点：这一页没有底栏，Tab 能走到的东西必须看得见在哪儿。
   用 outline 不用 box-shadow —— 焦点环不许被 `:active` 那一下缩放带走。 */
.mv-act:focus-visible, .mv-face:focus-visible, .mv-cir:focus-visible, .mv-name:focus-visible {
  outline: 2px solid var(--brand); outline-offset: 3px; border-radius: var(--r-pill);
}
/* 点赞 / 收藏在 markup 里是 <form><button>，两颗钮的默认外观都得清掉，
   不然安卓 WebView 会给它套一块灰底 outset 框（T34 那颗齿轮钮同样的坑）。 */
.mv-act button {
  -webkit-appearance: none; appearance: none; border: 0; margin: 0; padding: 0;
  background: transparent; color: inherit; font: inherit; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
/* `.ic` 的底座是 `fill:none; stroke:currentColor`（Lucide 描线图标），
   所以这里**只给爱心和星星上实心**（`.mv-like` / `.mv-fav` 那两条）：
   给整列都写 `fill:#fff` 会把评论气泡、转发箭头糊成白疙瘩。
   `margin-top:4px` 让六颗钮的图标贴在同一条水平线上（按钮等高之后不必再给谁单独下沉）。 */
.mv-act .ic { width: 30px; height: 30px; margin-top: 4px; color: #fff; filter: drop-shadow(0 1px 4px rgba(0, 0, 0, .6)); }
.mv-act.mv-like .ic, .mv-act.mv-fav .ic { fill: #fff; }
.mv-n { font-size: 11px; font-weight: 700; color: #fff; text-shadow: 0 1px 3px rgba(0, 0, 0, .65); }
/* 已赞 / 已藏：口径与详情页、卡片完全一致（Z6② 统一红实心，不用金黄） */
.mv-act.mv-like.on .ic, .mv-act.mv-fav.on .ic,
.mv-act button.on .ic { color: var(--coral); fill: var(--coral); filter: drop-shadow(0 0 6px rgba(255, 106, 69, .5)); }

/* 左下文字层：抬到评论框 + 进度条之上（原来和竖排同一条底边，现在那条边被声音钮占了）。
   右边留 78px 是给右侧那一列（宽 52 + 右距 10 + 一点空气），文字不许钻到图标底下去。 */
.mv-info {
  position: absolute; z-index: 3; left: 14px; right: 78px;
  bottom: calc(var(--mv-bar-h) + 18px);
}
.mv-name { font-size: 15px; font-weight: 900; color: #fff; text-decoration: none; text-shadow: 0 1px 4px rgba(0, 0, 0, .6); }
.mv-title {
  margin: 6px 0 0; font-size: 14.5px; font-weight: 700; line-height: 1.45; color: #fff;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .55); overflow-wrap: anywhere;
}
.mv-text {
  margin: 4px 0 0; font-size: 13px; line-height: 1.55; color: rgba(255, 255, 255, .88);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  overflow-wrap: anywhere;
}
.mv-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0 0; font-size: 12px; color: rgba(255, 255, 255, .8); }
.mv-meta .ic { width: 13px; height: 13px; vertical-align: -2px; }
.mv-loc { display: inline-flex; align-items: center; gap: 3px; min-width: 0; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mv-cir { display: inline-flex; align-items: center; gap: 3px; padding: 2px 9px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .18); color: #fff; text-decoration: none; font-weight: 700; }
.mv-dur { font-variant-numeric: tabular-nums; }

/* 点画面暂停时浮在中间的那颗三角 —— 不画出来，暂停看起来像卡住 */
.mv-hold {
  position: absolute; z-index: 4; left: 50%; top: 50%;
  width: 74px; height: 74px; margin: -37px 0 0 -37px;
  display: grid; place-items: center; border-radius: 50%;
  background: rgba(0, 0, 0, .38); pointer-events: none;
  /* 派总第 8 条：`hidden` 一摘就是「啪」地出现，硬得像画面卡了一下。
     补一个从 0.8 倍弹到位的 160ms（只动 transform/opacity ⇒ 走合成层，不触发布局）。
     动画挂在 `:not([hidden])` 上：JS 只切 hidden，没有第二个类可加，也不用加。 */
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.mv-hold:not([hidden]) { animation: mvPop .16s ease-out; }
@keyframes mvPop { from { transform: scale(.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.mv-hold .ic { width: 34px; height: 34px; color: #fff; fill: #fff; }

/* 进度条：原来横贯整屏、钉在 safe-b+54 —— 那块地方现在是评论框（第 7 条）。
   搬到评论框正上方，并跟左下文字层同宽（14 → 78），读起来就是「这条视频的进度」，
   也不会从声音钮身上横穿过去。
   派总第 8 条：2px + 22% 白在深色画面上几乎看不见（0:00 时等于没有），
   加到 3px、轨道提到 30%、走到的那截给一点光晕 —— 仍然是「细的一条」，不改成抖音那种粗条。 */
.mv-track {
  position: absolute; z-index: 3; left: 14px; right: 78px;
  bottom: calc(var(--mv-bar-h) + 8px);
  height: 3px; border-radius: 3px; background: rgba(255, 255, 255, .3);
}
/* 用 scaleX 而不是写 width：每帧只改一个合成属性，不动布局（200 条一起量会掉帧） */
.mv-track i {
  display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--brand-deep), var(--brand));
  box-shadow: 0 0 6px rgba(0, 189, 166, .55);
  transform: scaleX(0); transform-origin: left center;
}

/* 全屏只有这一颗声音钮（默认静音是浏览器的硬约束，见 video-feed.js 文件头第 1 条）。
   派总 2026-11-02 第 6 条：从右上角那颗胶囊搬进右侧竖排的**最下面一格**，
   版式与那五颗完全同构（markup 上就带着 `.mv-act`，所以尺寸/图标/字号都吃那一份），
   这里只写「它钉在哪儿」：底边 = `--mv-rail-b`（评论条顶边 + 2px 空气），
   竖排自己再往上摞一颗按钮 + 一个间距 ⇒「转发之下就是声音」这个次序
   是同一组常量算出来的，不靠肉眼对像素。
   派总 2026-11-04 第 3 条：按钮里「开声音/关声音」那行**文字删了**，只留图标
   （`applyMuted()` 不再改写标签，markup 里也没有那个 `<span>`）—— 这颗和右边那一列
   同宽同构，但没有下面的读数，视觉上比别颗轻，正合适：它是整页唯一的开关，不需要数字陪。
   ⚠️ 它仍然 `fixed`（整页一颗）而不是跟着每条视频一份：它管的是整页所有 `<video>`
   和那一只共用的 `<audio>`；200 条各挂一颗就要 200 处同步图标状态。 */
.mv-sound {
  position: fixed; z-index: 45; right: 10px;
  bottom: var(--mv-rail-b);
}

/* 一次性手势提示。第 5 条撤掉「×」之后，退出只剩手势这一个入口 ⇒ 四条都要写出来。
   派总第 8 条「精致一些」：原来是一行 + 三根竖线分隔，375px 上排不下就 `flex-wrap` 换行，
   换行的那一截**开头没有分隔线、上一截结尾还甩着一根**，看着像没排完。
   改成**两行两列的网格**：对齐本身就是分隔，分隔线整条删掉（模板里的 `<i>` 一起删）。 */
.mv-hint {
  position: fixed; z-index: 46; left: 50%; transform: translateX(-50%);
  top: calc(var(--safe-t) + 58px);
  display: grid; grid-template-columns: repeat(2, max-content);
  align-items: center; justify-content: center; gap: 6px 18px;
  max-width: calc(100vw - 32px);
  padding: 9px 16px; border-radius: 16px;
  background: rgba(16, 20, 24, .68); color: #fff; font-size: 12px; line-height: 1.5;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .12);
  pointer-events: none;
}

/* ---- 底部贴边评论条（派总 2026-11-02 第 7 条 → 2026-11-04 第 2 条改贴边铺满）----
   里面的表单是 `m/_comment_composer.html`，与详情页**同一份**，这里只覆写版式。
   详情页是「一张白卡浮在底部、两行竖排（输入在上、工具在下）」，
   派总要的是「贴着屏幕底边的一条半透明白，横着一排铺满」：
     ⚙ │ 说点什么… │ 😊 @ 🖼 📍 发送
   三条口径：
   ① 半透明白挂在**整条**（`.mv-commentbar`）上，表单自己透明 —— 否则齿轮和输入框
      各背一块白，中间会露出一条视频缝；
   ② 表单从纵向 flex 改成**横向 + 换行**：输入框 `flex:1` 把中间撑满，工具那一排
      `flex:0 0 auto` 贴右长，于是「表情/@/图片/位置/发送」自己排到最右边，铺满一整排。
      中间那颗弹簧 `.pcp-dock-grow`（详情页用来把「发送」顶到最右）在这一排里分不到
      多余宽度、自己就是 0 —— 不许在这儿删它：它归详情页那份模板管，一个口径一个真身；
   ③ 表情面板 / @ 候选 / 配图预览 / 地点 chip 全部 `flex:1 0 100%` + `order:-1`：
      它们是**在流里**长高的，这一条由 `bottom` 定位 ⇒ 长高只往上顶，
      不会把输入那一排挤到屏幕外面，也不会挡住视频。
   ⚠️ 不写死条高：见 ③。`--mv-bar-h`（在 `.mv-main` 那四条常量里）只是「收起时」的预算，
      供右侧竖排、声音钮、左下文字层、进度条四处让位用 —— 条的内边距一改，那处跟着改。 */
.mv-commentbar {
  position: fixed; z-index: 44;
  left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px calc(6px + var(--safe-b));
  /* 派总 2026-11-04 第 1 条「透明度不够，设为 25%」：.82 → .25。
     ⚠️ 这一处**不能单独改**：这一排底下永远压着 `.mv-shade`（0 → 屏幕底边 62% 黑纱），
        白垫叠在它上面，真浏览器实测（三条只有封面的量测帖，白/中灰/近黑，2026-11-04）
        条的表面亮度只有 **68 / 108 / 148** 这一小截灰阶。原来那套深墨前景
        （`--ink` #1a1a1d）在上面最低只剩 **1.78:1**（WCAG 正文要 4.5:1）——
        改完就是「字还在，但黑底视频上看不见」。所以前景跟着整排一起翻白：
        白字对同一块垫子是 9.73:1（黑帧）~3.03:1（白帧），
        白帧那一端靠下面那层黑影把字形边缘再压暗一档才读得清 —— 这招不是新发明的，
        这一页右侧竖排 `.mv-act .ic`（`drop-shadow 0 1px 4px .6`）与左下 `.mv-name`
        （`text-shadow 0 1px 4px .6`）压的就是同一种白视频画面，用的同一套数值，照抄。
        自带底色的元件不跟着翻：表情面板 #fff、@ 候选与地点 chip brand-soft、
        发送那颗 --brand 绿底白字 —— 它们自己就是可读的一块，翻了反而糊。 */
  background: rgba(255, 255, 255, .25);
  color: #fff;
  -webkit-backdrop-filter: blur(14px) saturate(1.15);
  backdrop-filter: blur(14px) saturate(1.15);
}
.mv-commentbar form {
  flex: 1; min-width: 0;
  position: relative;
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px;
  background: transparent; border-radius: 0; box-shadow: none; padding: 0;
}
.mv-commentbar form:focus-within { box-shadow: none; }
/* T59⑦（派总 2026-11-04 第 7 条「"说点什么…"文本框显示出来（当前文本框与磨砂底栏浑然一体）」）：
   病根是**两层"透明"叠在一起** —— 上面那条 `.mv-commentbar form{background:transparent}` 把
   详情页白卡清零（条自己就是那块半透明白），而 `.pcp-dock-expand .pcp-cmt-input`（4561 行）
   又把输入框清零（`background:transparent;border:0`）。于是输入框在**整页唯一的 25% 白垫**上
   没有任何自己的边界 ⇒ 白字直接落在磨砂上，用户看不见"该往哪打字"。
   修法只给输入框**自己一块深底**（不动条，条的 25% 白垫是第 1 条定的，U3b/T2b 两条闸门钉着它）：
   · 底 `rgba(16,20,24,.5)` —— 与这一页其余浮层同一支暗色（`.mv-blocked`、提示条都是它），
     压在 25% 白垫上形成**亮度断层**（实测条面 68~148 灰阶 → 框内 49~86），这才叫"看得见框"；
   · 描边用 `inset` 一圈 55% 白：不吃盒模型、不加宽、不会因为 1px 边框把同行挤换行（T2g 判据）；
   · 底一深，白字的对比度反而**涨了**（原来白字压 25% 白垫最低只剩 3.03:1，现按 ≥4.5:1 走）
     ⇒ 那层 `text-shadow` 不再需要，去掉：黑影在实底上会让字形边缘发浑；
   · 高度从 34px 提到 40px（热区地板），`--mv-bar-h` 的 46 也跟着改 52 —— 四处（竖排/声音/文字层/
     进度条）都从这一处往下推，不会错位。 */
.mv-commentbar .pcp-cmt-input {
  flex: 1 1 90px; min-width: 0; width: auto;
  min-height: 40px; padding: 8px 12px; font-size: 13.5px; line-height: 1.35;
  color: #fff;
  background: rgba(16, 20, 24, .5);
  border: 0; border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .55);
}
.mv-commentbar .pcp-cmt-input::placeholder { color: rgba(255, 255, 255, .86); }
/* 焦点态：描边加亮一档，让"正在打字"这件事在暗底上也看得出来（详情页那圈 brand 绿在这一排
   压在半透白垫上读不出来，所以这里只改自己的描边，不引第三套颜色）。 */
.mv-commentbar .pcp-cmt-input:focus {
  border: 0; outline: none;
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .9);
}
.mv-commentbar .pcp-dock-tools {
  flex: 0 0 auto; margin-top: 0; gap: 4px;
  /* T59⑦：输入框和这颗齿轮都穿上了深底，工具排还光着落在 25% 白垫上 ——
     白图标压浅垫（白视频帧那端实测 148）只有 1.9:1，是整排唯一读不清的一处。
     给它同一支底、同一圈描边，三块拼起来是「一组控件」而不是三处各画各的。 */
  padding: 0 4px; border-radius: var(--r-pill);
  background: rgba(16, 20, 24, .5);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .55);
}
.mv-commentbar .pcp-tool { padding: 3px 5px; font-size: 17px; }
.mv-commentbar .pcp-tool .ic { width: 19px; height: 19px; }
/* 这一排里「跟着条走」的两样：四颗工具钮的线框图标、取消那颗文字钮。
   图标（`<svg>`）不吃 `text-shadow` ⇒ 黑影走 `filter: drop-shadow`，与 `.mv-act .ic` 同一招。
   ⚠️ 工具钮选中态（地点那颗 `.on`）原本刷成 brand-soft 浅绿底 + brand-deep 深绿字，
      那是详情页白卡上的语言；在这一排浅底会盖住白字、深绿字压在 25% 白垫上又太暗，
      所以选中态在这一页只描一圈亮边不改底。 */
.mv-commentbar .pcp-tool,
.mv-commentbar .pcp-cmt-cancel { color: #fff; }
.mv-commentbar .pcp-tool .ic { filter: drop-shadow(0 1px 4px rgba(0, 0, 0, .6)); }
.mv-commentbar .pcp-tool:active { background: rgba(255, 255, 255, .18); }
.mv-commentbar .pcp-tool[data-cmt-loc-toggle].on {
  background: none; color: #fff;
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .75);
}
.mv-commentbar .pcp-cmt-send { padding: 6px 13px; font-size: 12.5px; }
.mv-commentbar .pcp-cmt-imgprev,
.mv-commentbar .pcp-cmt-sharechip { flex: 1 0 100%; order: -1; margin-top: 0; }
/* ⚙ 那颗（派总 2026-11-04 第 1、2 条：齿轮放在文本框左侧）：
   它是输入框的**兄弟**、不在表单里 —— 面板整页只挂一份（见 circle_video.html ①），
   滑到别条时由 post-settings.js 的 setTarget() 改写四颗钮的目标，齿轮只管开合。
   只给「这条是我发的」画，判据是服务层的 can_delete_ids。
   ⚠️ 最后那条 `[hidden]` 不是多余的：上面写了 `display:grid`，它会**盖掉**浏览器默认的
      `[hidden]{display:none}` —— 少了这一行，别人的视频那条上齿轮照样露出来。
      （T35 闸门「看不见 m-sheet」同族坑：靠属性隐藏的元件，自己一声明 display 就得自己补隐藏。） */
.mv-set {
  -webkit-appearance: none; appearance: none; flex: 0 0 auto;
  width: 40px; height: 40px; margin: 0; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  /* 原来这颗是 `rgba(16,20,24,.06)` 的底 + 深墨的齿轮 —— 在详情页那张白卡上对，
     在这一排（25% 白垫压着底部黑纱，实测亮度 64~136）等于「深灰画在深灰上」看不见。
     跟着整排一起翻：白底垫淡、图标白、黑影同 `.mv-act .ic`。
     T59⑦ 再改一档：输入框有了自己的深底（.5），这颗若还是 18% 白垫就跟它不像一排东西，
     所以底的算法换成与输入框同一支、描边同一圈，尺寸跟着输入框取 40px（两颗同高才齐）。 */
  background: rgba(16, 20, 24, .5); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .55);
}
.mv-set .ic { width: 20px; height: 20px; }
.mv-set:active { transform: scale(.9); }
.mv-set[hidden] { display: none; }
/* 游客：不给一个点了必被 m_login_required 拦下的输入框，给一颗能走完的登录钮。
   通栏是「登录用户那一排」的版式，游客仍是**浮起的胶囊** ⇒ 几何与白底都得自己声明回来。 */
.mv-commentbar-guest {
  left: 14px; right: 74px; bottom: calc(var(--safe-b) + 10px);
  display: flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 16px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .84);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: var(--ink-2); font-size: 13px; font-weight: 700; text-decoration: none;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .3);
}

/* ---- 沉浸页上的提示条（派总 2026-11-03 第 8 条「精致一些」）----
   `.flash-stack` 全站共用一份样式：白底、通栏、钉在**顶栏下面**（`--top-h`）。
   这一页没有顶栏、整屏是视频，于是「声音已打开」这种一句话回执会变成
   画面上一条 366×42 的**亮白横幅**（实测：top=106、background:#fff）—— 比原来的
   「×」还抢眼。改成与这一页其余浮层同一套语言：暗底、毛玻璃、居中、按内容宽。
   ⚠️ 为什么选择器挂在 `body.mv-page` 而不是 `.mv-main` 下面：
      提示条是 `document.body` 的直接孩子（base.html 第 72 行那份，app.js 复用同一个 id），
      写在 `.m-main …` 里根本够不着 —— 类因此挂在 `<body>` 上（见 m/base.html 的 body_class）。
   `top` 不再吃 `--top-h`：这一页顶栏不渲染，那 52px 是空气。 */
body.mv-page .flash-stack {
  top: calc(var(--safe-t) + 10px); left: 50%; right: auto;
  transform: translateX(-50%); width: max-content; max-width: calc(100vw - 96px);
  padding: 0; margin: 0;
}
body.mv-page .flash {
  justify-content: center; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: var(--r-pill);
  background: rgba(16, 20, 24, .72); color: #fff; font-size: 12.5px; font-weight: 600;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .12); box-shadow: 0 6px 22px rgba(0, 0, 0, .3);
}
/* 四档语义色在白底上是「字色」，在暗底上白字会分不出成败 —— 这里换成图标色的文字版：
   成功仍用品牌绿（在暗底上够亮），失败用珊瑚红，其余保持白。 */
body.mv-page .flash.success { color: var(--brand); }
body.mv-page .flash.error { color: var(--coral); }
body.mv-page .flash.info, body.mv-page .flash.warning { color: #fff; }

/* 晕动症偏好：这一页新加的三处动效（按压缩放 / 暂停三角弹入 / 提示条落下）全部关掉。
   写在最后是因为它必须**覆写**上面那几条，而 CSS 同权重时后写的赢。 */
@media (prefers-reduced-motion: reduce) {
  .mv-act, .mv-act button, .mv-face { transition: none; }
  .mv-act:active, .mv-act button:active, .mv-face:active { transform: none; opacity: 1; }
  .mv-hold:not([hidden]) { animation: none; }
  /* T59④ 缓冲环在「减少动态」下不转（无限旋转正是这条设置要关的那一类），
     留一圈带亮头的静态环 —— 「在取数据」这件事仍然说得出，只是不用转圈说。 */
  .mv-spin { animation: none; }
  body.mv-page .flash { animation: none; }
}

/* ======================================================================
 * T62 · 弹层进出场统一动效（派总 2026-11-07「交互流畅 / 界面转换流畅」）
 * ----------------------------------------------------------------------
 * 改前实测：发布面板 / 头像面板 / 动态设置 / 柠柠抽屉四个底部弹层全是**硬切** ——
 * 点开后 50ms 与 550ms 量到的面板 top 一模一样、getAnimations() 为 0、transition 0s。
 * 口径与上面 .mv-hold 那条同源：JS 只切 hidden，进场动画挂在 :not([hidden]) 上。
 * 为什么用 animation 不用 transition：`display:none → flex` **没有可插值的起点状态**，
 * transition 根本不跑（这是实测出来的，不是猜的）；keyframe animation 则会跑。
 * 退场由 app.js 的 ymwSheetHide() 先加 .is-closing 播 --dur-2，播完再真 hidden。
 * 只动 transform/opacity ⇒ 走合成层、不触发布局，这是「跟手不卡」的物理前提。
 * ⚠️ 退场规则必须写在进场规则**后面**：两者特异性都是 (0,2,0)/(0,3,0)，靠源顺序定胜负。
 * ==================================================================== */
@keyframes ymwSheetUp { from { transform: translateY(100%); } to { transform: none; } }
@keyframes ymwSheetDown { from { transform: none; } to { transform: translateY(100%); } }
@keyframes ymwScrimIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes ymwScrimOut { from { opacity: 1; } to { opacity: 0; } }

.m-sheet:not([hidden]) .m-sheet-panel,
.av-sheet:not([hidden]) .av-sheet-panel,
.pcp-set:not([hidden]) .pcp-set-panel,
.m-drawer:not([hidden]) { animation: ymwSheetUp var(--dur-4) var(--ease); }

.m-sheet:not([hidden]) .m-sheet-mask,
.av-sheet:not([hidden]) .av-sheet-mask,
.pcp-set:not([hidden]) .pcp-set-mask,
.m-drawer-mask:not([hidden]) { animation: ymwScrimIn var(--dur-3) var(--ease-out); }

.m-sheet.is-closing .m-sheet-panel,
.av-sheet.is-closing .av-sheet-panel,
.pcp-set.is-closing .pcp-set-panel,
.m-drawer.is-closing { animation: ymwSheetDown var(--dur-2) var(--ease-in-out) forwards; }

.m-sheet.is-closing .m-sheet-mask,
.av-sheet.is-closing .av-sheet-mask,
.pcp-set.is-closing .pcp-set-mask,
.m-drawer-mask.is-closing { animation: ymwScrimOut var(--dur-2) linear forwards; }

/* 减少动态：动画全关，但**开合本身照常**（JS 那边 reduceMotion() 会把等待时长收成 0，
   不会出现「动画没了、还在傻等 180ms」—— 那正是横滑切板块原来犯的错）。 */
@media (prefers-reduced-motion: reduce) {
  .m-sheet-panel, .av-sheet-panel, .pcp-set-panel, .m-drawer,
  .m-sheet-mask, .av-sheet-mask, .pcp-set-mask, .m-drawer-mask { animation: none !important; }
}

/* ====================================================================
 * T66 · 发布动态三件套（派总 2026-11-08 第 1、2、3 条）
 *   .mpk / .mpv = 自绘相册选择器 + 全屏预览（static/js/media-picker.js）
 *   .mcv        = 自绘取景器（static/js/camera-view.js）
 *   .med        = 全新图片编辑器（static/js/media-editor.js）
 *
 * 三条口径（都是本文件既有规矩，新组件必须一起守）：
 *  ① 样式并进 m.css、**不新建 CSS 文件**：新建的文件不进 audit_css.py 的配对表，
 *     也不进 audit_design_tokens.py 的扫描表 —— 那就是第二条真相 + 一道没人看的闸。
 *  ② 颜色/圆角/投影/字号/时长全走令牌；组件自己的尺寸（格子边长、快门直径…）
 *     挂在**自己的选择器**上（--mpk-cell / --mcv-shutter），绝不开 :root ——
 *     m.css 的 :root 必须和 app.css 逐字相同（audit_mobile_tokens.py），私自加令牌就是分家。
 *  ③ 进出场走 T62 那套公共出口（app.js 的 ymwSheetShow/ymwSheetHide 只切 hidden 与
 *     .is-closing），所以四个浮层各要写一条 :not([hidden]) 进场 + 一条 .is-closing 退场，
 *     少写就是「硬切」。⚠️ 编辑器只做**淡入淡出**、不做位移：
 *     .med-stage 在动画途中会被 layoutCropBox 量 getBoundingClientRect，
 *     translate 还没落定就量 ⇒ 裁切框整体偏移（这一条是量出来的，不是猜的）。
 * ==================================================================== */

/* ---------- 0 · 锁滚：三个浮层各挂各的 body 类（同 video-edit 的 body.mve-live） ---------- */
body.mpk-live, body.mcv-live, body.med-live { overflow: hidden; }

/* ---------- 1 · 相册选择器 .mpk ---------- */
.mpk {
  position: fixed; inset: 0; z-index: var(--z-lightbox);
  display: flex; flex-direction: column;
  background: var(--paper); color: var(--ink);
  padding-top: var(--safe-t); padding-bottom: var(--safe-b);
  --mpk-h: var(--ctl-h); --mpk-side: var(--sp-xl); --mpk-cell: 84px;
  --mpk-ring: rgba(255, 255, 255, .92); --mpk-veil: rgba(8, 10, 12, .55);
}
.mpk-top {
  flex: none; min-height: var(--mpk-h); display: flex; align-items: center;
  gap: var(--sp-sm); padding: 0 var(--mpk-side);
}
.mpk-x, .mpk-act {
  flex: none; width: var(--mpk-h); height: var(--mpk-h);
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--ink); border-radius: var(--r-pill);
}
.mpk-x:active, .mpk-act:active { background: var(--surface-2); }
.mpk-title {
  flex: 1; min-width: 0; text-align: center; font-size: var(--fs-8); font-weight: 800;
  letter-spacing: -.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mpk-acts { flex: none; display: flex; align-items: center; gap: var(--sp-sm); }
.mpk-done {
  min-height: var(--ctl-h-sm); padding: 0 var(--sp-xl); border: 0; border-radius: var(--r-pill);
  background: var(--grad-brand); color: #fff; box-shadow: var(--sh-brand);
  font-size: var(--fs-4); font-weight: 700;
  transition: transform var(--dur-1) var(--ease), opacity var(--dur-2) var(--ease);
}
.mpk-done:active { transform: scale(.97); }
.mpk-done.is-off { opacity: .4; pointer-events: none; }

.mpk-tabs {
  flex: none; display: flex; gap: 6px; padding: var(--sp-xs) var(--mpk-side) var(--sp-sm);
  overflow-x: auto; scrollbar-width: none;
}
.mpk-tabs::-webkit-scrollbar { display: none; }
/* 胶囊盒模型与 .m-ftab / .pc-cat 同一套（27px / 4px 10px / 12.5px / --r-pill / --sh-1）：
   派总 T17③ 定的「同一种交互菜单一种手感」，新入口不许自己长一个样。 */
.mpk-tab {
  position: relative; flex: 1; min-width: 0;
  min-height: 27px; padding: 4px 10px; border: 0; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--ink-2);
  font-size: 12.5px; font-weight: 700; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; box-shadow: var(--sh-1);
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.mpk-tab::after { content: ""; position: absolute; left: -2px; right: -2px; top: -7px; bottom: -7px; }
.mpk-tab.is-on { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }

/* T67①：note 那一行现在是「一句话 + 一颗再试一次」，两轴都得给宽度 */
.mpk-note {
  flex: none; display: flex; align-items: center; gap: var(--sp-sm);
  margin: 0; padding: var(--sp-md) var(--mpk-side);
  background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-4); line-height: 1.45;
}
.mpk-note-t { flex: 1; min-width: 0; }
.mpk-retry {
  flex: none; display: inline-flex; align-items: center; gap: var(--sp-2xs);
  min-height: var(--ctl-h-sm); padding: 0 var(--sp-md); border: 0; border-radius: var(--r-pill);
  background: var(--surface); color: var(--brand); font-size: var(--fs-4); font-weight: 700;
}
.mpk-body {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: var(--sp-sm) var(--sp-sm) 0;
}
.mpk-grid {
  display: grid; gap: var(--sp-2xs);
  grid-template-columns: repeat(auto-fill, minmax(var(--mpk-cell), 1fr));
}
.mpk-cell {
  position: relative; aspect-ratio: 1; overflow: hidden;
  border-radius: var(--r-xs); background: var(--surface-2);
}
.mpk-cell img { display: block; width: 100%; height: 100%; object-fit: cover; }
.mpk-cell.is-on img { opacity: .45; }
.mpk-cell.is-broken { display: flex; align-items: center; justify-content: center; }
.mpk-broken { padding: 0 var(--sp-sm); color: var(--ink-3); font-size: var(--fs-2); text-align: center; }
/* 右上角小圆圈：本体 22px，热区靠 ::after 撑到 44px（T50 的触控地板） */
.mpk-check {
  position: absolute; top: var(--sp-2xs); right: var(--sp-2xs);
  width: 22px; height: 22px; padding: 0; border: 2px solid var(--mpk-ring);
  border-radius: var(--r-pill); background: var(--mpk-veil); color: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.mpk-check::after { content: ""; position: absolute; inset: -11px; }
.mpk-cell.is-on .mpk-check { background: var(--brand); border-color: var(--brand); }
.mpk-seq { font-size: var(--fs-2); font-weight: 800; line-height: 1; }
.mpk-badge, .mpk-ts {
  position: absolute; bottom: var(--sp-2xs); display: inline-flex; align-items: center; gap: 2px;
  padding: 1px var(--sp-2xs); border-radius: var(--r-xs);
  background: var(--mpk-veil); color: #fff; font-size: var(--fs-2); line-height: 1.3;
}
.mpk-badge { left: var(--sp-2xs); }
.mpk-ts { right: var(--sp-2xs); }
.mpk-badge .ic { width: 12px; height: 12px; }
.mpk-more {
  display: block; width: calc(100% - var(--sp-xl)); margin: var(--sp-md) auto;
  min-height: var(--ctl-h-sm); border: 0; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-4); font-weight: 700;
}
/* T67①：空态是「一句话 + 唯一那颗主行动钮」，竖排居中；`<p>` 的默认下边距会把钮顶歪 */
.mpk-empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-md);
  padding: var(--sp-4xl) var(--sp-2xl); text-align: center;
  color: var(--ink-3); font-size: var(--fs-5);
}
.mpk-empty-t { margin: 0; }
.mpk-foot {
  flex: none; display: flex; align-items: center; gap: var(--sp-md);
  padding: var(--sp-md) var(--mpk-side); border-top: 1px solid var(--line); background: var(--surface);
}
.mpk-hint { flex: 1; min-width: 0; font-size: var(--fs-4); color: var(--ink-2); }
.mpk-imp {
  flex: none; display: inline-flex; align-items: center; gap: var(--sp-2xs);
  min-height: var(--ctl-h-sm); padding: 0 var(--sp-lg); border: 0; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink); font-size: var(--fs-4); font-weight: 700;
}

/* ---------- 2 · 宫格点图本体的全屏预览 .mpv ---------- */
.mpv {
  position: fixed; inset: 0; z-index: calc(var(--z-lightbox) + 1);
  background: var(--scrim-media);
  --mpv-fg: #fff; --mpv-plate: rgba(255, 255, 255, .14); --mpv-side: var(--sp-xl);
}
.mpv-stage {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: var(--sp-4xl) var(--sp-sm); touch-action: none;
}
.mpv-stage img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* 预览里那条视频（T66② 宫格点本体）：尺寸跟着图片那一套走，
   ⚠️ 必须自己写 display:none —— 父级是 flex，UA 的 [hidden] 规则会被布局要求盖过去，
   只挂 hidden 不写这条，「藏起来的那条」照样占一格（同一族坑见 details 里的 abspos，铁律 11）。 */
.mpv-stage video { max-width: 100%; max-height: 100%; object-fit: contain; background: #000; border-radius: var(--r-sm); }
.mpv-stage [hidden] { display: none; }
.mpv-x, .mpv-prev, .mpv-next {
  position: absolute; width: var(--ctl-h); height: var(--ctl-h); border: 0;
  border-radius: var(--r-pill); background: var(--mpv-plate); color: var(--mpv-fg);
  display: flex; align-items: center; justify-content: center;
}
.mpv-x { top: calc(var(--safe-t) + var(--sp-md)); right: var(--mpv-side); }
.mpv-prev, .mpv-next { top: 50%; margin-top: calc(var(--ctl-h) / -2); }
.mpv-prev { left: var(--sp-sm); }
.mpv-next { right: var(--sp-sm); }
.mpv-count {
  position: absolute; top: calc(var(--safe-t) + var(--sp-lg)); left: var(--mpv-side);
  color: var(--mpv-fg); font-size: var(--fs-5); font-weight: 700;
}
.mpv-check {
  position: absolute; right: var(--mpv-side); bottom: calc(var(--safe-b) + var(--sp-2xl));
  width: 34px; height: 34px; padding: 0; border: 2px solid var(--mpv-fg);
  border-radius: var(--r-pill); background: transparent; color: var(--mpv-fg);
  display: flex; align-items: center; justify-content: center;
  transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.mpv-check b { font-size: var(--fs-4); font-weight: 800; line-height: 1; }
.mpv.is-on .mpv-check { background: var(--brand); border-color: var(--brand); }

/* ---------- 3 · 自绘取景器 .mcv（从选择器里打开，所以压在它上面） ---------- */
.mcv {
  position: fixed; inset: 0; z-index: calc(var(--z-lightbox) + 2);
  background: #000; color: #fff;
  --mcv-plate: rgba(255, 255, 255, .16); --mcv-line: rgba(255, 255, 255, .28);
  --mcv-shutter: 66px; --mcv-side: var(--sp-xl);
}
.mcv-view { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000; }
.mcv-view.is-mirror { transform: scaleX(-1); }
/* 拍完那一张：成图是 JPEG，只有 `<img>` 解得开（video 里塞 JPEG = 一片黑 + MediaError，
   探针实测过），所以盖在同一层位置，靠 `hidden` 属性收放；contain 不裁边，
   用户回看到的就是最终存出去的那一整张。 */
.mcv-shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: #000; }
.mcv-lines {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, transparent calc(33.333% - .5px), var(--mcv-line) 33.333%, transparent calc(33.333% + .5px)),
    linear-gradient(to right, transparent calc(66.666% - .5px), var(--mcv-line) 66.666%, transparent calc(66.666% + .5px)),
    linear-gradient(to bottom, transparent calc(33.333% - .5px), var(--mcv-line) 33.333%, transparent calc(33.333% + .5px)),
    linear-gradient(to bottom, transparent calc(66.666% - .5px), var(--mcv-line) 66.666%, transparent calc(66.666% + .5px));
}
.mcv-top {
  position: absolute; left: 0; right: 0; top: calc(var(--safe-t) + var(--sp-sm));
  display: flex; align-items: center; justify-content: space-between; padding: 0 var(--mcv-side);
}
.mcv-title { font-size: var(--fs-7); font-weight: 800; }
.mcv-x, .mcv-grid-btn {
  width: var(--ctl-h); height: var(--ctl-h); border: 0; border-radius: var(--r-pill);
  background: var(--mcv-plate); color: #fff;
  display: flex; align-items: center; justify-content: center;
}
.mcv-err {
  position: absolute; left: var(--mcv-side); right: var(--mcv-side); top: 34%; margin: 0;
  padding: var(--sp-md) var(--sp-lg); border-radius: var(--r-sm);
  background: var(--mcv-plate); color: #fff; font-size: var(--fs-4); line-height: 1.5; text-align: center;
}
.mcv-foot {
  position: absolute; left: 0; right: 0; bottom: calc(var(--safe-b) + var(--sp-2xl));
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2xl);
}
.mcv-shutter {
  width: var(--mcv-shutter); height: var(--mcv-shutter); padding: 0;
  border: 3px solid #fff; border-radius: var(--r-pill); background: rgba(255, 255, 255, .35);
  transition: transform var(--dur-1) var(--ease), background var(--dur-2) var(--ease);
}
.mcv-shutter:active { transform: scale(.93); background: #fff; }
.mcv-act {
  min-width: var(--ctl-h); min-height: var(--ctl-h); padding: 0 var(--sp-lg);
  border: 0; border-radius: var(--r-pill); background: var(--mcv-plate); color: #fff;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2xs);
  font-size: var(--fs-4); font-weight: 700;
}

/* ---------- 4 · 图片编辑器 .med ---------- */
.med {
  position: fixed; inset: 0; z-index: calc(var(--z-lightbox) + 3);
  display: flex; flex-direction: column;
  --med-bg: #0e1013; --med-fg: #fff; --med-dim: rgba(255, 255, 255, .55);
  --med-plate: rgba(255, 255, 255, .12); --med-mask: rgba(0, 0, 0, .62);
  --med-side: var(--sp-xl);
  background: var(--med-bg); color: var(--med-fg); padding-top: var(--safe-t);
}
/* ⚠️ 退场必须写在进场后面：两者特异性相同，靠源顺序定胜负（T62 同一批的规矩）。 */
.med:not([hidden]) { animation: ymwOverlayIn var(--dur-3) var(--ease-out); }
.med.is-closing { animation: ymwOverlayOut var(--dur-2) var(--ease-in-out) forwards; }

.med-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.med-vstage {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  overflow: hidden; padding: var(--sp-2xl) var(--sp-sm); touch-action: none;
}
.med-vimg { max-width: 100%; max-height: 100%; object-fit: contain; }
.med-vcount { padding: var(--sp-sm) 0; text-align: center; color: var(--med-dim); font-size: var(--fs-4); }
.med-bar {
  flex: none; display: flex; align-items: center; justify-content: center; gap: var(--sp-2xl);
  padding: var(--sp-md) var(--med-side) calc(var(--sp-md) + var(--safe-b));
}
.med-edit { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.med-top {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-md); padding: var(--sp-sm) var(--med-side);
}
.med-top-acts { display: flex; align-items: center; gap: var(--sp-sm); }
.med-btn {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; min-width: var(--ctl-h-sm); min-height: var(--ctl-h-sm); padding: 0 var(--sp-sm);
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--med-fg);
  font-size: var(--fs-2); line-height: 1.2; white-space: nowrap;
  transition: background var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease),
    transform var(--dur-1) var(--ease);
}
.med-btn:active { transform: scale(.96); }
.med-btn.is-on { background: var(--med-plate); }
.med-btn.is-off { opacity: .3; pointer-events: none; }
.med-btn.is-go {
  flex-direction: row; min-height: var(--ctl-h-sm); padding: 0 var(--sp-xl);
  border-radius: var(--r-pill); background: var(--grad-brand); color: #fff;
  font-size: var(--fs-4); font-weight: 700;
}
.med-btn .ic { width: 18px; height: 18px; }
.med-flip { transform: scaleX(-1); }

.med-stage {
  position: relative; flex: 1; min-height: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center; touch-action: none;
}
/* 两只画布同尺寸同位置：base 只画几何（滤镜挂 CSS filter 做实时预览），
   over 只画叠加层（不吃滤镜，否则把用户写的字一起染色）。inset:0 + margin:auto
   让画布按自身比例居中，letterbox 的那圈空由 canvasRect() 量出来补偿。 */
.med-base, .med-over { position: absolute; inset: 0; margin: auto; max-width: 100%; max-height: 100%; }
.med-over { pointer-events: none; }
.med-crop {
  position: absolute; box-sizing: border-box; border: 1.5px solid var(--med-fg);
  box-shadow: 0 0 0 9999px var(--med-mask);
}
.med-crop-grid {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, transparent calc(33.333% - .5px), var(--med-dim) 33.333%, transparent calc(33.333% + .5px)),
    linear-gradient(to right, transparent calc(66.666% - .5px), var(--med-dim) 66.666%, transparent calc(66.666% + .5px)),
    linear-gradient(to bottom, transparent calc(33.333% - .5px), var(--med-dim) 33.333%, transparent calc(33.333% + .5px)),
    linear-gradient(to bottom, transparent calc(66.666% - .5px), var(--med-dim) 66.666%, transparent calc(66.666% + .5px));
}
.med-crop-h { position: absolute; width: 26px; height: 26px; touch-action: none; border: 0; background: transparent; }
.med-crop-h.is-tl { left: -13px; top: -13px; }
.med-crop-h.is-tr { right: -13px; top: -13px; }
.med-crop-h.is-bl { left: -13px; bottom: -13px; }
.med-crop-h.is-br { right: -13px; bottom: -13px; }
.med-crop-h::after {
  content: ""; position: absolute; inset: 8px;
  border: 2px solid var(--med-fg); border-radius: 3px;
}

.med-panel {
  flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-sm);
  padding: var(--sp-md) var(--med-side); max-height: 34vh; overflow-y: auto;
}
.med-panel-hint { width: 100%; color: var(--med-dim); font-size: var(--fs-3); }
.med-chip {
  min-height: var(--ctl-h-sm); padding: 0 var(--sp-lg); border: 0; border-radius: var(--r-pill);
  background: var(--med-plate); color: var(--med-fg); font-size: var(--fs-4); font-weight: 700;
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.med-chip.is-on { background: var(--brand); color: #fff; }
.med-chip.is-go { background: var(--grad-brand); color: #fff; }
.med-slide { display: flex; align-items: center; gap: var(--sp-sm); flex: 1 1 160px; min-width: 0; }
.med-slide-t { flex: none; width: 6.5em; color: var(--med-dim); font-size: var(--fs-3); }
.med-slide-i { flex: 1; min-width: 0; height: 26px; accent-color: var(--brand); }
.med-colors { display: flex; gap: var(--sp-xs); flex: 1 1 100%; }
.med-sw {
  position: relative; width: 26px; height: 26px; padding: 0;
  border: 2px solid transparent; border-radius: var(--r-pill);
}
.med-sw::after { content: ""; position: absolute; inset: -9px; }
.med-sw.is-on { border-color: var(--brand); }
.med-text-in {
  flex: 1 1 100%; min-width: 0; min-height: var(--ctl-h-sm); padding: 0 var(--sp-lg);
  border: 0; border-radius: var(--r-pill); background: var(--med-plate); color: var(--med-fg);
  font-size: var(--fs-5);
}
.med-text-in::placeholder { color: var(--med-dim); }
/* T67④（派总 2026-11-09 第 4 条）：贴纸从「一排 emoji」换成 20 颗自绘徽标。
   预览是 canvas（和落图同一个绘制函数），所以格子按 canvas 的宽高比给，
   热区仍要 ≥44px —— emoji 那版 38px 的钮本来就在触控地板以下。 */
.med-stks {
  display: flex; gap: var(--sp-2xs); flex: 1 1 100%;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  padding-bottom: var(--sp-2xs);
}
.med-stks::-webkit-scrollbar { display: none; }
.med-stk {
  flex: none; width: 84px; min-height: 52px; padding: var(--sp-2xs) 0;
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--med-fg);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2xs);
}
.med-stk.is-on { background: var(--med-plate); box-shadow: inset 0 0 0 1.5px var(--brand); }
.med-stk-c { width: 78px; height: 33px; display: block; }
.med-stk-n { font-size: var(--fs-2); line-height: 1; color: var(--med-dim); }
.med-stk-edit { flex: 1 1 100%; display: flex; gap: var(--sp-2xs); }
.med-stk-in {
  flex: 1; min-width: 0; min-height: var(--ctl-h-sm); padding: 0 var(--sp-lg);
  border: 0; border-radius: var(--r-pill); background: var(--med-plate); color: var(--med-fg);
  font-size: var(--fs-5);
}
.med-stk-in::placeholder { color: var(--med-dim); }
.med-tools {
  flex: none; display: flex; gap: var(--sp-xs); overflow-x: auto; scrollbar-width: none;
  padding: var(--sp-sm) var(--med-side) calc(var(--sp-sm) + var(--safe-b));
  border-top: 1px solid var(--med-plate);
}
.med-tools::-webkit-scrollbar { display: none; }
.med-tools .med-btn { flex: none; }

/* ---------- 5 · 进出场（选择器 / 预览 / 取景器 / 编辑器） ---------- */
@keyframes ymwOverlayIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes ymwOverlayOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes mpkUp { from { transform: translateY(100%); } to { transform: none; } }
@keyframes mpkDown { from { transform: none; } to { transform: translateY(100%); } }

.mpk:not([hidden]) { animation: mpkUp var(--dur-4) var(--ease); }
.mpk.is-closing { animation: mpkDown var(--dur-2) var(--ease-in-out) forwards; }
.mpv:not([hidden]) { animation: ymwOverlayIn var(--dur-3) var(--ease-out); }
.mpv.is-closing { animation: ymwOverlayOut var(--dur-2) var(--ease-in-out) forwards; }
.mcv:not([hidden]) { animation: ymwOverlayIn var(--dur-3) var(--ease-out); }
.mcv.is-closing { animation: ymwOverlayOut var(--dur-2) var(--ease-in-out) forwards; }

/* 减少动态：动画关掉，开合照常（app.js 的 reduceMotion() 已经把等待收成 0） */
@media (prefers-reduced-motion: reduce) {
  .mpk, .mpv, .mcv, .med,
  .mpk.is-closing, .mpv.is-closing, .mcv.is-closing, .med.is-closing {
    animation: none !important;
  }
}
