/* ===========================================================
   云帆圈子 · 设计系统 v2
   深墨蓝品牌色 + 暖白纸感内容层 + 金线官方标识
   一套代码同时适配 手机 / 平板 / 电脑
   =========================================================== */

:root {
  /* 品牌 */
  --navy-900: #08152C;
  --navy-800: #0B1E3C;
  --navy-700: #10305F;
  --navy-600: #17457F;
  --brand: #0A5AA8;          /* 取自 logo 主色 */
  --brand-600: #0B63B8;
  --brand-ink: #083E77;
  --brand-050: #EAF2FB;
  --gold: #C8A15A;
  --gold-300: #E6C98C;
  --gold-050: #FBF5E9;

  /* 中性 */
  --paper: #F7F6F3;
  --surface: #FFFFFF;
  --surface-2: #F1EFEA;
  --line: #ECE9E2;
  --hair: #E4E0D7;
  --ink: #16191F;
  --ink-2: #454C55;
  --ink-3: #767E88;
  --faint: #A6ADB6;

  --ok: #1F8A5B;
  --warn: #B5761A;
  --danger: #B4362F;

  --r-xs: 9px;
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 20px;
  --r-xl: 26px;

  --sh-1: 0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .04);
  --sh-2: 0 2px 8px rgba(16, 24, 40, .06), 0 8px 24px rgba(16, 24, 40, .05);
  --sh-3: 0 18px 48px rgba(8, 21, 44, .16);

  --font: -apple-system, BlinkMacSystemFont, "SF Pro SC", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --mono: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; }
/* 🚨 这一行治「点击左栏菜单时页面左右抖动」（第 65 轮 · 2026-09-28 帆哥报的）。
   抖动的链条：切页时中间列被换成 26px 的 .spin 转圈 → 文档高度从 3000+ 塌到
   恰好等于一屏 → **竖直滚动条消失** → 视口宽多出 15px → `.shell`（margin:0 auto
   居中）整体右移 7.5px；新内容回来 → 滚动条重现 → 整体左移 7.5px。
   一来一回就是肉眼看到的「抖一下」，而且每个菜单项都会发生。
   scrollbar-gutter: stable = 让浏览器**永久预留**滚动条那条槽，不管此刻有没有
   滚动条，可用宽度都恒定 → 居中容器永不横移。实测（有头 Chrome 1512×880）：
   修复前每次切页 cw/shell/左栏/内容列 各变 2 次；修复后四个值全程恒定。
   ⚠️ overlay 滚动条的平台（iOS/部分 macOS）本来就不占位，这条对它们无副作用。
   ⚠️ 兼容兜底在下面 @media(min-width:900px) 的 .col-nav 上，别删那一条。 */
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
body {
  font-family: var(--font);
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.6;
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
img { max-width: 100%; display: block; }
svg { display: block; width: 1em; height: 1em; }
input, textarea, select { font-family: inherit; font-size: 15px; }
::selection { background: var(--brand-050); }

/* --------------------------- 基础原子 --------------------------- */
.row { display: flex; align-items: center; gap: 10px; }
.spacer { flex: 1; }
.muted { color: var(--ink-3); }
.small { font-size: 13.5px; }
.tiny { font-size: 12px; }
.nowrap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-1);
}
.section-head { display: flex; align-items: center; gap: 10px; margin: 0 0 12px; }
.section-head h2 { font-size: 17px; font-weight: 700; margin: 0; letter-spacing: .01em; }
.empty { text-align: center; color: var(--ink-3); padding: 44px 20px; font-size: 14px; }
.em-ico { font-size: 30px; margin-bottom: 10px; opacity: .55; }
.spin {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2.5px solid var(--line); border-top-color: var(--brand);
  animation: spin .7s linear infinite; margin: 80px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------- 按钮 --------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 40px; padding: 0 17px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface); color: var(--ink);
  font-size: 14px; font-weight: 600; letter-spacing: .01em;
  transition: .16s; white-space: nowrap;
}
.btn:hover { border-color: #D4CFC3; background: #FCFBF9; }
.btn:active { transform: translateY(1px); }
.btn svg { width: 16px; height: 16px; }
.btn-primary {
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  border-color: transparent; color: #fff;
  box-shadow: 0 1px 2px rgba(10, 90, 168, .3), 0 6px 18px rgba(10, 90, 168, .22);
}
.btn-primary:hover { background: linear-gradient(180deg, #0B6BC6, #0A5DAE); }
.btn-sm { height: 33px; padding: 0 12px; font-size: 13px; border-radius: 9px; }
.btn-danger { color: var(--danger); border-color: #EED9D6; }
.btn-danger:hover { background: #FCF3F2; border-color: #E4C4C1; }
.btn-block { width: 100%; }

/* ---- 发布页底部按钮行（2026-09-21 第三轮）----
   帆哥：「底部四个按钮，第四个换行了，缩小一下，确保在同一行」。
   原来按钮、一个 spacer、「发布后所有人都能看到」挤在同一个 flex 行里，
   窄屏放不下就把「取消」挤到了第二行。现在拆成「按钮组 + 提示」两块，
   手机端按钮组等分成一行（见下方 620px 媒体查询）。 */
.cp-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cp-foot-btns { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cp-foot-hint { margin-left: auto; }

/* --------------------------- 表单 --------------------------- */
.field { margin-bottom: 16px; }
.field > label { display: block; font-size: 13px; font-weight: 600; color: var(--ink-2); margin-bottom: 7px; }
.field.hint { font-size: 12.5px; color: var(--ink-3); margin-top: -8px; }
.input, .select, .textarea {
  width: 100%; height: 42px; padding: 0 13px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface); color: var(--ink); outline: none;
  transition: .16s;
}
.textarea { height: auto; min-height: 130px; padding: 12px 13px; line-height: 1.65; resize: vertical; }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand); box-shadow: 0 0 0 3.5px rgba(10, 90, 168, .12);
}
.select {
  appearance: none; padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23767E88' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; background-size: 17px;
}

/* 发帖页自定义板块选择器（2026-09-21 帆哥：不要原生 select 弹窗，要在当前页面下滑出选项） */
.cp-board-select { position: relative; }
.cp-board-bar {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 42px; padding: 0 13px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface); cursor: pointer;
  transition: .16s;
}
.cp-board-bar:hover { border-color: var(--brand-400); }
.cp-board-bar:active { background: var(--surface-2); }
.cp-board-placeholder { color: var(--ink-3); font-size: 14px; }
.cp-board-name { color: var(--ink); font-size: 14px; font-weight: 600; }
.cp-board-arrow {
  flex: none; width: 20px; height: 20px;
  display: grid; place-items: center;
  color: var(--ink-3); font-size: 11px;
  transition: transform .18s;
}
.cp-board-options {
  margin-top: 6px; padding: 6px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface);
  box-shadow: 0 8px 28px rgba(8, 21, 44, .10);
  max-height: 260px; overflow-y: auto;
  animation: cpBoardDown .18s ease;
}
.cp-board-options[hidden] { display: none; }
@keyframes cpBoardDown { from { opacity: .6; transform: translateY(-6px); } }
.cp-board-option {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 9px;
  cursor: pointer; transition: .14s;
}
.cp-board-option:hover { background: var(--surface-2); }
.cp-board-option.on { background: var(--brand-050); color: var(--brand-700); }
.cp-board-option .cp-board-name { font-weight: 500; }
.cp-board-option.on .cp-board-name { font-weight: 700; }
.cp-board-tag {
  margin-left: auto;
  height: 20px; padding: 0 7px; border-radius: 5px;
  font-size: 11px; font-weight: 600;
  background: var(--gold-050); color: #8A6415;
}
.cp-board-select.shake { animation: shake .4s ease; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-5px); }
  40%, 80% { transform: translateX(5px); }
}

/* --------------------------- 标签 / 芯片 --------------------------- */
.tag {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px; padding: 0 8px; border-radius: 6px;
  font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
  background: var(--surface-2); color: var(--ink-3);
}
.tag.top { background: var(--navy-800); color: #fff; }
.tag.essence { background: var(--gold-050); color: #8A6415; box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .4); }
.tag.ok { background: #E9F6EF; color: var(--ok); }
.tag.warn { background: #FDF3E3; color: var(--warn); }
.tag.gray { background: var(--surface-2); color: var(--ink-3); }
.tag.blue { background: var(--brand-050); color: var(--brand-ink); }

.chip {
  display: inline-flex; align-items: center;
  height: 33px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--hair); background: var(--surface);
  font-size: 13.5px; font-weight: 550; color: var(--ink-2);
  white-space: nowrap; transition: .15s; cursor: pointer;
}
.chip:hover { border-color: #D4CFC3; }
.chip.on {
  background: linear-gradient(180deg, var(--navy-700), var(--navy-800));
  border-color: transparent; color: #fff;
  box-shadow: 0 4px 14px rgba(11, 30, 60, .25);
}
.chips-scroll { display: flex; gap: 7px; overflow-x: auto; padding-bottom: 4px; -webkit-overflow-scrolling: touch; }
.chips-scroll::-webkit-scrollbar { display: none; }

/* --------------------------- 头像 --------------------------- */
.avatar {
  flex: none; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center;
  background: linear-gradient(150deg, #E8EDF4, #D7DEE8);
  color: var(--brand-ink); font-weight: 700;
  user-select: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.s20 { width: 20px; height: 20px; font-size: 10px; }
.avatar.s24 { width: 24px; height: 24px; font-size: 11px; }
.avatar.s28 { width: 28px; height: 28px; font-size: 12px; }
.avatar.s30 { width: 30px; height: 30px; font-size: 12px; }
.avatar.s32 { width: 32px; height: 32px; font-size: 13px; }
.avatar.s36 { width: 36px; height: 36px; font-size: 14px; }
.avatar.s40 { width: 40px; height: 40px; font-size: 15px; }
.avatar.s44 { width: 44px; height: 44px; font-size: 16px; }
.avatar.s48 { width: 48px; height: 48px; font-size: 18px; }
.avatar.s64 { width: 64px; height: 64px; font-size: 24px; }
.avatar.s72 { width: 72px; height: 72px; font-size: 26px; }
.avatar.s96 { width: 96px; height: 96px; font-size: 34px; }
.avatar.official {
  background: linear-gradient(150deg, var(--navy-700), var(--navy-900));
  color: var(--gold-300); box-shadow: inset 0 0 0 1.5px rgba(200, 161, 90, .55);
}

/* --------------------------- 等级 --------------------------- */
.lv-badge {
  display: inline-flex; align-items: center;
  height: 20px; padding: 0 7px; border-radius: 5px;
  font-size: 11px; font-weight: 700; letter-spacing: .02em;
  background: var(--surface-2); color: var(--ink-3);
}
.lv-badge.l1 { background: #EEF1F5; color: #6C7683; }
.lv-badge.l2 { background: #E9F2ED; color: #2C7A58; }
.lv-badge.l3 { background: #E8F2FA; color: #1D6A9E; }
.lv-badge.l4 { background: #EAF0FB; color: #2A56A8; }
.lv-badge.l5 { background: #F0EDFB; color: #5533A6; }
.lv-badge.l6 { background: #FBEFE9; color: #A5502A; }
.lv-badge.l7 { background: var(--gold-050); color: #8A6415; }
.lv-badge.l8 { background: linear-gradient(90deg, #FBF0D8, #F4E0B4); color: #7A5310; }

/* --------------------------- 顶栏（手机） --------------------------- */
.topbar {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: 10px;
  height: 56px; padding: 0 16px;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid var(--line);
}
.topbar.navy {
  background: linear-gradient(158deg, var(--navy-700) 0%, var(--navy-800) 55%, var(--navy-900) 100%);
  border-bottom: none; color: #fff;
  box-shadow: 0 6px 22px rgba(8, 21, 44, .22);
}
.tb-title { font-size: 16.5px; font-weight: 700; letter-spacing: .01em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-btn {
  position: relative; flex: none;
  width: 36px; height: 36px; border-radius: 11px;
  display: grid; place-items: center;
  border: none; background: transparent; color: inherit;
}
.tb-btn:hover { background: rgba(128, 140, 160, .14); }
.tb-btn svg { width: 20px; height: 20px; }
.tb-btn .tbadge {
  position: absolute; top: 4px; right: 2px;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  background: #E0473C; color: #fff; font-size: 10px; font-weight: 700;
  display: grid; place-items: center;
}
.brand-logo { width: 28px; height: 28px; flex: none; }
.brand-logo img { width: 100%; height: 100%; object-fit: contain; }

/* --------------------------- 容器 --------------------------- */
.shell { display: block; }
.col-nav { display: none; }
.col-main { padding: 16px 14px 96px; }

/* --------------------------- 侧边导航（PC） --------------------------- */
.brand { display: flex; align-items: center; gap: 11px; padding: 4px 8px 20px; }
.brand-mark {
  width: 38px; height: 38px; border-radius: 12px; flex: none;
  background: linear-gradient(150deg, var(--navy-700), var(--navy-900));
  display: grid; place-items: center; overflow: hidden;
  box-shadow: 0 4px 14px rgba(8, 21, 44, .3);
}
.brand-mark img { width: 72%; height: 72%; object-fit: contain; }
.brand-name { font-size: 16px; font-weight: 800; letter-spacing: .02em; }
.brand-sub { font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.nav-group { margin-bottom: 18px; }
.nav-label {
  font-size: 11px; font-weight: 700; letter-spacing: .12em;
  color: var(--faint); padding: 0 10px 8px; text-transform: uppercase;
}
.nav-item {
  display: flex; align-items: center; gap: 11px;
  height: 42px; padding: 0 11px; border-radius: 11px;
  font-size: 14.5px; font-weight: 550; color: var(--ink-2);
  cursor: pointer; transition: .15s;
}
.nav-item .ico { width: 20px; height: 20px; flex: none; opacity: .8; }
.nav-item .ico svg { width: 20px; height: 20px; }
.nav-item:hover { background: rgba(16, 48, 95, .06); color: var(--ink); }
.nav-item.active {
  background: linear-gradient(180deg, var(--navy-700), var(--navy-800));
  color: #fff; box-shadow: 0 6px 18px rgba(11, 30, 60, .22);
}
.nav-item.active .ico { opacity: 1; }
.nav-badge {
  margin-left: auto; min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: 10px; background: #E0473C; color: #fff;
  font-size: 11px; font-weight: 700; display: grid; place-items: center;
}
.nav-item.active .nav-badge { background: rgba(255, 255, 255, .28); }
.nav-cta {
  width: 100%; height: 44px; margin-bottom: 20px;
  border: none; border-radius: 12px;
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  color: #fff; font-size: 14.5px; font-weight: 650;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  box-shadow: 0 8px 22px rgba(10, 90, 168, .3);
  transition: .16s;
}
.nav-cta svg { width: 17px; height: 17px; }
.nav-cta:hover { transform: translateY(-1px); box-shadow: 0 10px 26px rgba(10, 90, 168, .36); }

/* --------------------------- 右栏 --------------------------- */
.side-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 16px 17px; margin-bottom: 14px;
  box-shadow: var(--sh-1);
}
.side-card h4 {
  margin: 0 0 12px; font-size: 13px; font-weight: 700; color: var(--ink-3);
  letter-spacing: .06em; display: flex; align-items: center; gap: 7px;
}
.side-card h4 svg { width: 15px; height: 15px; }
.profile-card {
  display: flex; align-items: center; gap: 12px;
  padding: 15px 16px; margin-bottom: 14px; cursor: pointer;
  border-radius: var(--r-md);
  background: linear-gradient(150deg, var(--navy-700), var(--navy-900));
  color: #fff; box-shadow: var(--sh-2); position: relative; overflow: hidden;
}
.profile-card::after {
  content: ''; position: absolute; right: -50px; top: -60px;
  width: 160px; height: 160px; border-radius: 50%;
  background: radial-gradient(circle, rgba(200, 161, 90, .28), transparent 65%);
}
.profile-card .avatar { box-shadow: 0 0 0 2px rgba(255, 255, 255, .18); }
.pc-name { font-size: 15px; font-weight: 700; }
.pc-meta { font-size: 11.5px; color: rgba(255, 255, 255, .62); }
.pc-lv { margin-left: auto; text-align: right; font-size: 11px; color: rgba(255, 255, 255, .65); }
.pc-lv b { display: block; font-size: 17px; color: var(--gold-300); font-variant-numeric: tabular-nums; }

/* ------- 左栏内的个人信息卡 / 侧卡（2026-09-20 从「右侧栏」移进来）-------
   栏宽只有 236px（可用约 220px），照原样把「110 积分」摆在右边，会把
   「KA事业部 · CEO」挤成两行甚至溢出 —— 这里缩一版：头像 40、积分换行右对齐。 */
.col-nav .profile-card { padding: 13px 14px; gap: 11px; margin: 10px 0 14px; flex-wrap: wrap; }
.col-nav .profile-card .avatar { width: 40px; height: 40px; font-size: 15px; }
.col-nav .pc-name { font-size: 14.5px; }
.col-nav .pc-meta { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.col-nav .pc-lv { flex-basis: 100%; margin: 2px 0 0; text-align: right; font-size: 10.5px; }
.col-nav .pc-lv b { display: inline; font-size: 14px; margin-right: 3px; }
.col-nav .nav-side-card { padding: 14px 15px; }
.col-nav .nav-side-card h4 { margin-bottom: 8px; }
.col-nav .rank-row { padding: 7px 0; }

/* --------------------------- 底部导航（手机） ---------------------------
   2026-09-24 帆哥选定「A · 悬浮胶囊」改版：
   脱离屏幕底边的悬浮岛（左右 12px、离底 14px + 安全区），大投影 + 毛玻璃，
   选中项垫淡蓝胶囊。⚠️ 几何一变，全站写死「58px」的贴底元素都要跟着抬：
   评论输入条 / 返回顶部 / 详情页操作条（各自已同步改 76px），
   app.js 里用户头像弹层的 TABBAR 常量也同步改 82。 */
.tabbar {
  position: fixed; left: 12px; right: 12px;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px)); z-index: 70;
  display: flex; align-items: stretch;
  height: 62px;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(180%) blur(20px);
  border: 1px solid rgba(255, 255, 255, .65);
  border-radius: 21px;
  box-shadow: 0 12px 34px rgba(8, 21, 44, .20), 0 2px 6px rgba(8, 21, 44, .08);
  /* 键盘弹出时要收起（见文件末尾「软键盘适配」）——
     用位移 + 淡出而不是 display:none，有了过渡才不闪。 */
  transition: transform .18s ease, opacity .18s ease;
}
.tab {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  border: none; background: transparent; color: var(--ink-3);
  font-size: 11px; font-weight: 600; letter-spacing: .02em;
  position: relative; padding: 0;
}
.tab > svg { width: 22px; height: 22px; }
.tab > span { position: relative; z-index: 1; }   /* 图标/文字浮在选中胶囊垫底之上 */
.tab.active { color: var(--brand); }
.tab.active::before {
  content: ""; position: absolute; inset: 5px 5px 5px;
  background: var(--brand-050); border-radius: 14px; z-index: 0;
}
/* 发布按钮：圆角长方形 → 正圆（2026-09-21 帆哥要求）。
   悬浮版（2026-09-24）：⌀46 + 3px 白描边，向上浮 22px 探出栏外——
   白描边把圆和毛玻璃栏「切」开，凸起感是靠这圈边做出来的。
   颜色不在这里定：默认蓝紫，进了频道页由文件末尾 body[data-bd] 那组换成频道色
   （帆哥点名保留的效果），白描边与投影不受频道色影响。 */
.tab-pub .pub-circle {
  width: 46px; height: 46px; border-radius: 50%;
  margin-top: -22px;
  background: linear-gradient(135deg, var(--brand), var(--violet));
  color: #fff; display: grid; place-items: center;
  border: 3px solid rgba(255, 255, 255, .95);
  box-shadow: 0 8px 20px rgba(74, 91, 240, .40);
}
.tab-pub { gap: 2px; }
.tab-pub .pub-circle svg { width: 19px; height: 19px; }
.tab .tbadge {
  position: absolute; top: 5px; left: 50%; transform: translateX(3px);
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  background: #E0473C; color: #fff; font-size: 10px; font-weight: 700;
  display: grid; place-items: center;
}

/* ===========================================================
   门户首页
   =========================================================== */
.hero {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  background: linear-gradient(158deg, var(--navy-700) 0%, var(--navy-800) 48%, var(--navy-900) 100%);
  color: #fff; padding: 19px 18px 18px;
  box-shadow: 0 14px 40px rgba(8, 21, 44, .28);
  margin-bottom: 16px;
}
.hero::before {
  content: ''; position: absolute; right: -70px; top: -90px;
  width: 260px; height: 260px; border-radius: 50%;
  background: radial-gradient(circle, rgba(200, 161, 90, .3), transparent 62%);
}
.hero::after {
  content: ''; position: absolute; left: -50px; bottom: -110px;
  width: 220px; height: 220px; border-radius: 50%;
  background: radial-gradient(circle, rgba(10, 90, 168, .55), transparent 65%);
}
.hero > * { position: relative; }
/* 顶部 logo 行已撤掉（2026-09-20 改版：不再显示 logo 与站点标题） */
.hero-hello { font-size: 19px; font-weight: 800; line-height: 1.35; margin-bottom: 4px; }
.hero-desc { font-size: 12.5px; color: rgba(255, 255, 255, .72); line-height: 1.72; margin-bottom: 13px; }
.hero-stats { display: flex; margin-top: 13px; border-top: 1px solid rgba(255, 255, 255, .13); padding-top: 11px; }
.hero-stat { flex: 1; min-width: 0; }
.hero-stat b {
  display: block; font-size: 17px; font-weight: 800; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; color: #fff; line-height: 1.2;
}
.hero-stat b.gold { color: var(--gold-300); }
.hero-stat span { font-size: 10px; color: rgba(255, 255, 255, .55); letter-spacing: .04em; }

.hero-search {
  display: flex; align-items: center; gap: 9px;
  height: 40px; padding: 0 13px;
  border-radius: 13px; background: rgba(255, 255, 255, .1);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
}
.hero-search svg { width: 16px; height: 16px; flex: none; color: rgba(255, 255, 255, .6); }
.hero-search input {
  flex: 1; min-width: 0; border: none; background: transparent; outline: none;
  color: #fff; font-size: 13px;
}
.hero-search input::placeholder { color: rgba(255, 255, 255, .48); }

/* 频道：6 个格子 2 列 3 行，整块高度从 419px 压到约 210px（2026-09-20 改版）
   每格 = 左边频道名 + 灰色小字（原有简介），右边一块方形缩略图 */
.channel-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
.ch-cell {
  min-width: 0; display: flex; align-items: center; gap: 10px; cursor: pointer;
  border-radius: 14px; background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--sh-1);
  transition: .18s; padding: 9px 9px;
}
.ch-cell:hover { transform: translateY(-1px); box-shadow: var(--sh-2); border-color: #DED9CE; }
.ch-cell .tx { flex: 1; min-width: 0; overflow: hidden; }
.ch-cell .cn {
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
  font-size: 13px; font-weight: 800; letter-spacing: -.005em;
}
.ch-cell .cn i { width: 5px; height: 13px; border-radius: 3px; background: var(--brand); flex: none; }
/* 板块色统一到下方「唯一事实来源」那一组（原先是另一套纯色，与首页不一致） */
.ch-cell .cn .cnt { font-size: 10.5px; font-weight: 700; color: var(--faint); font-variant-numeric: tabular-nums; }
.ch-cell .cn .cnt .u { display: none; }   /* 窄屏只留数字，宽屏补回「条」 */
.ch-cell .ci {
  font-size: 10.5px; color: var(--ink-3); line-height: 1.5;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ch-cell .ct {
  flex: none; width: 38px; height: 38px; border-radius: 11px; overflow: hidden;
  background: linear-gradient(150deg, var(--brand-050), var(--surface-2));
}
.ch-cell .ct img { width: 100%; height: 100%; object-fit: cover; display: block; }

.official-strip { display: flex; gap: 9px; overflow-x: auto; padding-bottom: 4px; }
.official-strip::-webkit-scrollbar { display: none; }
.off-chip {
  flex: none; display: flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 13px; border-radius: 999px;
  background: linear-gradient(180deg, var(--navy-700), var(--navy-800));
  color: #fff; font-size: 13px; font-weight: 600; white-space: nowrap;
  cursor: pointer;
}
.off-chip b { color: var(--gold-300); font-variant-numeric: tabular-nums; }

.album-strip { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.album-strip::-webkit-scrollbar { display: none; }
.album-year {
  flex: none; width: 74px; padding: 12px 0 11px; text-align: center;
  border-radius: var(--r-sm); background: var(--surface);
  border: 1px solid var(--line); cursor: pointer; transition: .16s;
}
.album-year b { display: block; font-size: 15.5px; font-weight: 800; font-variant-numeric: tabular-nums; }
.album-year span { font-size: 11px; color: var(--ink-3); }
.album-year:hover { border-color: var(--brand); color: var(--brand); }

/* 首页「最新动态」列表项
   左：标题 +（官方徽章）→ 下面跟摘要文字
   右：作者 / 部门 / 日期，竖排右对齐
   右下：方块小图（该帖第一张图） */
.feed-row { display: flex; gap: 12px; padding: 13px 0; cursor: pointer; border-bottom: 1px solid var(--line); }
.feed-row:last-child { border-bottom: none; }
.fr-main { min-width: 0; flex: 1; }

.fr-head { display: flex; align-items: flex-start; gap: 12px; }
.fr-headline { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; }
.fr-headline .off-badge { height: 18px; padding: 0 6px; font-size: 10.5px; flex: none; }
.fr-title {
  min-width: 0; font-size: 14.5px; font-weight: 650; line-height: 1.45; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fr-meta { flex: none; text-align: right; font-size: 11px; line-height: 1.4; color: var(--faint); }
.fr-meta > span { display: block; }
.fr-who { font-weight: 650; color: var(--ink-2); }
/* 部门紧跟发帖人。2026-09-21 帆哥反馈：原来这里的 `margin-left: auto`
   会和 `.fr-sp`（点赞/浏览/时间那组）的 `margin-left: auto` 平分剩余空间，
   于是部门被推到中段，看起来像「居中」了。去掉这个 auto，部门回到名字后面，
   由 .fr-foot 的 gap 留出一个字符的间距。 */
.fr-dept { max-width: 138px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-time { font-variant-numeric: tabular-nums; }

.fr-excerpt { display: flex; align-items: flex-start; gap: 12px; margin-top: 6px; }
.fr-text {
  flex: 1; min-width: 0; font-size: 12.5px; line-height: 1.62; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fr-thumb {
  width: 58px; height: 58px; flex: none; border-radius: 9px; overflow: hidden;
  background: var(--surface-2);
}
.fr-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 手机端：右侧信息区收窄，小图略缩 */
@media (max-width: 560px) {
  .fr-head { gap: 8px; }
  .fr-dept { max-width: 96px; }
  .fr-title { font-size: 14px; }
  .fr-thumb { width: 52px; height: 52px; }
}

/* ===========================================================
   帖子卡片
   =========================================================== */
.post-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 16px 16px 12px;
  margin-bottom: 12px; cursor: pointer; transition: .18s;
  box-shadow: var(--sh-1); position: relative; overflow: hidden;
}
.post-card:hover { box-shadow: var(--sh-2); border-color: #DFDACF; }
.post-card.official { border-left: 3px solid var(--gold); }
.pc-head { display: flex; align-items: center; gap: 11px; margin-bottom: 11px; }
.pc-author { font-size: 14.5px; font-weight: 700; display: flex; align-items: center; gap: 6px; min-width: 0; }
.pc-sub { font-size: 11.5px; color: var(--faint); display: flex; align-items: center; gap: 6px; }
.pc-time { margin-left: auto; display: flex; gap: 5px; align-items: center; flex: none; }
.pc-title { font-size: 16.5px; font-weight: 700; line-height: 1.45; margin: 0 0 7px; }
.pc-body {
  font-size: 14.5px; color: var(--ink-2); line-height: 1.7;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
  white-space: pre-wrap;
}
.pc-imgs { display: grid; gap: 5px; margin-top: 11px; }
.pc-imgs.n1 { grid-template-columns: 1fr; }
.pc-imgs.n2 { grid-template-columns: repeat(2, 1fr); }
.pc-imgs.n3 { grid-template-columns: repeat(3, 1fr); }
.ph { position: relative; overflow: hidden; border-radius: 10px; background: var(--surface-2); aspect-ratio: 4 / 3; }
.pc-imgs.n1 .ph { aspect-ratio: 16 / 10; }
.ph img { width: 100%; height: 100%; object-fit: cover; transition: .3s; }
.post-card:hover .ph img { transform: scale(1.03); }
.ph .ph-more {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(8, 21, 44, .52); color: #fff;
  font-size: 16px; font-weight: 700; backdrop-filter: blur(2px);
}
/* 卡片底部一行（2026-09-21 帆哥要求：改成首页「最新动态」那种排法）
   左：头像 20px + 名字 + 部门（名字和部门之间留一个字符）
   右：板块名 → 点赞 → 评论 → 浏览
   原来左边是三个计数、最右边孤零零一个板块名，牌子像被扔在角落。 */
.pc-foot {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line);
  font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.pc-foot .avatar { flex: none; }
.pc-foot .pc-who { flex: none; font-weight: 650; color: var(--ink-2); }
.pc-foot .pc-who .off-badge { height: 19px; padding: 0 7px; font-size: 11px; }
.pc-foot .pc-dept,
.pc-foot .pc-by { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-foot .pc-by { color: var(--faint); }
.pc-foot .pc-sp {
  margin-left: auto; flex: none;
  display: flex; align-items: center; gap: 11px;
}
.pc-foot .pc-board { color: var(--ink-3); }
.pc-foot .act svg { width: 14px; height: 14px; }

/* 标题行：标题占满（长了就折行），发帖时间贴在整行的最右侧 */
.pc-trow { display: flex; align-items: baseline; gap: 10px; margin: 0 0 7px; }
.pc-trow .pc-title { flex: 1; min-width: 0; margin: 0; }
.pc-when {
  flex: none; margin-left: auto; font-size: 11.5px; color: var(--faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* 题目前导（2026-09-21 第四轮改版）：板块色竖线 + 置顶/精华圆标，整块贴在标题最前。
   为什么是 <h3> 里的行内元素：标题长到折成两三行时，行内元素跟着**第一行**走；
   当兄弟节点只会贴在标题**块**的边上，与文字对不齐。
   vertical-align: middle —— 圆标 17px、竖线 15px，标题行高 24px（桌面）/ 19.9px（手机），
   用默认 baseline 会被它们自己的行盒顶开一条。 */
.pc-lead {
  display: inline-flex; align-items: center; gap: 5px;
  margin-right: 6px; vertical-align: middle;
}
/* 板块色竖线：颜色由 --bd-* 统一供给（见 .bd-cell 那处「唯一事实来源」块），
   这里只管几何。15px 比一行中文略高一点，视觉上正好「压住」标题第一行。 */
.pc-bdbar { flex: none; width: 3px; height: 15px; border-radius: 2px; background: var(--brand); }
.pc-bdbar.mute { background: rgba(19, 26, 46, .14); }   /* 没有板块的帖子：中性灰，保持左侧节奏 */

/* 置顶 / 精华圆标：一个「顶」一个「精」，圆形白字，两色必须区分开 ——
   置顶＝橙红（重要、压在最上面），精华＝金（优质内容）。
   这两个色跟任一板块色都不撞：板块色里最接近的橙是 #FFB020→#FF8A3D（活动风采），
   置顶特意压到更红的 #FF6B4A→#DC3E1F，色相差得开、不会看混。 */
.pi {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%;
  font-size: 10.5px; font-weight: 800; font-style: normal; line-height: 1;
  letter-spacing: 0; color: #fff;
}
.pi.top { background: linear-gradient(140deg, #FF6B4A, #DC3E1F); box-shadow: 0 1px 3px rgba(200, 62, 30, .35); }
.pi.ess { background: linear-gradient(140deg, #F5CE6A, #C08A1E); box-shadow: 0 1px 3px rgba(170, 125, 25, .35); }

/* 帖子详情页底部那条「顶 置顶 / 精 精华」：跟列表页同一套圆标，补一个文字胶囊 */
.pi-lab {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 10px 0 4px; border-radius: 999px;
  background: var(--surface-2); font-size: 12px; font-weight: 700; color: var(--ink-2);
}

/* 手机端把作者行整体压到 10.5px —— 和首页「最新动态」的 .fr-foot 同一个量级，
   不然卡片底部的头像/名字会比首页的粗一圈。 */
@media (max-width: 899px) {
  .pc-foot { font-size: 10.5px; gap: 5px; }
  .pc-foot .pc-sp { gap: 9px; }
  .pc-foot .pc-who .off-badge { height: 18px; padding: 0 6px; font-size: 10.5px; }
  .pc-when { font-size: 10.5px; }
}

.act { display: inline-flex; align-items: center; gap: 5px; transition: .15s; }
.act svg { width: 16px; height: 16px; }
.act.on { color: #D0473C; }
.post-card .act:hover { color: var(--brand); }

.off-badge {
  display: inline-flex; align-items: center; gap: 4px;
  height: 21px; padding: 0 8px; border-radius: 6px;
  background: var(--gold-050); color: #8A6415;
  font-size: 11.5px; font-weight: 700; letter-spacing: .02em;
  box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .38);
}
.off-badge::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--gold); flex: none; }
.legacy-dot { font-size: 11px; color: var(--faint); }

/* ===========================================================
   帖子详情
   =========================================================== */
.post-detail { padding: 20px 18px; }

/* 帖子详情头部（2026-09-21 改版）
   手机截图反馈「顶部排版很乱」：原来名字/部门/时间/「历史内容」全挤在一条 flex 里
   各自折行，「历史内容」被挤成竖排 4 个字，三行文字又把 48px 头像衬歪。
   现在固定成两行硬结构，任何宽度都不再折行：
     r1 = 名字 + 等级徽章 …… 发帖时间（margin-left:auto 贴右，nowrap）
     r2 = 部门 · 岗位（nowrap + 省略号）
   发帖时间随之从 r2 挪到 r1 的等级徽章右侧，末尾「历史内容」标签去掉。
   两行合计约 44px，对着 48px 头像居中 → 左侧头像与右侧信息上下对齐。 */
.pd-head { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.pd-head-tx { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.pd-head-r1 { display: flex; align-items: center; gap: 8px; min-width: 0; }
.pd-author { flex: 0 1 auto; font-size: 15.5px; }
.pd-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pd-when {
  flex: none; margin-left: auto; padding-left: 4px;
  font-size: 11.5px; color: var(--faint);
  white-space: nowrap;
}
.pd-sub {
  min-width: 0; font-size: 12px; line-height: 1.45; color: var(--faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 窄屏再收一档：名字 + 等级 + 时间 三件套并排 */
@media (max-width: 899px) {
  .pd-head { gap: 10px; margin-bottom: 15px; }
  .pd-head-r1 { gap: 6px; }
  .pd-author { font-size: 15px; }
  .pd-when { font-size: 11px; }
  .pd-sub { font-size: 11.5px; }
}
/* 320px 级极窄屏（iPhone SE 一代 / 老安卓）再压一档：
   不压的话「名字 + Lv.N 一级警司 + 2026-09-14 11:56」三件套会溢出约 7px，
   最后被省略号切的是名字。宁可头像小一圈、等级徽章和字号小半号，也不切名字。 */
@media (max-width: 360px) {
  .pd-head { gap: 9px; }
  .pd-head-tx { gap: 3px; }
  .pd-head-r1 { gap: 5px; }
  .pd-author { font-size: 14.5px; }
  .pd-author .lv-badge { height: 19px; padding: 0 5px; font-size: 10.5px; }
  .pd-when { padding-left: 3px; font-size: 10.5px; }
  .pd-head .avatar { width: 42px; height: 42px; font-size: 16px; }
}
.pd-title { font-size: 21px; font-weight: 800; line-height: 1.42; margin: 0 0 14px; }
.pd-body { font-size: 15.5px; line-height: 1.82; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }
/* 详情页图片墙：帆哥 2026-09-23 反馈「都点进帖子了，图片必须完整显示，不能裁成方块、
   更不能逼用户点开才看得全」。所以这里放弃 1:1 裁剪，图片按原始比例纵向完整呈现
   （宽度撑满、高度自适应），object-fit 改为 contain 兜底、img 用原图不裁；
   点图仍可放大看原图（data-act="zoom" 灯箱），但默认就完整可读。 */
/* 🚨 align-items:start 不能删（第 59 轮 2026-09-24「两块灰」）：
   Grid 不写 align-items 时浏览器默认 stretch → 把同一行的两个 .ph 拉成等高；而 img 是
   height:auto，只占图片自身高度 → 矮的那张下方露出 .ph 的 background（--surface-2）。
   覆盖层又把 --surface-2 重定义为 rgba(19,26,46,.045)，叠白卡 = rgb(245,245,246)，
   肉眼就是「一块灰」。实测 1440×10167 那种整页长截图旁边能露 1120px（占格子 47%）。
   start 只让格子回到各自自然高，不改图片顺序、不改任何间距。 */
.pd-imgs { display: grid; gap: 7px; margin-top: 16px; grid-template-columns: repeat(2, 1fr); align-items: start; }
.pd-imgs .ph { aspect-ratio: auto; border-radius: var(--r-sm); cursor: zoom-in; }
.pd-imgs .ph img { width: 100%; height: auto; object-fit: contain; }
.pd-imgs.single { grid-template-columns: 1fr; }
.pd-imgs.single .ph { aspect-ratio: auto; }
.pd-actions { display: flex; align-items: center; gap: 12px; margin-top: 18px; padding-top: 15px; border-top: 1px solid var(--line); }

/* 原富文本内容（含产品规格表） */
.rt-body { margin-top: 14px; overflow-x: auto; }
.rt-body table, table.rtable {
  width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 13.5px;
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  table-layout: auto;
}
table.rtable td, table.rtable th {
  padding: 9px 11px; border: 1px solid var(--line); vertical-align: top;
  color: var(--ink-2); line-height: 1.55;
}
table.rtable td:first-child { color: var(--ink-3); white-space: nowrap; }
.rt-body p { margin: 10px 0; color: var(--ink-2); line-height: 1.8; }
.rt-body img { display: none; }

/* 图片灯箱 */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(6, 12, 24, .94);
  display: grid; place-items: center; padding: 20px;
  backdrop-filter: blur(6px);
  /* touch-action:none 把双指捏合让给我们自己的手势代码 ——
     不写这条，iOS 会拿去做「整页缩放」，图纹丝不动而页面在放大 */
  touch-action: none;
}
.lb-backdrop { position: absolute; inset: 0; z-index: 0; }
.lb-stage {
  position: relative; z-index: 1; max-width: 100%;
  display: grid; place-items: center; gap: 12px;
}
.lightbox img { max-width: 100%; max-height: 84vh; object-fit: contain; border-radius: 8px; }
/* 缩放只作用在 transform 上，不改布局尺寸 ——
   所以切图、关闭、预加载那些既有逻辑一行都不用动。
   will-change 让手机把它提到合成层，捏合时不会一卡一卡。 */
.lightbox .lb-img {
  max-height: 78vh;
  cursor: zoom-in;
  transform-origin: center center;
  will-change: transform;
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-user-drag: none; -webkit-touch-callout: none;
}
.lightbox.zoomed .lb-img { cursor: zoom-out; }
.lb-stage { touch-action: none; }
.lb-backdrop { touch-action: none; }

/* 「双击可放大」提示：出现一次就够，2.4 秒后淡出 */
.lb-tip {
  position: absolute; left: 50%; bottom: 70px; z-index: 3;
  transform: translateX(-50%);
  padding: 7px 14px; border-radius: 20px; white-space: nowrap;
  background: rgba(8, 21, 44, .74); color: rgba(255, 255, 255, .93);
  font-size: 12.5px; pointer-events: none;
  backdrop-filter: blur(6px);
  animation: lbTipIn .26s cubic-bezier(.22, .7, .3, 1) both;
}
.lb-tip.out { opacity: 0; transition: opacity .6s ease; }
@keyframes lbTipIn {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.lb-title {
  color: rgba(255, 255, 255, .88); font-size: 14px; font-weight: 600;
  line-height: 1.5; text-align: center; max-width: min(88vw, 760px);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.lb-close {
  position: absolute; top: 18px; right: 18px;
  width: 40px; height: 40px; border-radius: 50%;
  border: none; background: rgba(255, 255, 255, .12); color: #fff;
  display: grid; place-items: center;
}
.lb-close svg { width: 20px; height: 20px; }
.lb-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; border-radius: 50%;
  border: none; background: rgba(255, 255, 255, .12); color: #fff;
  display: grid; place-items: center;
}
.lb-nav svg { width: 20px; height: 20px; }
.lb-prev { left: 16px; }
.lb-next { right: 16px; }
.lb-count {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%); z-index: 2;
  color: rgba(255, 255, 255, .75); font-size: 13px; font-variant-numeric: tabular-nums;
  background: rgba(8, 21, 44, .55); padding: 5px 12px; border-radius: 20px;
  backdrop-filter: blur(4px);
}
.lb-close, .lb-nav { z-index: 2; }

/* ===========================================================
   评论
   =========================================================== */
.comment-item { display: flex; gap: 11px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.comment-item:last-child { border-bottom: none; }
.ci-main { min-width: 0; flex: 1; }
.ci-head { display: flex; align-items: center; gap: 7px; margin-bottom: 5px; }
.ci-name { font-size: 14px; font-weight: 650; }
.ci-time { font-size: 11.5px; color: var(--faint); margin-left: auto; }
.ci-body { font-size: 14.5px; color: var(--ink-2); line-height: 1.7; white-space: pre-wrap; word-break: break-word; }
.ci-foot { display: flex; gap: 16px; margin-top: 8px; font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.composer { display: flex; align-items: flex-end; gap: 10px; padding: 14px 0 4px; border-top: 1px solid var(--line); margin-top: 8px; }
.composer textarea {
  flex: 1; min-width: 0; min-height: 42px; max-height: 180px;
  padding: 10px 13px; border: 1px solid var(--hair); border-radius: 12px;
  background: var(--surface); resize: none; outline: none; line-height: 1.6;
}
.composer textarea:focus { border-color: var(--brand); box-shadow: 0 0 0 3.5px rgba(10, 90, 168, .12); }

/* ===========================================================
   相册
   =========================================================== */
/* 图集网格：一个封面 = 一个帖子 */
.album-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.album-card { cursor: zoom-in; min-width: 0; }
.album-cover {
  position: relative; overflow: hidden; border-radius: 12px;
  background: var(--surface-2); aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
}
.album-cover img { width: 100%; height: 100%; object-fit: cover; display: block; transition: .35s; }
/* 未加载完的封面加一层微光：纯灰块和坏图在观感上分不出来，
   微光至少能明确表达「正在加载」而不是「这图没了」。
   .filled 由 img 的 onload 打上，加载完立刻撤掉。
   服务器出口带宽窄（约 148 KB/s），首屏铺满需要一两秒，这段过渡很关键。 */
.album-cover:not(.filled)::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 32%, rgba(255,255,255,.62) 50%, transparent 68%);
  background-size: 240% 100%;
  animation: coverShimmer 1.15s linear infinite;
}
@keyframes coverShimmer { from { background-position: 130% 0; } to { background-position: -130% 0; } }
@media (prefers-reduced-motion: reduce) { .album-cover:not(.filled)::after { animation: none; } }
.album-card:hover .album-cover img { transform: scale(1.045); }
/* 张数角标 */
.album-n {
  position: absolute; right: 7px; top: 7px;
  height: 21px; padding: 0 8px 0 6px; border-radius: 7px;
  background: rgba(8, 21, 44, .74); color: #fff;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 3px;
  backdrop-filter: blur(4px);
}
.album-n svg { width: 13px; height: 13px; opacity: .9; }
.album-cap {
  margin-top: 7px; font-size: 12.5px; font-weight: 650; color: var(--ink-2);
  font-variant-numeric: tabular-nums; letter-spacing: .2px;
}
.album-title {
  margin-top: 2px; font-size: 12px; color: var(--ink-3); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
/* 官方身份角标（图集封面与旧平铺网格共用） */
.g-badge {
  position: absolute; left: 6px; bottom: 6px;
  height: 19px; padding: 0 6px; border-radius: 5px;
  background: rgba(8, 21, 44, .72); color: #fff;
  font-size: 10.5px; font-weight: 600; display: grid; place-items: center;
  backdrop-filter: blur(4px);
}
/* 旧的平铺网格，保留给后台排查用 */
.gallery-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.g-item { position: relative; overflow: hidden; border-radius: 9px; background: var(--surface-2); aspect-ratio: 1 / 1; cursor: zoom-in; }
.g-item img { width: 100%; height: 100%; object-fit: cover; transition: .3s; }
.g-item:hover img { transform: scale(1.05); }

/* ===========================================================
   其它组件
   =========================================================== */
.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 14px 15px; box-shadow: var(--sh-1); }
.stat .sv { font-size: 23px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat .sl { font-size: 12px; color: var(--ink-3); margin-top: 2px; }

.progress { height: 7px; border-radius: 4px; background: rgba(255, 255, 255, .18); overflow: hidden; }
.progress .pfill { height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--gold), var(--gold-300)); }
.progress.on-light { background: var(--surface-2); }
.progress.on-light .pfill { background: linear-gradient(90deg, var(--brand), var(--brand-600)); }

.chart { display: flex; align-items: flex-end; gap: 5px; height: 128px; padding-top: 10px; }
.bar-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
.bar { width: 100%; max-width: 26px; border-radius: 5px 5px 2px 2px; min-height: 3px; background: linear-gradient(180deg, var(--brand-600), var(--navy-700)); transition: .3s; }
.bl { font-size: 10.5px; color: var(--faint); font-variant-numeric: tabular-nums; }
.bar-line { margin-bottom: 14px; }
.bl-top { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 6px; color: var(--ink-2); }
.bl-top b { font-variant-numeric: tabular-nums; }
.track { height: 7px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.track .fill { height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--brand), var(--navy-700)); }

.rank-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; cursor: pointer; }
.rank-no {
  flex: none; width: 22px; height: 22px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--ink-3);
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.rank-no.top1 { background: linear-gradient(150deg, #E8C87A, #C8A15A); color: #fff; }
.rank-no.top2 { background: linear-gradient(150deg, #CBD2DA, #A8B2BD); color: #fff; }
.rank-no.top3 { background: linear-gradient(150deg, #DDB894, #BE8F63); color: #fff; }
.rank-name { font-size: 14px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-pts { margin-left: auto; font-size: 13px; font-weight: 700; color: var(--brand-600); font-variant-numeric: tabular-nums; }

.board-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px; }
.board-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 16px 15px; cursor: pointer;
  box-shadow: var(--sh-1); transition: .18s;
}
.board-card:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
.board-ico {
  width: 42px; height: 42px; border-radius: 13px; margin-bottom: 11px;
  display: grid; place-items: center; font-size: 18px; font-weight: 800; color: #fff;
  background: linear-gradient(150deg, var(--brand-600), var(--navy-700));
}
.board-ico.a-gold { background: linear-gradient(150deg, #D9B871, #B08A3E); }
.board-ico.a-indigo { background: linear-gradient(150deg, #6272C4, #3C49A0); }
.board-ico.a-amber { background: linear-gradient(150deg, #D9A24A, #B07A22); }
.board-ico.a-teal { background: linear-gradient(150deg, #35A392, #16786A); }
.board-ico.a-rose { background: linear-gradient(150deg, #D4798F, #B04E68); }
.board-ico.a-slate { background: linear-gradient(150deg, #8593A2, #5F6B78); }
.board-name { font-size: 15px; font-weight: 700; margin-bottom: 4px; }
.board-intro { font-size: 12.5px; color: var(--ink-3); line-height: 1.55; }

.act-card {
  display: flex; gap: 14px; padding: 14px; margin-bottom: 11px;
  border-radius: var(--r-md); background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--sh-1); cursor: pointer;
}
.ac-cover {
  width: 78px; height: 78px; flex: none; border-radius: var(--r-sm);
  background: linear-gradient(150deg, var(--brand-050), var(--surface-2));
  display: grid; place-items: center; color: var(--brand); overflow: hidden;
}
.ac-cover img { width: 100%; height: 100%; object-fit: cover; }
.ac-cover svg { width: 26px; height: 26px; }

.uploader { display: flex; flex-wrap: wrap; gap: 9px; }
.up-tile {
  width: 82px; height: 82px; border-radius: 11px; position: relative; overflow: hidden;
  border: 1.5px dashed var(--hair); background: var(--surface-2);
  display: grid; place-items: center; color: var(--ink-3); cursor: pointer;
}
.up-tile:hover { border-color: var(--brand); color: var(--brand); }
.up-tile svg { width: 24px; height: 24px; }
.up-tile img { width: 100%; height: 100%; object-fit: cover; }
.up-tile .rm {
  position: absolute; top: 3px; right: 3px;
  width: 19px; height: 19px; border-radius: 50%;
  background: rgba(8, 21, 44, .68); color: #fff;
  display: grid; place-items: center; font-size: 13px; line-height: 1;
}

.toast-wrap {
  position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
  z-index: 300; display: flex; flex-direction: column; gap: 8px;
  align-items: center; pointer-events: none; width: calc(100% - 32px); max-width: 420px;
}
.toast {
  padding: 10px 17px; border-radius: 12px;
  background: rgba(16, 25, 40, .93); color: #fff;
  font-size: 13.5px; font-weight: 500;
  box-shadow: var(--sh-3); backdrop-filter: blur(10px);
  animation: toastIn .24s ease;
}
.toast.ok { background: rgba(20, 100, 70, .95); }
.toast.err { background: rgba(150, 40, 34, .95); }
@keyframes toastIn { from { opacity: 0; transform: translateY(-10px); } }

.sheet-mask {
  position: fixed; inset: 0; z-index: 150;
  background: rgba(6, 12, 24, .55); backdrop-filter: blur(5px);
  display: grid; align-items: flex-end; justify-items: center;
}
.sheet {
  width: 100%; max-width: 520px;
  background: var(--surface);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding: 26px 22px calc(26px + env(safe-area-inset-bottom));
  box-shadow: var(--sh-3); animation: sheetUp .3s cubic-bezier(.22, .8, .3, 1);
}
@keyframes sheetUp { from { transform: translateY(60px); opacity: .6; } }
.sheet-crest {
  width: 62px; height: 62px; border-radius: 20px; margin: 0 auto 16px;
  background: linear-gradient(150deg, var(--navy-700), var(--navy-900));
  display: grid; place-items: center; box-shadow: 0 10px 26px rgba(8, 21, 44, .3);
}
.sheet-crest img { width: 60%; height: 60%; object-fit: contain; }
.sheet h3 { text-align: center; font-size: 19px; font-weight: 800; margin: 0 0 8px; }
.sheet p { text-align: center; font-size: 13.5px; color: var(--ink-3); line-height: 1.7; margin: 0 0 18px; }
.sheet-stat { display: flex; gap: 10px; margin-bottom: 20px; }
.sheet-stat > div { flex: 1; text-align: center; padding: 13px 8px; border-radius: var(--r-sm); background: var(--surface-2); }
.sheet-stat b { display: block; font-size: 19px; font-weight: 800; font-variant-numeric: tabular-nums; }
.sheet-stat span { font-size: 11.5px; color: var(--ink-3); }

.login-wrap { max-width: 420px; margin: 0 auto; padding: 24px 4px 60px; }
.login-card { padding: 26px 22px; }
.login-hero { text-align: center; padding: 8px 0 22px; }
.login-hero .brand-mark { width: 56px; height: 56px; border-radius: 18px; margin: 0 auto 14px; }
.login-hero h1 { font-size: 21px; font-weight: 800; margin: 0 0 6px; letter-spacing: .02em; }
.login-hero p { font-size: 12.5px; color: var(--ink-3); margin: 0; letter-spacing: .06em; }
.login-note { display: flex; gap: 9px; padding: 12px 13px; border-radius: var(--r-sm); background: var(--brand-050); margin-bottom: 18px; }
.login-note svg { width: 17px; height: 17px; flex: none; color: var(--brand); margin-top: 1px; }
.login-note div { font-size: 12.5px; color: var(--brand-ink); line-height: 1.65; }

/* ===========================================================
   响应式：≥ 900px 进入三栏
   =========================================================== */
@media (min-width: 900px) {
  .tabbar, .topbar { display: none; }
  .shell {
    display: grid;
    grid-template-columns: 236px minmax(0, 1fr);
    max-width: 1180px; margin: 0 auto; padding: 0 20px;
    align-items: start;
  }
  .col-nav {
    display: block; position: sticky; top: 0;
    /* 🚨 100vh + 1px，不是笔误（第 65 轮防抖动）：
       文档高度只要**恰好等于**视口高，竖直滚动条就会消失；切页瞬间中间列被换成
       26px 转圈占位、高度正好塌到一屏 → 滚动条一闪一灭 → 整页横移 7.5px。
       多留 1px 让文档永远比视口高一点点 → 滚动条**常驻**，状态不再翻转。
       为什么不直接写 html{overflow-y:scroll}：那会让 html 的 overflow 不再是
       visible，body 的 `overflow:hidden`（.sh-lock 那道滚动锁）就不再传播到视口，
       故事编辑浮层打开时背景还能滚。多 1px 这种写法完全不碰 overflow 传播。
       ⚠️ 上面 html 的 scrollbar-gutter 是老内核的主锁，这条是第二道保险，两条都要。 */
    height: calc(100vh + 1px); overflow-y: auto;
    padding: 22px 16px 40px 0;
    border-right: 1px solid var(--line);
  }
  .col-nav::-webkit-scrollbar { width: 5px; }
  .col-nav::-webkit-scrollbar-thumb { background: var(--hair); border-radius: 3px; }
  .col-main { padding: 22px 24px 60px; }
  .post-card { padding: 18px 20px 14px; }
  .pc-title { font-size: 17px; }
  .pd-title { font-size: 24px; }
  .post-detail { padding: 26px 28px; }
  .stat-grid { grid-template-columns: repeat(4, 1fr); }
  .board-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .gallery-grid { grid-template-columns: repeat(5, 1fr); gap: 7px; }
  .album-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
  .hero { padding: 22px 24px 20px; margin-bottom: 20px; }
  .hero-hello { font-size: 26px; margin-bottom: 6px; }
  .hero-desc { font-size: 13.5px; margin-bottom: 16px; }
  .hero-search { height: 44px; padding: 0 15px; }
  .hero-stats { margin-top: 16px; padding-top: 14px; }
  .hero-stat b { font-size: 21px; }
  .hero-stat span { font-size: 11px; }
  .ch-cell { padding: 9px 10px; }
  .ch-cell .cn { font-size: 14px; }
  .ch-cell .cn .cnt { font-size: 11.5px; }
  .ch-cell .cn .cnt .u { display: inline; }
  .ch-cell .ci { font-size: 11.5px; }
  .ch-cell .ct { width: 44px; height: 44px; }
  .sheet-mask { align-items: center; }
  .sheet { border-radius: var(--r-xl); }
}

@media (min-width: 1400px) {
  .shell { grid-template-columns: 236px minmax(0, 1fr) 288px; max-width: 1360px; }
  .gallery-grid { grid-template-columns: repeat(6, 1fr); }
  .album-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 380px) {
  .col-main { padding: 12px 11px 92px; }
  .post-card { padding: 14px 13px 11px; border-radius: var(--r-sm); }
  .pc-title { font-size: 15.5px; }
  .hero { padding: 17px 15px 16px; }
  .hero-hello { font-size: 18px; }
  .ch-cell { padding: 8px 8px; gap: 8px; }
  .ch-cell .ct { width: 34px; height: 34px; }
  .ch-cell .cn { font-size: 12.5px; }
  .ch-cell .ci { font-size: 10px; }
  .gallery-grid { gap: 4px; }
  .album-grid { gap: 9px; }
}


/* ===========================================================
   帖子详情页 · 互动条（点赞 / 写评论）
   =========================================================== */
.pd-acts {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.pd-act {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 17px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: border-color .18s ease, color .18s ease, transform .18s ease, background .18s ease;
}
.pd-act:hover {
  border-color: #CBD4E0;
  color: var(--brand);
  transform: translateY(-1px);
}
.pd-act svg { width: 17px; height: 17px; display: block; }
.pd-act-ico { display: inline-flex; align-items: center; }
.pd-act-n {
  font-variant-numeric: tabular-nums;
  color: var(--faint);
  font-size: 12.5px;
  font-weight: 600;
}
.pd-act-like.on {
  background: linear-gradient(135deg, #FFF3F4, #FFE6EA);
  border-color: #F2B4C0;
  color: #BE2E48;
}
.pd-act-like.on svg { fill: #DE4462; stroke: #DE4462; }
.pd-act-like.on .pd-act-n { color: #BE2E48; }

@media (max-width: 900px) {
  .pd-acts { gap: 8px; margin-top: 16px; padding-top: 14px; }
  .pd-act { flex: 1; justify-content: center; padding: 11px 12px; }
}

/* ===========================================================
   2026-09-20 改版：圈子列表 / 频道 / 活动 / 产品档案 / 手机详情页
   =========================================================== */

/* --------- ① 搜索条：原来是一个 42px 输入框套 12px 内边距（总高 66px），
   太占地方，压到 38px 单行。 --------- */
.home-search {
  display: flex; align-items: center; gap: 9px;
  height: 38px; padding: 0 13px; margin-bottom: 12px;
  border-radius: 12px; background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--sh-1);
  transition: .16s;
}
.home-search:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3.5px rgba(10, 90, 168, .1); }
.home-search svg { width: 15px; height: 15px; flex: none; color: var(--faint); }
.home-search input {
  flex: 1; min-width: 0; height: 100%; padding: 0;
  border: none; background: transparent; outline: none; font-size: 13.5px;
}
.home-search input::placeholder { color: var(--faint); }

/* --------- ② 顶上 6 个板块：3 列 × 2 行，极简格子（不放缩略图与简介） --------- */
.bd-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 12px; }
.bd-cell {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  padding: 9px 9px; border-radius: 12px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--sh-1); transition: .16s;
}
.bd-cell:hover { transform: translateY(-1px); box-shadow: var(--sh-2); border-color: #DED9CE; }
/* 圈子板块格左侧竖线：颜色见下面「唯一事实来源」那一组（--bd-*），
   几何交给 ⑦ 频道格那条两页共用规则（.ch-cell .cn i, .bd-cell i，
   实测 3.5×14），这里只留底色兜底和 flex 行为 ——
   帆哥要求「以首页为准」，颜色和尺寸一起收敛。 */
.bd-cell i { background: var(--brand); flex: none; }

/* 板块强调色：唯一事实来源（变量定义见文件末尾的 :root）。
   四个用到「板块色」的地方全在这一条里 —— 首页频道格、圈子板块格、
   帖子题目前的板块竖线、右栏热门板块圆点。改色只改这一处。
   ⚠️ 必须放在 .bd-cell.on i（选中态转金色）**之前**，否则选中态会被这组盖掉。 */
.ch-cell .cn i.a-blue,   .bd-cell i.a-blue,   .pc-bdbar.a-blue,   .aside-row .dot.a-blue   { background: var(--bd-blue); }
.ch-cell .cn i.a-indigo, .bd-cell i.a-indigo, .pc-bdbar.a-indigo, .aside-row .dot.a-indigo { background: var(--bd-indigo); }
.ch-cell .cn i.a-amber,  .bd-cell i.a-amber,  .pc-bdbar.a-amber,  .aside-row .dot.a-amber  { background: var(--bd-amber); }
.ch-cell .cn i.a-teal,   .bd-cell i.a-teal,   .pc-bdbar.a-teal,   .aside-row .dot.a-teal   { background: var(--bd-teal); }
.ch-cell .cn i.a-rose,   .bd-cell i.a-rose,   .pc-bdbar.a-rose,   .aside-row .dot.a-rose   { background: var(--bd-rose); }
.ch-cell .cn i.a-slate,  .bd-cell i.a-slate,  .pc-bdbar.a-slate,  .aside-row .dot.a-slate  { background: var(--bd-slate); }
.ch-cell .cn i.a-gold,   .bd-cell i.a-gold,   .pc-bdbar.a-gold,   .aside-row .dot.a-gold   { background: var(--bd-gold); }

.bd-cell .bn { font-size: 12.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bd-cell .bc { margin-left: auto; flex: none; font-size: 10.5px; font-weight: 700; color: var(--faint); font-variant-numeric: tabular-nums; }
.bd-cell.on {
  background: linear-gradient(180deg, var(--navy-700), var(--navy-800));
  border-color: transparent; color: #fff;
  box-shadow: 0 6px 18px rgba(11, 30, 60, .24);
}
.bd-cell.on i { background: var(--gold-300); }
.bd-cell.on .bc { color: rgba(255, 255, 255, .6); }

/* --------- ③ 最新 / 热门 / 全部：小巧的分段控件 + 独立小片 --------- */
.sort-row { display: flex; align-items: center; gap: 8px; margin-bottom: 13px; }
.mini-seg {
  display: inline-flex; gap: 2px; padding: 2px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
}
.mini-seg .ms {
  height: 26px; padding: 0 12px; border-radius: 8px;
  display: inline-flex; align-items: center; cursor: pointer;
  font-size: 12.5px; font-weight: 650; color: var(--ink-3);
  white-space: nowrap; transition: .16s;
}
.mini-seg .ms:hover { color: var(--ink); }
.mini-seg .ms.on {
  background: var(--surface); color: var(--brand-ink);
  box-shadow: 0 1px 3px rgba(16, 24, 40, .12);
}
.mini-chip {
  height: 30px; padding: 0 12px; border-radius: 10px;
  display: inline-flex; align-items: center; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12.5px; font-weight: 650; color: var(--ink-3);
  white-space: nowrap; transition: .16s;
}
.mini-chip:hover { color: var(--ink); }
.mini-chip.on {
  background: linear-gradient(180deg, var(--navy-700), var(--navy-800));
  border-color: transparent; color: #fff;
  box-shadow: 0 4px 12px rgba(11, 30, 60, .2);
}

/* --------- ④ 分类磁贴（频道页「全部板块」）：紧凑版 --------- */
.bd-tile {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 11px 12px; border-radius: 14px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--sh-1); transition: .18s;
}
.bd-tile:hover { transform: translateY(-2px); box-shadow: var(--sh-2); border-color: #DED9CE; }
.bd-tile .bt-ico {
  width: 34px; height: 34px; border-radius: 11px; flex: none;
  display: grid; place-items: center; color: #fff; font-size: 14px; font-weight: 800;
  background: linear-gradient(150deg, var(--brand-600), var(--navy-700));
}
.bd-tile .bt-ico.a-gold { background: linear-gradient(150deg, #D9B871, #B08A3E); }
.bd-tile .bt-ico.a-indigo { background: linear-gradient(150deg, #6272C4, #3C49A0); }
.bd-tile .bt-ico.a-amber { background: linear-gradient(150deg, #D9A24A, #B07A22); }
.bd-tile .bt-ico.a-teal { background: linear-gradient(150deg, #35A392, #16786A); }
.bd-tile .bt-ico.a-rose { background: linear-gradient(150deg, #D4798F, #B04E68); }
.bd-tile .bt-ico.a-slate { background: linear-gradient(150deg, #8593A2, #5F6B78); }
.bd-tile .bt-main { flex: 1; min-width: 0; }
.bd-tile .bt-name { font-size: 13.5px; font-weight: 750; letter-spacing: -.005em; }
.bd-tile .bt-intro {
  font-size: 11px; color: var(--ink-3); line-height: 1.5; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bd-tile .bt-cnt {
  flex: none; text-align: right; color: var(--faint);
  font-size: 10px; font-variant-numeric: tabular-nums; line-height: 1.25;
}
.bd-tile .bt-cnt b { display: block; font-size: 14px; font-weight: 800; color: var(--brand-600); }

/* 板块页顶部信息条 */
.board-hero {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 15px; margin-bottom: 14px;
  border-radius: var(--r-md); background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--sh-1);
}
.board-hero .board-ico { width: 36px; height: 36px; border-radius: 11px; margin: 0; font-size: 15px; }
.board-hero .board-name { font-size: 15px; font-weight: 750; margin-bottom: 2px; }

/* --------- ⑤ 部门发布：深蓝大药丸 → 浅底小片 → 部门身份色点（方案 B，2026-09-22 帆哥拍板）
   这一版只留「一颗 7px 色点 + 部门名」，药丸的底色 / 边框 / 圆角全部去掉，靠间距分列。
   为什么干脆不要底：原来的底 #EFF1FF 与页面底 #F3F6FF 只差 4 阶色，
   形状全靠 1px 边框撑着 —— 与其用一层几乎看不见的底，不如不用。 */
.section-head.sm h2 { font-size: 15px; }
.dept-strip {
  display: flex; align-items: center; gap: 16px;
  overflow-x: auto; padding: 4px 0;
}
.dept-strip::-webkit-scrollbar { display: none; }
.dept-chip {
  flex: none; display: inline-flex; align-items: center; gap: 8px;
  height: 26px; padding: 0; border: 0; border-radius: 0;
  background: transparent; box-shadow: none;
  color: var(--ink); font-size: 13.5px; font-weight: 600; white-space: nowrap;
  cursor: pointer; transition: color .15s;
}
.dept-chip:hover, .dept-chip:active { background: transparent; color: var(--brand-600); }
/* 部门身份色点。颜色一律取 :root 里的 --bd-*（与首页「频道」左侧竖线、圈子顶部板块格、
   右栏「热门板块」圆点**同一套**，改色只动 :root 那一处）。
   哪个部门配哪个色由 app.js 按部门名算（不在这里写死），保证「几个部门几种颜色」。 */
.dept-chip .dd { width: 7px; height: 7px; border-radius: 50%; flex: none; display: block; }
.dept-chip .dd.a-blue   { background: var(--bd-blue); }
.dept-chip .dd.a-indigo { background: var(--bd-indigo); }
.dept-chip .dd.a-amber  { background: var(--bd-amber); }
.dept-chip .dd.a-teal   { background: var(--bd-teal); }
.dept-chip .dd.a-rose   { background: var(--bd-rose); }
.dept-chip .dd.a-slate  { background: var(--bd-slate); }
.dept-chip .dd.a-gold   { background: var(--bd-gold); }

/* --------- ⑥ 产品档案表单 --------- */
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.grid3 .field { margin-bottom: 14px; }
.grid3 .field > label { font-size: 12px; }
.grid3 .input { height: 40px; padding: 0 10px; font-size: 13.5px; border-radius: 10px; }
.grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

.sell-list { display: flex; flex-direction: column; gap: 9px; }
.sell-row { display: flex; align-items: flex-start; gap: 8px; }
.sell-row .textarea.sell {
  flex: 1; min-width: 0; min-height: 62px; height: auto;
  padding: 10px 12px; font-size: 14px; border-radius: 11px;
}
.sell-add {
  width: 40px; height: 40px; flex: none; border-radius: 11px;
  border: 1.5px dashed var(--hair); background: var(--surface-2); color: var(--ink-3);
  display: grid; place-items: center; transition: .16s; padding: 0;
}
.sell-add svg { width: 17px; height: 17px; }
.sell-add:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-050); }
.prod-thanks {
  display: flex; align-items: center; gap: 8px;
  padding: 11px 13px; margin-bottom: 18px; border-radius: 12px;
  background: linear-gradient(90deg, var(--gold-050), #FDFBF5);
  border: 1px solid rgba(200, 161, 90, .3);
  font-size: 12.5px; color: #8A6415; line-height: 1.6;
}
.prod-thanks .pt-ico { font-size: 15px; flex: none; }

/* --------- ⑦ 产品帖：图片带（放不下就向左匀速循环） --------- */
.pd-strip {
  position: relative; margin-top: 11px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 16px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 16px), transparent 100%);
}
.pd-track { display: flex; gap: 6px; width: max-content; }
.pd-track img {
  width: 58px; height: 58px; flex: none; display: block;
  border-radius: 10px; object-fit: cover; background: var(--surface-2);
}
.pd-strip.sm { margin-top: 7px; }
.pd-strip.sm .pd-track img { width: 46px; height: 46px; border-radius: 8px; }
.pd-strip.run .pd-track {
  animation-name: pdScroll; animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes pdScroll { from { transform: translateX(0); } to { transform: translateX(calc(-1 * var(--shift, 0px))); } }
@media (prefers-reduced-motion: reduce) { .pd-strip.run .pd-track { animation: none; } }

/* 2026-09-21 帆哥反馈：新品发布板块的帖子题目比其他板块大一圈。
   根因就是原来这里写死了 font-size: 16px —— 而 .pc-title 在 v2 里是 15px（桌面）
   / 14px（手机），选择器优先级（0,3,0）又高于 .pc-title（0,1,0），所以产品帖
   永远大一号。现在去掉这个 font-size，让它跟着 .pc-title 走，各板块一致。
   margin-bottom 保留（产品卡标题下面直接是图片带，间距需求跟普通卡不同）。 */
.post-card.prod .prod-title { margin-bottom: 0; }
.post-card.prod .pc-foot { margin-top: 13px; }

/* 产品档案（详情页） */
.prod-spec {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px;
  margin: 4px 0 16px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--line); border: 1px solid var(--line);
}
.prod-spec .ps-item {
  display: flex; align-items: baseline; gap: 8px;
  padding: 10px 13px; background: var(--surface); min-width: 0;
}
.prod-spec .ps-k { flex: none; font-size: 12px; color: var(--ink-3); }
.prod-spec .ps-v {
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prod-sells { margin-top: 6px; }
.prod-sells .ps-head {
  font-size: 12px; font-weight: 700; letter-spacing: .1em;
  color: var(--faint); margin-bottom: 9px;
}
.prod-sells ul { margin: 0; padding: 0; list-style: none; }
.prod-sells li {
  position: relative; padding: 6px 0 6px 22px;
  font-size: 15px; line-height: 1.75; color: var(--ink-2);
}
.prod-sells li::before {
  content: ''; position: absolute; left: 4px; top: 14px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--gold); box-shadow: 0 0 0 3px var(--gold-050);
}

/* --------- ⑧ 活动 --------- */
.act-card { display: flex; gap: 14px; padding: 13px 14px; }
.act-main { min-width: 0; flex: 1; }
.act-tags { display: flex; gap: 5px; margin-bottom: 5px; flex-wrap: wrap; }
.act-title {
  font-size: 15.5px; font-weight: 700; line-height: 1.4; margin-bottom: 4px;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.act-meta {
  display: flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--ink-3); line-height: 1.7;
}
.act-meta svg { width: 13px; height: 13px; flex: none; }
.act-meta b { color: var(--brand-600); font-variant-numeric: tabular-nums; }
.act-cover-big {
  margin: -6px -6px 16px; border-radius: var(--r-sm); overflow: hidden;
  aspect-ratio: 16 / 9; background: var(--surface-2);
}
.act-cover-big img { width: 100%; height: 100%; object-fit: cover; display: block; }
.act-info { margin-bottom: 7px; align-items: flex-start; gap: 8px; }
.act-info:last-child { margin-bottom: 0; }
.act-info .ai-k { flex: none; width: 44px; font-size: 12.5px; color: var(--ink-3); }
.act-info .ai-v { font-size: 13.5px; color: var(--ink-2); min-width: 0; }
.up-wide { width: 168px; gap: 7px; flex-direction: column; }
.up-wide .up-tip { font-size: 11px; color: var(--ink-3); }
.uploader input[type="datetime-local"] { font-size: 14px; }

/* --------- ⑨ 帖子详情：管理操作区 --------- */
.admin-bar { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }

/* ---- 管理操作条（2026-09-21 第三轮重做）----
   帆哥要求：按钮名称就是「置顶 / 精华 / 下架 / 删除 / 编辑」，按这个顺序，
   大小一致、排在同一行不换行。
   状态**不靠改文案**表达 —— 「已置顶」是 3 个字，窄屏会把一排挤折；
   改成换底色：蓝 = 已置顶、金 = 已精华、灰 = 已下架。
   「点下去会发生什么」交给 title（桌面端悬停可见）。 */
.ab-label {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .1em;
  color: var(--faint); margin-bottom: 9px;
}
.ab-label::before {
  content: ''; width: 3px; height: 11px; border-radius: 2px;
  background: var(--brand); opacity: .5;
}
.ab-row { display: flex; flex-wrap: wrap; gap: 8px; }
.ab-btn { gap: 5px; font-weight: 600; }
.ab-btn svg { width: 14px; height: 14px; flex: none; }
.ab-btn > span { white-space: nowrap; }

/* 已置顶 —— 品牌蓝实心 */
.ab-btn.on {
  background: var(--brand); border-color: var(--brand); color: #fff;
  box-shadow: 0 1px 2px rgba(10, 90, 168, .26);
}
.ab-btn.on:hover { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
/* 已精华 —— 金线色实心（压深字色保证对比度） */
.ab-btn.on-gold {
  background: var(--gold); border-color: var(--gold); color: #2E2107;
  box-shadow: 0 1px 2px rgba(200, 161, 90, .34);
}
.ab-btn.on-gold:hover { background: #BE934A; border-color: #BE934A; color: #2E2107; }
/* 已下架 —— 中性灰实心 */
.ab-btn.on-gray {
  background: #6B7280; border-color: #6B7280; color: #fff;
  box-shadow: 0 1px 2px rgba(107, 114, 128, .28);
}
.ab-btn.on-gray:hover { background: #5B6472; border-color: #5B6472; color: #fff; }
/* 删除 —— 唯一的危险操作，红字红边 */
.ab-btn.ab-del { color: var(--danger); border-color: #EED9D6; }
.ab-btn.ab-del:hover { background: #FCF3F2; border-color: #E4C4C1; }
/* 审核通过 —— 主操作 */
.ab-btn.ab-ok {
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  border-color: transparent; color: #fff;
}
.ab-btn.ab-ok:hover { color: #fff; filter: brightness(1.05); background: linear-gradient(180deg, var(--brand-600), var(--brand)); }

/* --------- ⑩ 手机端：评论输入框变成贴底的输入条 --------- */
.cf-spacer { display: none; }
.guest-cta {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 18px 0 6px; border-top: 1px solid var(--line);
}

@media (max-width: 899px) {
  /* --- 帖子详情底部整体收一收 --- */
  .post-detail { padding: 16px 14px; }
  .pd-title { font-size: 19px; margin-bottom: 10px; }
  .pd-body { font-size: 15px; line-height: 1.78; }
  .pd-actions { margin-top: 15px; padding-top: 13px; }
  .pd-act {
    flex: 1; justify-content: center;
    padding: 10px 10px; border-radius: 11px;
    background: var(--surface-2); border-color: transparent;
    font-size: 13px; gap: 6px;
  }
  .pd-act:hover { transform: none; }
  .pd-act-like.on { background: linear-gradient(135deg, #FFF3F4, #FFE6EA); }

  /* 管理操作：灰底一块 + 小号药丸按钮，不再是一排忽大忽小的按钮 */
  .admin-bar {
    margin-top: 14px; padding: 12px 13px 13px;
    border-top: none; border-radius: var(--r-sm); background: var(--surface-2);
  }
  .admin-bar .btn-sm {
    height: 30px; padding: 0 11px; font-size: 12.5px;
    border-radius: 9px; background: var(--surface); flex: 0 1 auto;
  }
  /* 五（六）个按钮必须同一行：图标 + 两字，等分宽度。
     用 flex 等分而不是 grid 固定列数 —— 待审核帖有 6 个按钮，固定列会折行。 */
  .ab-row { flex-wrap: nowrap; gap: 6px; }
  .ab-row .ab-btn {
    flex: 1 1 0; min-width: 0; height: 36px; padding: 0 4px;
    font-size: 12px; gap: 3px; border-radius: 9px;
    background: var(--surface);
  }
  .ab-row .ab-btn svg { width: 13px; height: 13px; }
  .ab-row .ab-btn > span { overflow: hidden; text-overflow: ellipsis; }
  .ab-row .ab-btn.on { background: var(--brand); }
  .ab-row .ab-btn.on-gold { background: var(--gold); }
  .ab-row .ab-btn.on-gray { background: #6B7280; }
  .ab-row .ab-btn.ab-del { background: var(--surface); }
  .ab-label { margin-bottom: 8px; }

  /* 评论卡：标题更紧、空态不再占半屏 */
  #cmtBox { padding: 4px 14px 14px !important; }
  #cmtBox .section-head { padding-top: 12px; margin-bottom: 6px; }
  #cmtBox .empty { padding: 22px 12px; }

  /* 评论输入条贴底（悬浮导航占位 14+62=76px，所以抬到它上面） */
  .cf-spacer { display: block; height: 84px; }
  .composer-fixed {
    position: fixed; left: 0; right: 0; z-index: 66;
    bottom: calc(76px + env(safe-area-inset-bottom));
    margin: 0; padding: 9px 12px;
    align-items: center; gap: 8px;
    background: rgba(255, 255, 255, .96);
    backdrop-filter: saturate(180%) blur(18px);
    border-top: 1px solid var(--line);
    box-shadow: 0 -6px 20px rgba(8, 21, 44, .06);
  }
  .composer-fixed .avatar { width: 30px; height: 30px; font-size: 13px; }
  .composer-fixed textarea {
    min-height: 38px; max-height: 96px; padding: 8px 14px;
    border-radius: 19px; font-size: 14px; background: var(--surface-2);
    border-color: transparent;
  }
  .composer-fixed textarea:focus { background: var(--surface); }
  .composer-fixed .btn { height: 38px; padding: 0 16px; border-radius: 12px; flex: none; }

  /* 表单一行三个：手机上再挤一点，别让字数撑破 */
  .grid3 { gap: 8px; }
  .grid3 .input { height: 38px; padding: 0 9px; font-size: 13px; }
  .grid3 .field > label { font-size: 11.5px; }
  .bd-grid { gap: 7px; }
  .bd-cell { padding: 8px; gap: 5px; }
  .bd-cell .bn { font-size: 12px; }
}

@media (max-width: 380px) {
  .bd-cell .bn { font-size: 11.5px; }
  .grid3 .input { font-size: 12.5px; }
}

@media (min-width: 900px) {
  .bd-tile { padding: 12px 13px; }
  .bd-cell .bn { font-size: 13px; }
  .bd-cell .bc { font-size: 11px; }
  .mini-seg .ms { padding: 0 14px; }
  .home-search { height: 40px; }
  .pd-track img { width: 64px; height: 64px; }
  .prod-spec { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}


/* ===========================================================================
   2026-09-20 首页改版 · 方案三「清透玻璃」（帆哥选定）
   ---------------------------------------------------------------------------
   ① 配色  品牌蓝 #0A5AA8 → 靛蓝 #4A5BF0；底 → 淡蓝紫渐变；卡 → 半透明玻璃
   ② 布局  PC ≥1100px 三列（左导航 200 / 内容 / 右栏 272）
           右栏放「个人卡 + 热门板块 + 积分榜」—— 原来三块全挤在左栏
   ③ 首页  hero 不套深蓝卡，改透明底 + 两团色斑；频道格 / 帖子卡玻璃化
   ④ 帖表  通栏大图结构（方案二）：标题 → 摘要 → 大图 → 底部作者行
   ---------------------------------------------------------------------------
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚整段删掉即可。
   =========================================================================== */

/* ---------- ① 设计令牌 ---------- */
:root {
  --brand: #4A5BF0;
  --brand-600: #3B4CE0;
  --brand-ink: #2E3CC0;
  --brand-050: #EFF1FF;
  --violet: #7C5CFF;
  --cyan: #22B8E6;

  --ink: #131A2E;
  --ink-2: #525C74;
  --ink-3: #8B94AA;
  --faint: #A9B1C4;
  --line: rgba(19, 26, 46, .08);
  --hair: rgba(19, 26, 46, .10);
  --paper: #F1F4FF;
  --surface-2: rgba(19, 26, 46, .045);

  --glass: rgba(255, 255, 255, .88);
  --glass-brd: rgba(255, 255, 255, .92);
  --glass-sh: 0 12px 30px rgba(74, 91, 240, .13);
  --r-lg: 26px;
  --r-md: 20px;

  /* ---------- 板块强调色：唯一事实来源（2026-09-21） ----------
     凡是用 a-blue / a-indigo / … 标记「这是哪个板块」的地方，颜色都从这里取：
       · 首页「频道」格子左侧竖线（.ch-cell .cn i）
       · 圈子顶部板块格左侧竖线（.bd-cell i）
       · 帖子题目前的板块竖线（.pc-bdbar）
       · 右栏「热门板块」圆点（.aside-row .dot）
     改颜色只动这一处。
     🚨 帆哥 2026-09-21 反馈：首页与圈子的竖线颜色不一样 —— 根因是首页走的是
     这一组渐变、圈子走的是另一套纯色（#4A5BAE / #C08A2A / …）。以首页为准收敛。 */
  --bd-blue:   linear-gradient(135deg, #4A5BF0, #22B8E6);
  --bd-indigo: linear-gradient(135deg, #7C5CFF, #4A5BF0);
  --bd-amber:  linear-gradient(135deg, #FFB020, #FF8A3D);
  --bd-teal:   linear-gradient(135deg, #22B8E6, #12C9B4);
  --bd-rose:   linear-gradient(135deg, #FF6BA6, #FF4D8D);
  --bd-slate:  linear-gradient(135deg, #98A3BB, #6C7996);
  --bd-gold:   linear-gradient(135deg, #D9B871, #B08A3E);
}

/* 底色：一层很淡的蓝紫渐变。fixed 是为了长列表滚动时不会跑出第二遍渐变 */
body {
  background: linear-gradient(165deg, #E3EAFF 0%, #F3F6FF 44%, #EDE8FF 100%) fixed;
}

/* ---------- ② 顶栏 / 底栏：深蓝 → 浅色玻璃 ---------- */
.topbar, .topbar.navy {
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid rgba(19, 26, 46, .06);
  color: var(--ink);
  box-shadow: none;
}
.topbar .tb-title { color: var(--ink); }
.tabbar {
  background: rgba(255, 255, 255, .90);
  backdrop-filter: saturate(180%) blur(16px);
  border-color: rgba(255, 255, 255, .7);
}
.tab { color: var(--ink-3); }
.tab.active { color: var(--brand); }
.tab .pub-circle, .tab-pub .pub-circle {
  background: linear-gradient(120deg, var(--brand), var(--violet));
  box-shadow: 0 8px 20px rgba(74, 91, 240, .4);
}

/* ---------- 返回顶部浮动按钮（2026-09-21 帆哥要求） ----------
   下滑超过两屏才浮现，点一下平滑回到最顶部。
   隐藏用 opacity + visibility（不用 display）—— 这样 transform 过渡能生效，
   按钮是「淡入 + 上浮」而不是硬闪。元素由 app.js 的 initBackTop() 建一次挂在
   <body> 上，不受 render 换页影响。 */
.back-top {
  position: fixed; z-index: 68; right: 14px;
  /* 抬到底部 tabbar（58px）上面，留 16px 呼吸 */
  bottom: calc(76px + env(safe-area-inset-bottom) + 16px);
  width: 40px; height: 40px; padding: 0;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, .92);
  border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .88);
  backdrop-filter: saturate(180%) blur(14px);
  color: var(--brand);
  box-shadow: 0 6px 18px rgba(19, 26, 46, .13), 0 1px 3px rgba(19, 26, 46, .07);
  opacity: 0; visibility: hidden; transform: translateY(10px) scale(.9);
  transition: opacity .22s ease, transform .22s ease, visibility .22s;
  -webkit-tap-highlight-color: transparent;
}
.back-top.on { opacity: 1; visibility: visible; transform: none; }
.back-top:hover { color: var(--brand-600); }
.back-top:active { transform: scale(.92); }
.back-top svg { width: 19px; height: 19px; display: block; }
/* 帖子详情页（移动端）底部还有一条贴底的评论输入条，约 56px 高 ——
   按钮必须再抬一层，否则正好被它盖住（帆哥看不到按钮还以为没做） */
.back-top.above-composer { bottom: calc(76px + env(safe-area-inset-bottom) + 72px); }
/* 桌面端（≥900px）没有 tabbar 也没有贴底评论条，贴右下角就行 */
@media (min-width: 900px) {
  .back-top { right: 26px; bottom: 30px; }
  .back-top.above-composer { bottom: 30px; }
}

/* ---------- ③ 左栏导航：玻璃化 + 胶囊选中态 ---------- */
.brand-mark {
  background: transparent;
  box-shadow: none;
  border-radius: 0;
}
.brand-mark img { width: 100%; height: 100%; }
.nav-cta {
  height: 42px; border: none; border-radius: 999px;
  background: linear-gradient(120deg, var(--brand), var(--violet));
  box-shadow: 0 10px 22px rgba(74, 91, 240, .24);
}
.nav-cta:hover { transform: none; box-shadow: 0 12px 26px rgba(74, 91, 240, .3); }
.nav-item { border-radius: 999px; }
.nav-item.active {
  background: rgba(255, 255, 255, .92);
  color: var(--brand);
  font-weight: 750;
  box-shadow: 0 6px 16px rgba(74, 91, 240, .14);
}
.nav-item.active .ico { opacity: 1; }

/* ---------- ④ 三列布局 ---------- */
.col-aside { display: none; }                    /* 手机/平板：右栏没地方放 */
@media (min-width: 900px) {
  .shell {
    grid-template-columns: 216px minmax(0, 1fr);
    max-width: 1180px;
    gap: 0 22px;
  }
}
@media (min-width: 1100px) {
  .shell {
    grid-template-columns: 200px minmax(0, 1fr) 272px;
    max-width: 1284px;
  }
  .col-aside {
    display: block;
    position: sticky; top: 0;
    max-height: 100vh; overflow-y: auto;
    padding: 22px 0 40px;
    scrollbar-width: none;
  }
  .col-aside::-webkit-scrollbar { display: none; }
}
@media (min-width: 1400px) {
  /* 大屏不再加宽侧栏 —— 方案三是固定三列，内容列吃满剩余空间 */
  .shell { max-width: 1340px; }
}

/* ---------- ⑤ 右栏卡片 ---------- */
.aside-me {
  display: flex; align-items: center; gap: 11px;
  padding: 15px 16px; margin-bottom: 14px; cursor: pointer;
  background: var(--glass); backdrop-filter: blur(14px);
  border: 1px solid var(--glass-brd); border-radius: var(--r-md);
  box-shadow: 0 14px 34px rgba(74, 91, 240, .12);
}
.aside-me .am-tx { flex: 1; min-width: 0; }
.aside-me .am-name { font-size: 15.5px; font-weight: 780; color: var(--ink); }
.aside-me .am-meta {
  font-size: 11px; color: var(--ink-3); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.aside-me .am-pts { text-align: right; flex: none; }
.aside-me .am-pts b {
  display: block; font-size: 20px; font-weight: 800; line-height: 1.1;
  background: linear-gradient(120deg, var(--brand), var(--violet));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.aside-me .am-pts span { font-size: 10.5px; color: var(--ink-3); }
.aside-card {
  background: var(--glass); backdrop-filter: blur(14px);
  border: 1px solid var(--glass-brd); border-radius: var(--r-md);
  padding: 15px 16px; margin-bottom: 14px;
  box-shadow: 0 14px 34px rgba(74, 91, 240, .12);
}
.aside-card .ac-head { display: flex; align-items: center; margin-bottom: 10px; }
.aside-card .ac-head b { font-size: 13.5px; font-weight: 780; color: var(--ink); }
.aside-card .ac-more { margin-left: auto; font-size: 11px; color: var(--brand); font-weight: 650; cursor: pointer; }
.aside-row { display: flex; align-items: center; gap: 9px; padding: 7px 0; cursor: pointer; }
.aside-row .ar-name {
  font-size: 12.5px; color: var(--ink-2); font-weight: 600;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.aside-row .ar-num { margin-left: auto; font-size: 12.5px; font-weight: 750; color: var(--brand); flex: none; }
.aside-card .rank-row { padding: 6px 0; }
.aside-card .rank-name { font-size: 12.5px; color: var(--ink-2); }
.aside-card .rank-pts { font-size: 12.5px; font-weight: 780; color: var(--ink); }

/* 色点：一套渐变，频道格与右栏共用（原来是同一色系单色方块） */
/* 板块色已收敛到 .bd-cell 那一处的「唯一事实来源」块（--bd-* 变量），
   这里只留几何：右栏热门板块的小圆点。 */
.aside-row .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; display: block; background: var(--brand); }

/* ---------- ⑥ 首页 hero：深蓝卡 → 透明底 + 色斑 ---------- */
.hero {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  color: var(--ink);
  padding: 6px 4px 4px;
}
.hero::before, .hero::after { display: none; }   /* 旧的深蓝径向光斑 */
.hero-glow {
  position: absolute; right: -40px; top: -60px;
  width: 320px; height: 260px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 50% 50%, rgba(124, 92, 255, .16), rgba(124, 92, 255, 0) 70%);
}
.hero-glow::after {
  content: ''; position: absolute; left: -250px; top: 130px;
  width: 220px; height: 180px; border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(34, 184, 230, .14), rgba(34, 184, 230, 0) 70%);
}
.hero-hello { font-size: 30px; font-weight: 820; letter-spacing: -.025em; color: var(--ink); margin-bottom: 0; }
.hero-desc { font-size: 13.5px; color: var(--ink-2); line-height: 1.75; margin: 9px 0 18px; }
.hero-search {
  height: 48px; padding: 0 18px; border-radius: 999px;
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, .95);
  box-shadow: 0 12px 30px rgba(74, 91, 240, .12);
}
.hero-search svg { color: var(--brand); }
.hero-search input { color: var(--ink); font-size: 13px; }
.hero-search input::placeholder { color: var(--ink-3); }

/* 搜索提交按钮（2026-09-21）：帆哥反馈「输入完只能在输入法键盘上点回车（火车箭）才搜」。
   首页 hero 的搜索框和圈子顶部搜索条各加一个。共用一个类，靠容器调尺寸，
   右侧用负 margin 把按钮压到和容器内边距贴合（容器是 999px 药丸，按钮也是药丸）。 */
.sbtn {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  border: none; cursor: pointer; font-family: inherit;
  border-radius: 999px; background: var(--brand); color: #fff;
  font-size: 13px; font-weight: 700; letter-spacing: .02em;
  transition: background .16s ease, transform .12s ease;
}
.sbtn:hover { background: var(--brand-600); }
.sbtn:active { transform: scale(.95); }
.hero-search .sbtn { height: 34px; padding: 0 16px; margin-right: -9px; box-shadow: 0 4px 12px rgba(10, 90, 168, .26); }
.home-search .sbtn { height: 26px; padding: 0 13px; margin-right: -7px; font-size: 12.5px; }
/* 统计条：四格等分、每格文字居中（2026-09-20 反馈：原来左对齐显得重心偏左）。
   分隔线仍落在格子左边界上，第一个格子不画线。 */
.hero-stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0; margin-top: 20px; border-top: none; padding-top: 0;
}
.hero-stat { text-align: center; padding: 2px 0; border-left: 1px solid rgba(19, 26, 46, .1); }
.hero-stat:first-child { border-left: none; }
.hero-stat b { font-size: 23px; font-weight: 780; color: var(--ink); letter-spacing: -.03em; line-height: 1.15; }
.hero-stat b.gold {
  background: linear-gradient(120deg, var(--brand), var(--cyan));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero-stat span { font-size: 11px; color: var(--ink-3); letter-spacing: 0; }

/* ---------- ⑦ 频道格：玻璃卡 + 色条 + 右图 ---------- */
.section-head h2 { font-size: 15px; }
.channel-grid { gap: 10px; }
/* 高度收紧（2026-09-20 反馈：原来 50px 图 + 12/14px 内边距显得臃肿）：
   图 50→40、内边距 12/14→8/11、行高压到 1.25/1.4，单卡约 74px→58px */
.ch-cell {
  gap: 10px; padding: 8px 11px;
  background: var(--glass); backdrop-filter: blur(14px);
  border: 1px solid var(--glass-brd); border-radius: var(--r-md);
  box-shadow: var(--glass-sh);
}
.ch-cell:hover { transform: translateY(-1px); }
.ch-cell .cn { font-size: 13.5px; font-weight: 740; color: var(--ink); gap: 7px; line-height: 1.25; }
/* 色点改回小竖条（2026-09-20 反馈：竖条比圆点好看，也更贴频道语义）
   圈子板块格跟着同一尺寸 —— 两页竖线必须一样宽一样高，否则「一个颜色」的
   统一只做了一半。 */
.ch-cell .cn i, .bd-cell i { width: 3.5px; height: 14px; border-radius: 2px; }
.ch-cell .ci { font-size: 11px; color: var(--ink-3); margin-top: 2px; line-height: 1.4; }
.ch-cell .ct { width: 40px; height: 40px; border-radius: 13px; }

/* ---------- ⑧ 帖表：方案二「通栏大图」+ 方案三玻璃卡 ---------- */
.feed-card {
  background: var(--glass); backdrop-filter: blur(14px);
  border: 1px solid var(--glass-brd); border-radius: var(--r-lg);
  padding: 2px 18px;
  box-shadow: 0 12px 32px rgba(74, 91, 240, .09);
}
.feed-row {
  display: block; padding: 16px 0; min-width: 0;
  border-bottom: 1px solid rgba(19, 26, 46, .06);
}
.feed-row:last-child { border-bottom: none; }
/* 题目行：左「板块色竖线」+ 右两行截断的标题文字。
   🚨 2026-09-21 加竖线时必须拆成两层：原来 .fr-title 自己就是
   `display:-webkit-box` + `-webkit-box-orient: vertical` 做两行截断，
   而**这种盒子里任何子元素都会被当成一整行**竖着叠 —— 竖线会跑到题目正上方，
   还占掉「两行」额度里的第一行。所以外层换成 flex 只放竖线，
   -webkit-box 那套截断只留给内层 .fr-title-tx。 */
.fr-title {
  display: flex; align-items: flex-start; gap: 7px;
  min-width: 0; font-size: 15px; font-weight: 700; line-height: 1.45; color: var(--ink);
}
.fr-title .fr-title-tx {
  min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; white-space: normal;
}
/* 竖线在门户列表里是 flex 子项：高度跟着标题字号走（1em），
   .22em 的上边距让它对准第一行文字的视觉中心。 */
.fr-title .pc-bdbar { height: 1em; margin-top: .22em; }
.fr-badge { margin-bottom: 6px; }
.fr-ex {
  margin-top: 4px; font-size: 12.5px; line-height: 1.6; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fr-media { margin-top: 10px; border-radius: 16px; overflow: hidden; background: rgba(19, 26, 46, .04); }
.fr-media img { width: 100%; display: block; object-fit: cover; }
.fr-media.single img { aspect-ratio: 16 / 9; }
.fr-media.n2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3px; }
.fr-media.n3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 3px; }
.fr-media .fm-cell { position: relative; overflow: hidden; min-width: 0; }
.fr-media:not(.single) .fm-cell img { aspect-ratio: 1 / 1; }
.fr-media .fm-more {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(8, 21, 44, .5); color: #fff; font-size: 15px; font-weight: 700;
}
.fr-foot {
  margin-top: 10px; display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--ink-3); min-width: 0;
}
.fr-foot .fr-av { flex: none; }
.fr-foot .fr-av.off {
  width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; flex: none;
  font-size: 10px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--brand), var(--violet));
}
.fr-foot .fr-who { font-weight: 650; color: var(--ink-2); flex: none; }
.fr-foot .fr-dept { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 2026-09-21 第九轮：作者名与部门之间的「·」已撤掉（帆哥要求只留空格），
   间距由 `.fr-foot` 的 gap 提供（PC 6px / 手机 5px），这里不再需要任何分隔符样式。
   `.fr-sep` 规则整条删除，避免留着一条永远不命中的死规则。 */
.fr-foot .fr-sp { margin-left: auto; display: flex; gap: 11px; align-items: center; flex: none; }
.fr-foot .fr-sp i { font-style: normal; display: flex; align-items: center; gap: 3px; }
.fr-foot .fr-sp svg { width: 13px; height: 13px; }
.fr-foot .fr-like.on { color: var(--brand); }
.fr-foot .fr-when { font-variant-numeric: tabular-nums; }

/* ---------- ⑨ 手机端：同一套方案，尺寸降一档 ---------- */
@media (max-width: 899px) {
  .hero { padding: 4px 2px 0; }
  .hero-hello { font-size: 25px; }
  .hero-desc { font-size: 12.5px; margin: 7px 0 13px; }
  .hero-search { height: 44px; padding: 0 16px; font-size: 12.5px; }
  .hero-stats { margin-top: 15px; }
  .hero-stat b { font-size: 18px; }
  .hero-stat span { font-size: 9.5px; }
  .channel-grid { gap: 9px; }
  .ch-cell { padding: 7px 10px; gap: 9px; border-radius: 14px; }
  .ch-cell .cn { font-size: 13px; gap: 6px; }
  .ch-cell .ci { font-size: 10.5px; margin-top: 2px; }
  .ch-cell .ct { width: 34px; height: 34px; border-radius: 11px; }
  .feed-card { padding: 0 13px; border-radius: 22px; }
  .feed-row { padding: 13px 0; }
  .fr-title { font-size: 15.5px; }
  /* 帆哥 2026-09-22：首页摘要与圈子卡摘要（.pc-body 14.5px / --ink-2 / 1.7）对齐 */
  .fr-ex { font-size: 14.5px; color: var(--ink-2); line-height: 1.7; }
  .fr-foot { font-size: 10.5px; gap: 5px; margin-top: 8px; }
  .fr-foot .fr-sp { gap: 9px; }
}
@media (max-width: 380px) {
  .hero-stat b { font-size: 16px; }
  .ch-cell .ct { width: 32px; height: 32px; border-radius: 10px; }
  .fr-title { font-size: 15px; }
}

/* 产品帖在首页的图片带：原来的 46px 缩略图在通栏大图的语境下太寒酸，放大一档 */
.feed-row .pd-strip.sm .pd-track img { width: 64px; height: 64px; border-radius: 12px; }
@media (max-width: 899px) {
  .feed-row .pd-strip.sm .pd-track img { width: 58px; height: 58px; border-radius: 11px; }
}

/* 头像尺寸兜底：avatar(user, N) 拼出的类名是 .avatar.sN，而尺寸类只定义了
   24/28/30/32/36/40/44/48/64/72/96 这几档 —— 传 46 或 20 就没有任何尺寸约束，
   头像会按内容撑开（线上实测 .aside-me 的头像撑到 192x192，把姓名挤成 0 宽）。
   这里用后代选择器直接定尺寸，不依赖类名是否存在。 */
.aside-me .avatar { width: 46px; height: 46px; font-size: 17px; }
.feed-row .fr-foot .avatar { width: 20px; height: 20px; font-size: 10px; }


/* ============================================================
   产品档案卡（2026-09-20 晚）—— 本段是覆盖层，必须留在文件最后。
   ------------------------------------------------------------
   帆哥的原话：「不要以内容的形式显示，默认和普通内容贴显示风格不一样，
   特别是写了那么多产品参数，看上去就和一个混乱的内容贴一样」。
   做法：参数走格子（标签在上、值在下），卖点走带序号的条块，整体包在
   一张浅金描边的档案卡里 —— 跟普通正文一眼分开。
   手机 390px 下每格约 167px，「店铺券前价」5 字和「TS2616Z99-001」
   都放得下，不用横向滚动。要回滚整段删掉即可。 */
.pfile {
  margin: 2px 0 16px; padding: 13px 13px 15px;
  border-radius: 14px;
  border: 1px solid rgba(200, 161, 90, .30);
  background: linear-gradient(180deg, #FDFBF6, #FFFDFA);
}
.pfile-hd {
  display: flex; align-items: center; gap: 7px; margin-bottom: 11px;
  font-size: 12.5px; font-weight: 800; letter-spacing: .08em; color: #8A6415;
}
.pfile-hd i {
  width: 3.5px; height: 13px; border-radius: 2px;
  background: var(--gold); flex: none;
}
/* 第四轮改 flex-wrap：成对组要「自己独占一整行」（与列数无关），单个字段
   独占一行时又要自动撑满 —— 这两件事 grid 都做不到（会留半格空洞）。 */
.pfile-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.pf-cell {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
  padding: 8px 11px 9px; border-radius: 10px;
  background: #fff; border: 1px solid var(--line);
}
.pf-k { font-size: 11px; color: var(--faint); line-height: 1.3; }
.pf-v {
  font-size: 14px; font-weight: 700; color: var(--ink); line-height: 1.45;
  word-break: break-word; overflow-wrap: anywhere;
}
.pfile-sub {
  margin: 14px 0 9px; padding-top: 12px;
  font-size: 12.5px; font-weight: 800; letter-spacing: .08em; color: #8A6415;
  border-top: 1px dashed rgba(200, 161, 90, .42);
}
.pfile-sells {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 9px;
}
.pfile-sells li { display: flex; gap: 9px; align-items: flex-start; }
.pf-n {
  flex: none; width: 19px; height: 19px; margin-top: 2px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--gold-050); color: #8A6415;
  font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums;
  box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .38);
}
.pf-t { font-size: 14.5px; line-height: 1.7; color: var(--ink-2); }
/* （2026-09-21 第四轮）原「760px 以上改三列」已废弃 —— .pfile-grid 改成
   flex-wrap 之后列数失去意义（单字段恒占半行、成对组恒占整行），
   三列反而会把包装袋(第6) / 上架渠道(第7) 甩到两行去。 */
/* 很窄的手机（<340px）把格子内边距收一点，避免「店铺券前价」被压成两行 */
@media (max-width: 340px) {
  .pf-cell { padding: 7px 8px 8px; }
  .pf-v { font-size: 13px; }
}

/* 「产品卖点」标题后面的小圆圈 +（帆哥要求：跟前面的文字差不多大）。
   原来是跟在最后一条卖点输入框右侧，现在固定挂在标题上。 */
.sell-plus {
  width: 19px; height: 19px; margin-left: 7px; padding: 0;
  border-radius: 50%; border: 1.5px solid var(--hair);
  background: var(--surface-2); color: var(--ink-3);
  display: inline-grid; place-items: center; vertical-align: -4px;
  transition: .16s; cursor: pointer;
}
.sell-plus svg { width: 11px; height: 11px; }
.sell-plus:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-050); }

/* ===========================================================
   相册「按时间 / 按部门」（2026-09-20）
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚整段删掉即可。

   首页相册区改成两个视角（按时间 = 年份，按部门 = 部级部门），
   卡片统一成「圆角正方形」：上面一块缩略图、下面一条文字（年份+张数 / 部门名+张数）。

   尺寸取舍：帆哥说「上方五分之四放图，下面放文字」。文字要竖着放两行
   （主文案 + 「N 张」），13px + 10px 行高 1.15 至少需要 30px，再压就截字。
   所以 108px 的卡片里图区 78px（约 3/4）、文字区 30px —— 图仍占绝对主体，
   但没有为了凑 4/5 而让文字被裁。PC 上卡片放大到 124px。
   =========================================================== */

/* 首页：按时间 / 按部门 切换条 */
.album-tabs { display: flex; gap: 6px; margin: 10px 0 11px; }
.album-tab {
  height: 28px; padding: 0 14px; border-radius: 999px;
  display: inline-flex; align-items: center;
  font-size: 12.5px; font-weight: 600; color: var(--ink-3);
  background: var(--surface-2); border: 1px solid transparent;
  cursor: pointer; user-select: none; transition: .16s;
}
.album-tab:hover { color: var(--brand); }
.album-tab.on { background: var(--brand); color: #fff; box-shadow: var(--sh-1); }

/* 卡片条（横滑） */
.tile-strip { display: flex; gap: 10px; overflow-x: auto; padding: 2px 0 4px; }
.tile-strip::-webkit-scrollbar { display: none; }
.ktile {
  flex: none; width: 108px; height: 108px;
  display: flex; flex-direction: column;
  border-radius: 14px; overflow: hidden; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--sh-1); transition: .16s;
}
.ktile:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--sh-2); }
.kt-img {
  flex: 1 1 auto; min-height: 0; overflow: hidden; position: relative;
  background: linear-gradient(135deg, var(--brand-050), var(--surface-2));
}
.kt-img img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  opacity: 0; transition: opacity .3s;
}
.kt-img img.ok { opacity: 1; }
.kt-tx {
  /* 高度按「两行文字 + 上下各 ~4px 呼吸」定：实测 34px 时文字底距卡底只剩 3.5px，
     截图缩放过一遍就像被裁掉半行。宁可少 2px 图，也别让文字贴边。 */
  flex: none; height: 34px; padding: 0 8px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  line-height: 1.12; text-align: center;
}
.kt-tx b {
  font-size: 13px; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 部门名比「2026」长得多（最长「文创百货研发部」7 字），小一号才放得下 */
.kt-tx b.nm { font-size: 11.5px; font-weight: 700; }
.kt-tx span { font-size: 10px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

@media (min-width: 760px) {
  .ktile { width: 124px; height: 124px; border-radius: 16px; }
  .kt-tx { height: 37px; }
  .kt-tx b { font-size: 14px; }
  .kt-tx b.nm { font-size: 12.5px; }
  .kt-tx span { font-size: 10.5px; }
}

/* ============================================================
   相册页顶部筛选（按时间 / 按部门）—— 2026-09-21 重新设计
   ------------------------------------------------------------
   帆哥反馈：「这两排按钮设计的不好看、不精美，重新设计，精美大气，
   但不要很大，注意手机幅，要精巧」。
   改前：chip 33px 高、13.5px 字、左右各 14px 内边距，两行裸排在页面底色上，
        390px 手机上一行只放得下 4 个，又高又壮。
   改后：① 两行收进一张浅色玻璃卡，跟页面底色分层 —— 看起来是一块「筛选器」
              而不是两排散落的药丸
        ② chip 压到 27px 高 / 12.5px 字 / 左右 12px，圆角关系不变
        ③ 左侧标签配一条 3px 渐变色条（时间=蓝、部门=青），维度一眼可辨
        ④ 横滑区右缘加渐隐，暗示「后面还有」
   整块（含 2px 边框）实测收在 79px 内；27px 仍是稳妥的可点高度（手指点得准）。
   ⚠️ 只作用于 .gal-filter 内，admin 页那批 .chip 不受影响（那边是桌面工具，尺寸另论）。
   ============================================================ */
.gal-filter {
  padding: 9px 12px 8px; margin-bottom: 11px;
  border-radius: 18px;
  background: rgba(255, 255, 255, .74);
  border: 1px solid rgba(255, 255, 255, .92);
  box-shadow: 0 6px 20px rgba(74, 91, 240, .07), 0 1px 2px rgba(19, 26, 46, .03);
}
.filter-row { display: flex; align-items: center; gap: 9px; }
.filter-row + .filter-row { margin-top: 6px; }
.filter-label {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 700; color: var(--ink-2);
  letter-spacing: .02em; white-space: nowrap;
}
/* 维度色条：复用板块色变量（--bd-*），跟全站「彩色小竖条 = 分类」的视觉语言一致 */
.filter-label::before {
  content: ''; width: 3px; height: 12px; border-radius: 2px; background: var(--bd-blue);
}
.filter-row.dept .filter-label::before { background: var(--bd-teal); }
.filter-row .chips-scroll {
  flex: 1; min-width: 0; padding: 0; gap: 6px;
  /* 右缘渐隐：提示还能往左滑。手机上必然溢出；桌面上即使不溢出，
     这 5% 的淡出也看不出来，不用再按断点分叉。
     2026-09-21 实测 10% 会把一整个 chip 压暗（像渲染坏了），收到 5% 刚好。 */
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 95%, transparent 100%);
  mask-image: linear-gradient(90deg, #000 0, #000 95%, transparent 100%);
}
.gal-filter .chip {
  display: inline-flex; align-items: center;
  height: 27px; padding: 0 12px; border-radius: 999px;
  border: 1px solid rgba(19, 26, 46, .07);
  background: rgba(255, 255, 255, .94);
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(19, 26, 46, .04);
  transition: .15s; cursor: pointer;
}
.gal-filter .chip:hover { border-color: rgba(74, 91, 240, .38); color: var(--brand-ink); }
.gal-filter .chip.on {
  background: linear-gradient(135deg, var(--brand), var(--violet));
  border-color: transparent; color: #fff; font-weight: 700;
  box-shadow: 0 4px 12px rgba(74, 91, 240, .28);
}
/* 交叉筛选下该组合没有照片：仍然可点（点了会看到空状态提示），但先置灰 */
.chip.zero { opacity: .42; }



/* ============================================================
   产品档案格：一行显示 + 价格红字（2026-09-20 深夜 · 帆哥第二轮反馈）
   ------------------------------------------------------------
   原样是「灰标签一行 + 黑值一行」，格子偏高、参数一多整张卡就显得散。
   现在标签和值同一行、字号统一（取原来灰标签那一档 12px），价格用红字挑出来。
   ⚠️ 判据是「值以 ¥ 开头」（见 app.js prodFileHtml），不是「键名带价字」——
      「定制价 / 无」也带价字，但红起来毫无意义。
   本段与上面的档案卡样式同属覆盖层，必须留在文件最后。
   `.pf-k` 不换行、`.pf-v` 可换行：标签最多 5 个字，值里可能有
   「BH24701001-001」这种长编码，窄屏上宁可值折一行，也不能把标签压断。
   ============================================================ */
.pf-cell { flex-direction: row; align-items: baseline; gap: 7px; padding: 8px 10px; }
.pf-k { flex: none; font-size: 12px; white-space: nowrap; }
.pf-v { flex: 1; min-width: 0; font-size: 12px; font-weight: 620; line-height: 1.55; }
.pf-v.is-price { color: #D8362B; font-weight: 760; }
.pf-cell.is-price { border-color: rgba(216, 54, 43, .22); }

/* ============================================================
   投票模块（2026-09-20 深夜 · 帆哥要求「活动板块再加一个发起投票」）
   ============================================================ */

/* 活动 / 投票 两个 Tab。做成胶囊分段器而不是标签下划线：
   和站内其它圆角胶囊元素（按钮、tag、频道格）同一套语言，看着更年轻。 */
.seg-tabs { display: flex; gap: 8px; margin: 0 0 14px; }
.seg {
  height: 34px; padding: 0 15px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--glass-brd); background: var(--glass); backdrop-filter: blur(14px);
  font-size: 13.5px; font-weight: 650; color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 6px; transition: .16s;
}
.seg:hover { color: var(--ink); transform: translateY(-1px); }
.seg.on {
  background: linear-gradient(135deg, var(--brand), var(--violet));
  border-color: transparent; color: #fff;
  box-shadow: 0 8px 18px rgba(74, 91, 240, .28);
}
.seg-n { font-size: 11px; opacity: .8; font-variant-numeric: tabular-nums; }
.acts-head { flex-wrap: wrap; }

/* 卡片之间要有间距 —— .card 本身没有 margin，直接拼会贴在一起 */
.stack { display: flex; flex-direction: column; gap: 12px; }

/* ---------- 活动页的投票卡 ---------- */
.poll-card { padding: 15px 16px; display: block; cursor: pointer; transition: .16s; }
.poll-card:hover { transform: translateY(-1px); box-shadow: var(--sh-2); }
.pc-hd { display: flex; align-items: flex-start; gap: 10px; }
.pc-ico {
  flex: none; width: 34px; height: 34px; border-radius: 11px;
  display: grid; place-items: center; color: #fff;
  background: linear-gradient(135deg, var(--brand), var(--cyan));
}
.pc-ico svg { width: 17px; height: 17px; }
.pc-tt { min-width: 0; flex: 1; }
.pc-title { font-size: 15px; font-weight: 720; color: var(--ink); line-height: 1.42; }
.pc-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 6px; font-size: 11.5px; color: var(--ink-3);
}

/* 状态小标签。比 .tag 更小一号，用在卡片的元信息行里不抢戏 */
.kr-tag { padding: 1.5px 8px; border-radius: 999px; font-size: 11px; font-weight: 650; }
.kr-tag.ok { background: #E9F6EF; color: var(--ok); }
.kr-tag.gray { background: var(--surface-2); color: var(--ink-3); }
.kr-tag.blue { background: var(--brand-050); color: var(--brand-ink); }

/* ---------- 选项行（列表卡与详情页共用） ---------- */
.poll-opts { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.poll-opt {
  display: flex; gap: 9px; align-items: center;
  padding: 9px 11px; border-radius: 12px;
  background: #fff; border: 1px solid var(--line); transition: .15s;
}
.poll-opts.pickable { margin-top: 16px; gap: 10px; }
.poll-opts.pickable .poll-opt { cursor: pointer; padding: 12px 13px; }
.poll-opts.pickable .poll-opt:hover { border-color: var(--brand); background: var(--brand-050); }
.poll-opt.on {
  border-color: var(--brand); background: var(--brand-050);
  box-shadow: inset 0 0 0 1px rgba(74, 91, 240, .35);
}
/* 勾选框：单选多选都用圆框 —— 圆形跟站内头像、序号牌一致，
   方的（checkbox）在这套圆角语言里显得突兀，而且选项本来就不多。 */
.po-box {
  flex: none; width: 19px; height: 19px; border-radius: 50%;
  border: 1.5px solid var(--hair); background: #fff;
  display: grid; place-items: center; color: #fff; transition: .15s;
}
.po-box svg { width: 11px; height: 11px; }
.poll-opt.on .po-box { background: var(--brand); border-color: var(--brand); }
.po-main { flex: 1; min-width: 0; }
.po-line { display: flex; align-items: baseline; gap: 10px; }
.po-text { font-size: 13.5px; font-weight: 600; color: var(--ink-2); word-break: break-word; }
.poll-opt.on .po-text { color: var(--brand-ink); }
.po-num {
  margin-left: auto; flex: none; font-size: 11.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.po-bar { margin-top: 6px; height: 6px; border-radius: 999px; background: rgba(19, 26, 46, .07); overflow: hidden; }
.po-bar i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--brand), var(--cyan));
  transition: width .3s ease;
}
.poll-opt.on .po-bar i { background: linear-gradient(90deg, var(--brand-600), var(--violet)); }
.po-more { font-size: 11.5px; color: var(--ink-3); text-align: center; padding-top: 2px; }

/* ---------- 投票详情 ---------- */
.poll-tags { flex-wrap: wrap; gap: 8px; }
.poll-actions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 15px; border-top: 1px solid var(--line);
}
.poll-hint { margin-top: 10px; font-size: 12px; color: var(--ink-3); }
.voter-grid { display: flex; flex-wrap: wrap; gap: 10px 16px; }
.voter { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-2); }
.voter .avatar { width: 28px; height: 28px; font-size: 11px; }

/* ---------- 发起投票表单 ---------- */
.opt-list { display: flex; flex-direction: column; gap: 9px; margin-bottom: 10px; }
.opt-row { display: flex; align-items: center; gap: 9px; }
.opt-n {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 750; font-variant-numeric: tabular-nums;
  background: var(--brand-050); color: var(--brand-ink);
}
.opt-row .input { flex: 1; min-width: 0; }
.opt-rm {
  flex: none; width: 30px; height: 30px; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--line); background: #fff; color: var(--ink-3);
  font-size: 17px; line-height: 1; padding: 0;
}
.opt-rm:hover { color: var(--danger); border-color: #EED9D6; background: #FCF3F2; }
/* 「N 票」小标：只在「修改投票」时出现（编辑一条已经有人投过的投票）。
   它不是装饰 —— 是「这个选项不能删」的可见依据，所以做成一眼能认出的状态标记
   （米金色药丸），而不是一行灰色说明。删除键同步做成禁用态，
   免得发起人点了半天才发现删不掉。 */
.opt-votes {
  flex: none; display: inline-flex; align-items: center;
  padding: 3px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--gold-050); color: #8A6415;
  border: 1px solid rgba(200, 161, 90, .34);
}
.opt-row.has-votes .input { background: #FFFDF7; }
.opt-row.has-votes .opt-rm {
  color: var(--faint); border-color: var(--line); background: var(--surface-2);
  cursor: not-allowed;
}
@media (max-width: 430px) {
  .opt-votes { padding: 3px 7px; font-size: 11px; }
}
.opt-add { margin-top: 2px; }
.radio-row { display: flex; gap: 18px; align-items: center; min-height: 40px; }
.radio-row label { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; color: var(--ink-2); cursor: pointer; }

/* ---------- 首页「最新动态」里的活动 / 投票卡 ---------- */
.kr-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2.5px 10px 2.5px 8px; border-radius: 999px; margin-bottom: 7px;
  font-size: 11px; font-weight: 750; letter-spacing: .02em;
}
.kr-badge svg { width: 12px; height: 12px; }
.kr-badge.act { background: rgba(74, 91, 240, .10); color: var(--brand-ink); }
.kr-badge.poll { background: rgba(34, 184, 230, .16); color: #0C6E8A; }
.kr-meta { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 7px; font-size: 12px; color: var(--ink-2); }
.kr-meta .kr-i { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.kr-meta .kr-i svg { width: 13px; height: 13px; color: var(--ink-3); flex: none; }
.kr-foot {
  margin-top: 10px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--ink-3);
}
.kr-foot b { color: var(--brand-600); font-variant-numeric: tabular-nums; }
.kr-foot .kr-go { margin-left: auto; font-weight: 700; color: var(--brand-600); white-space: nowrap; }
.kind-row .poll-opts { margin-top: 10px; }
.kind-row .fr-media { margin-top: 10px; }

/* ---------- 手机端降一档 ---------- */
@media (max-width: 899px) {
  .pf-cell { padding: 7px 9px; }
  .pf-k, .pf-v { font-size: 11.5px; }
  .poll-card { padding: 13px; }
  .pc-title { font-size: 14px; }
  .pc-ico { width: 30px; height: 30px; border-radius: 10px; }
  .pc-ico svg { width: 15px; height: 15px; }
  .poll-opt { padding: 8px 10px; }
  .poll-opts.pickable .poll-opt { padding: 11px 12px; }
  .po-text { font-size: 13px; }
  .kr-foot { font-size: 11px; gap: 6px; }
  .seg { height: 32px; padding: 0 13px; font-size: 13px; }
}


/* ============================================================
   手机端首页：撤掉品牌顶栏 + 品牌图形 logo 落位
   （2026-09-20 帆哥反馈，本段必须留在文件最后）
   ------------------------------------------------------------
   帆哥的原话：「手机端，顶部这个云帆圈子的横条可以不要，直接去掉，
   云帆的图形logo可以放在这个位置。这个调整仅限手机端。」

   ① 顶栏为什么可以撤
      那条横条上只有「logo + 站点名 + 铃铛」。手机上底部 tabbar 已经
      高亮当前位置，"云帆圈子"四个字再重复一遍没有信息量，却实打实
      占掉 56px 首屏 —— 用户一进来最想看到的是内容，不是自己的站名。

   ② 只撤「标题＝站点名」的那两页，别的一律保留
      判据用页面结构而不是标题文本（CSS 读不到文本）：
        · 首页 portal   → 有 .hero
        · 圈子列表 home → 有 .home-search
      其余页面（帖子详情、发帖、相册、频道、活动、我的、消息）的顶栏
      带返回键或真正的页面标题，撤了就没法返回，必须留。

   ③ logo 用 hero 的背景图画，不改 HTML
      本轮另一个会话正在大改 app.js（投票功能），两边同时改同一个文件
      必然互相覆盖，所以这里走纯 CSS，零依赖。
      位置对齐「晚上好，一帆」那一行 —— 帆哥给的参考图箭头就指在那儿。

      ⚠️ 一开始用 .hero::after 画，实测在这套样式里画不出来：
         CSSOM 里规则在（(max-width:899px) 上下文，display:block /
         width:36px / height:36px / background 都对），getComputedStyle
         也回报 block + 36px，但渲染层一片空白 —— 换成纯色底、换成
         非空 content 都照样不出。不纠结 quirk，改用 hero 自己的
         background-image 画：层级确定（在子元素之下、不会挡点击），
         也顺带绕开 .hero::before/::after 被上面 display:none 关掉这件事。

   ④ 图源仍用 star-128.png（11.6KB，第六轮由 star.png 512px 缩出）
      第七轮把显示尺寸还原回 36px 后，DPR2 实际需要 72px 源 —— star-64.png
      只有 64px，余量 0.89 倍会糊；star-128.png 有 3.56 倍余量，DPR2/DPR3
      都够，体积只比 64px 版多 6KB，比 512px 的 star.png 省 81KB。
      所以本轮**回退尺寸、不回退图源**。

   ⑤ :has() 需要 Chrome 105+ / Safari 15.4+。不支持时的表现是"
      回到改动前的样子"，不会错版 —— 属于优雅降级。
   ============================================================ */
@media (max-width: 899px) {
  /* 顶栏：手机端「标题＝站点名」的页面直接撤掉 */
  body:has(.hero) .topbar,
  body:has(.home-search) .topbar { display: none; }

  /* 顶栏撤掉后首屏上沿只剩 .col-main 自己的 padding。
     2026-09-21（第六轮）帆哥：「顶部那个浅色边可以小一多半，这样整体页面
     默认打开的时候会更靠上一些」→ 20px 收到 6px。
     首屏上沿总高 = 6px(这里) + 4px(.hero 自己的 padding-top) = 10px，
     原来是 24px，减掉 58%（「一多半」）。 */
  body:has(.hero) .col-main { padding-top: 6px; }

  /* 品牌图形 logo：画在 hero 右上角。
     background-position 的参照系是 **padding box**；hero 没有 border，
     padding-box 的上/右沿就等于 hero 盒子的上/右沿，不受 hero 自身 padding
     影响。所以「logo 距屏幕顶」= hero.getBoundingClientRect().y + top 值。

四轮轨迹（实测值，非估算）：
       · 第五轮及以前：36px，right 0 / top 0   → 距屏幕顶 24px、距屏幕右 14px
       · 第六轮：      46px，right 12px / top 22px → 距屏幕顶 28px、距屏幕右 26px
       · 第七轮：      36px，right 0 / top 18px    → 距屏幕顶 24px、距屏幕右 14px
                       （帆哥「logo 还是调整回去吧」→ 还原观感）
       · 第八轮（本次）：36px，right 0 / top 8px   → 距屏幕顶 14px、距屏幕右 14px
                       帆哥：「距离顶部不要 24px，改成 14px」→ 再上提 10px。

     ⚠️ 为什么 top 不是 0、也不是 14：第六轮把 .col-main 的上内边距从 20px
     收到 6px（帆哥认可，此后一直没动），所以
         「logo 距屏幕顶」= hero.y(恒为 6px) + top 值
     要落在 14px，top 就得取 8px —— **别照抄 14 这个数**。 */
  .hero {
    background-image: url(brand/star-128.png);
    background-repeat: no-repeat;
    background-position: right 0 top 8px;
    background-size: 36px 36px;
  }
}

/* 窄屏（≤520px）档案格改单列 ── 实测出来的硬约束，不是审美选择：
   390px 手机上格子只有 148px 宽，减去内边距只剩 130px；
   而「款式编码」标签就要 46px，值「XZ24401304-007」在 11.5px 下还有约 103px，
   两列怎么调都差 25px 以上（11px 字号 + 全部内边距压到最小，仍差 30px）。
   520px 以上两列是够的（内容宽 202px），所以只在这条线以下改单列。
   单列后标签在左、值右对齐，一屏一条，长编码再长也不会折行。 */
@media (max-width: 520px) {
  .pfile-grid { grid-template-columns: 1fr; gap: 6px; }
  .pf-cell { padding: 7px 11px; }
  .pf-k, .pf-v { font-size: 12px; }
  .pf-v { text-align: right; }
}

/* ============================================================
   投票选项配图（2026-09-20 帆哥需求，末尾追加覆盖层）
   两块各一套样式，别混：
     ① .opt-pic —— 「发起投票」表单里那个小方块
        未选图 = 虚线方框 + 图片图标（一眼看出「这里可以放图」）
        已选图 = 缩略图 + 右上角红点移除键
     ② .po-pic  —— 列表卡 / 详情页里，选项文字左侧的缩略图
   尺寸取 38 / 46px：再小就只剩一团色块，起不到「这个选项是干啥的」提示作用；
   再大则会把选项文字挤成两行 —— 手机上尤其明显。
   ============================================================ */
.opt-pic {
  flex: none; width: 38px; height: 38px; border-radius: 10px; cursor: pointer;
  display: grid; place-items: center; position: relative;
  border: 1px dashed var(--hair); background: #fff; color: var(--ink-3);
  transition: .15s;
}
.opt-pic:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-050); }
.opt-pic.on { border-style: solid; border-color: var(--line); }
.opt-pic.on img { width: 100%; height: 100%; border-radius: 9px; object-fit: cover; display: block; }
/* 移除键要压在方块外面（负偏移），所以父级不能 overflow:hidden */
.opt-pic-rm {
  position: absolute; top: -6px; right: -6px; width: 17px; height: 17px;
  border-radius: 50%; background: var(--danger); color: #fff; font-style: normal;
  font-size: 12px; line-height: 17px; text-align: center; cursor: pointer;
  box-shadow: 0 1px 4px rgba(19, 26, 46, .3);
}
/* 「如无需图片，请忽略图片上传」—— 跟「（至少 2 个，最多 20 个）」同排，
   但更轻，避免两句提示打架 */
.opt-note { margin-left: 7px; font-weight: 400; }

.po-pic {
  flex: none; width: 46px; height: 46px; border-radius: 11px;
  object-fit: cover; background: var(--surface-2);
}

/* 手机端：一条选项行要塞下 序号 + 图 + 输入框 + 删除键，
   不缩尺寸的话输入框只剩 200px 左右，40 字的选项会看不全。
   这里把序号和图各缩一档，给输入框腾出约 218px。 */
@media (max-width: 520px) {
  .opt-list { gap: 8px; }
  .opt-row { gap: 7px; }
  .opt-n { width: 18px; height: 18px; font-size: 10.5px; }
  .opt-pic { width: 34px; height: 34px; border-radius: 9px; }
  .opt-pic.on img { border-radius: 8px; }
  .opt-rm { width: 27px; height: 27px; font-size: 16px; }
  .po-pic { width: 40px; height: 40px; border-radius: 10px; }
}

/* ===========================================================
   2026-09-21 改版（帆哥 5 项反馈）
   ① 个人主页头部重排（手机端为主）
   ② 右栏「最新活动 / 最新投票」模块
   =========================================================== */

/* ---------- ① 个人主页头部 ----------
   旧版把结构写死在行内 style 上，行内优先级高于任何 CSS，媒体查询改不动，
   于是手机端只能沿用 PC 的 96px 头像 + 86px 色带，比例失衡；且姓名两行
   紧贴头像底部，色带分界线正好切在姓名上沿，深色字压深蓝底 → 帆哥说「乱」。
   现在换成语义类名，PC / 手机各一套尺寸。 */
.me-card { overflow: hidden; position: relative; }
/* 色带高度 88 → 53（帆哥 2026-09-24：改为原来的五分之三，整体有用信息上移）。
   ⚠️ .me-top 的负 margin 推导见下，色带变矮后头像更靠上但「姓名块顶 ≥ 色带底」
   的约束不受色带高度影响，仍然成立。 */
.me-band {
  height: 53px;
  background: linear-gradient(135deg, var(--brand), var(--brand-ink));
}
.me-body { padding: 0 22px 20px; }

/* 负 margin 的作用：把「姓名整块」推进白色区。
   姓名块顶部（相对卡片顶） = 色带高 − |margin-top| + 头像高 − 姓名块高
   要让姓名块顶部 ≥ 色带高，就得 |margin-top| ≤ 头像高 − 姓名块高。
     PC  ：头像 92+6 边框=98、姓名块 ≈ 49（20px 名 + 13px 部门 + 间距 + padding）
            → 取 42px，留 7px 余量。
     手机：头像 72+5=77、姓名块 ≈ 39 → 取 28px，留 10px 余量。
   ⚠️ 改字号或头像尺寸必须重算这个值，否则姓名又会压到渐变带上。
   验收脚本 v13_qa.js 会量「姓名块 top ≥ 色带底」来兜住这件事。 */
.me-top {
  display: flex; align-items: flex-end; gap: 14px;
  margin-top: -42px;
}
.me-av { flex: none; border: 3px solid #fff; border-radius: 50%; }
.me-av .avatar { width: 92px; height: 92px; font-size: 32px; }
/* padding-bottom: 0 —— 姓名块底边直接对齐头像底边。
   留 padding 的话（原来 5px）姓名块整体上抬，顶部离色带只剩 2px，看着局促；
   归零后 PC 距色带约 7px、手机约 6px，呼吸感够了，且仍在安全区内。 */
.me-id { flex: 1; min-width: 0; }
/* 姓名 + 部门并排（第 64 轮 · 帆哥：部门提到名字这一行，岗位职务独占第二行）。
   原来拼成「部门 · 职务」一行，职务一长整串都被省略号吞掉。 */
.me-name-row { display: flex; align-items: baseline; min-width: 0; }
/* flex:0 1 auto + max-width —— 名字优先完整（最多占七成），
   真超长时自己截断，绝不把部门挤成 0 宽、也不撑破 .me-id。 */
.me-name-row .me-name { flex: 0 1 auto; max-width: 70%; }
.me-name {
  font-size: 20px; font-weight: 700; line-height: 1.25; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 部门：跟在名字后面，字号收一档做出层级。
   🚨 中间的间隔点走 ::before，不写进 HTML —— 部门为空时整块不渲染，
      点自然也不出现（拼在字符串里就会剩一个孤零零的「·」）。 */
.me-dept {
  flex: 0 1 auto; min-width: 0;
  font-size: 13px; font-weight: 500; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.me-dept::before { content: '·'; margin: 0 7px 0 6px; opacity: .6; }
/* 岗位职务：独占第二行，不换行（帆哥要求）；过长走省略号 */
.me-meta {
  font-size: 13px; color: var(--ink-3); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.me-tags { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 14px; }
/* 「加入云帆的第 N 天」徽章（2026-09-24 · METAGS-JOIN，UI 方案 A 玻璃胶囊）：
   浮在色带右上角（JOINUI-A-R60 起改为 absolute 定位）。
   🚨 之前在 .me-top 行内参与 flex，会把「部门 · 职务」一行挤到只剩 69px
   （帆哥的「CEO」直接被省略号吞掉）——绝对定位后完全不占行内空间。
   数据没有（hiredAt 为空）就不渲染，不占位。
   半透明白 + 毛玻璃「长在」蓝色色带上，最不打架。 */
.me-join {
  position: absolute; top: 10px; right: 22px; z-index: 2;
  display: inline-flex; align-items: center; gap: 4px;
  height: 24px; padding: 0 12px; border-radius: 999px;
  background: rgba(255,255,255,.14); color: #fff;
  border: 1px solid rgba(255,255,255,.38);
  font-size: 11.5px; font-weight: 600; letter-spacing: .03em;
  box-shadow: 0 1px 6px rgba(8,21,44,.18);
  backdrop-filter: blur(3px);
  white-space: nowrap;
}
.me-prog { margin-top: 12px; height: 8px; }
.me-next { font-size: 11.5px; color: var(--ink-3); margin-top: 6px; }

/* 统计四格：一行四个 + 细分隔线。
   旧的 2×2 大卡片块（.stat-grid）又大又空，帆哥评价「low」。
   这里不复用 .stat-grid —— 数据看板与后台也用它，改全局会连带改动那两处。 */
.me-stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
}
.me-stats .ms { position: relative; text-align: center; padding: 0 4px; }
.me-stats .ms + .ms::before {
  content: ''; position: absolute; left: 0; top: 4px; bottom: 4px;
  width: 1px; background: var(--line);
}
.me-stats .ms b {
  display: block; font-size: 22px; font-weight: 800; line-height: 1.15;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.me-stats .ms span { font-size: 11.5px; color: var(--ink-3); }

@media (max-width: 899px) {
  .me-band { height: 42px; }
  .me-body { padding: 0 16px 18px; }
  .me-top { margin-top: -28px; gap: 12px; }
  .me-av { border-width: 2.5px; }
  .me-av .avatar { width: 72px; height: 72px; font-size: 25px; }
  .me-name { font-size: 17px; }
  /* 手机端行内空间紧：名字让出一点比例，把余量留给部门 */
  .me-name-row .me-name { max-width: 62%; }
  .me-dept { font-size: 12px; }
  .me-dept::before { margin: 0 6px 0 5px; }
  .me-meta { font-size: 12px; margin-top: 2px; }
  .me-tags { gap: 6px; margin-top: 12px; }
  /* 手机端右上角徽章：头像从 92 缩到 72 后，行内空间更紧 —— 字号/内边距同步收一档 */
  .me-join { right: 16px; height: 20px; padding: 0 9px; font-size: 10.5px; }
  .me-prog { margin-top: 11px; }
  .me-next { font-size: 11px; }
  .me-stats { margin-top: 14px; padding-top: 12px; }
  .me-stats .ms b { font-size: 19px; }
  .me-stats .ms span { font-size: 11px; }
}
@media (max-width: 380px) {
  .me-stats .ms b { font-size: 17.5px; }
  .me-stats .ms span { font-size: 10.5px; }
}

/* ---------- ② 右栏「最新活动 / 最新投票」----------
   帆哥要求：插在「热门板块」之上，活动在上、投票在下；
   没有内容就整块不出现（loadAsideNew 判定后置空容器，
   再靠 :empty 把卡片外壳也收掉，不留一条空边框）。 */
.aside-new:empty { display: none; }
.aside-new .an-title {
  font-size: 14px; font-weight: 700; line-height: 1.45; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; margin-bottom: 9px;
}
.aside-new .an-cover {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 10px; display: block; margin-bottom: 10px;
}
.aside-new .an-meta {
  display: flex; flex-direction: column; gap: 5px;
  font-size: 11.5px; color: var(--ink-3); margin-bottom: 11px;
}
.aside-new .an-meta i { font-style: normal; display: flex; align-items: center; gap: 5px; }
.aside-new .an-meta i svg { width: 13px; height: 13px; flex: none; }
.aside-new .an-tx { color: var(--ink-3); }
.aside-new .an-foot {
  display: flex; align-items: center; gap: 8px;
  padding-top: 10px; border-top: 1px solid var(--line);
  font-size: 11px; color: var(--ink-3);
}
.aside-new .an-foot .btn {
  flex: none; margin-left: auto; height: 30px; padding: 0 13px; font-size: 12.5px;
}
.aside-new .an-done { margin-left: auto; color: var(--ok); font-weight: 650; flex: none; }
/* 投票选项在 256px 宽的侧栏里要再收一档，否则选项文字被挤成两三行 */
.aside-new .poll-opts { margin-top: 0; gap: 6px; }
.aside-new .poll-opts.pickable { margin-top: 0; gap: 6px; }
.aside-new .poll-opts.pickable .poll-opt { padding: 8px 10px; gap: 8px; }
.aside-new .po-text { font-size: 12.5px; }
.aside-new .po-line { gap: 7px; }
.aside-new .po-num { font-size: 10.5px; }
.aside-new .po-bar { margin-top: 5px; height: 5px; }
.aside-new .poll-opt.has-pic { align-items: flex-start; }
.aside-new .po-pic { width: 36px; height: 36px; border-radius: 9px; }

/* ===========================================================
   帖子「左右排」：文字概要在左、首图在右（2026-09-21 帆哥要求）
   -----------------------------------------------------------
   适用：除「新品发布」外的五个板块，且发帖时只传了 1~2 张图
        （判定见 app.js 的 sideLayout()）。
   ≥3 张图仍是「上文下三图」（第 3 张挂 +N），不在这里管。

   ⚠️ 一律写成「末尾追加覆盖层」，不去改 .pc-imgs / .fr-media 的
   n1/n2/n3 —— 那几条分支还被「新品发布」和「≥3 张图」共用，
   改原规则会连带把那两种也改掉。
   =========================================================== */

/* ---- 圈子 / 板块列表（postCardHtml） ---- */
.pc-side { display: flex; align-items: flex-start; gap: 14px; }
.pc-side-txt { flex: 1 1 auto; min-width: 0; }
/* 左栏比整卡窄，标题行原本的 7px 下边距加上正文自身的上边距会显得空，
   这里把间距收到一处管 */
.pc-side-txt .pc-trow { margin-bottom: 0; }
.pc-side-txt .pc-body { margin-top: 6px; -webkit-line-clamp: 3; }

/* 图片定宽 + 定比例。**故意不跟着左栏高度走**：
   正文长短差别很大，让图去对齐文字高度的话，同样是「1 张图」的卡片
   会长短不一，列表扫下来就散了。定死尺寸最整齐。 */
.pc-side-pic {
  flex: none; width: 138px; aspect-ratio: 4 / 3;
  border-radius: 12px; overflow: hidden; background: var(--surface-2);
}
.pc-side-pic img { width: 100%; height: 100%; object-fit: cover; display: block; transition: .3s; }
.post-card:hover .pc-side-pic img { transform: scale(1.03); }

/* ---- 首页「最新动态」（feedRowHtml） ---- */
/* 首页那一条比板块卡窄一些，图片相应收一档，否则文字列会被压得频繁换行 */
.fr-side { display: flex; align-items: flex-start; gap: 12px; }
.fr-side-txt { flex: 1 1 auto; min-width: 0; }
.fr-side-pic {
  flex: none; width: 92px; aspect-ratio: 1 / 1;
  border-radius: 13px; overflow: hidden; background: rgba(19, 26, 46, .04);
}
.fr-side-pic img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 手机上卡片内宽只剩三百出头，图再占 138px 文字就只剩十来字一行 */
@media (max-width: 520px) {
  .pc-side { gap: 11px; }
  .pc-side-pic { width: 96px; border-radius: 10px; }
  .fr-side { gap: 10px; }
  .fr-side-pic { width: 78px; border-radius: 11px; }
}

/* ===========================================================
   页面内确认弹窗（替代浏览器原生 confirm）  ·  2026-09-21
   -----------------------------------------------------------
   见 app.js 里 askConfirm() 的注释：原生 confirm 在三种情况下会被
   **静默吞掉**（不报错、直接返回 false）——钉钉/微信内置 WebView、
   跨域 iframe、以及用户勾过「阻止此页面创建更多对话框」。
   代码里 `if (!confirm(...)) return` 就成了「点了没反应」。
   自绘一个，行为完全自己掌控。

   z-index 260：压住灯箱(200)与欢迎浮层(150)，但让 toast(300) 在最上层 ——
   确认框开着的时候弹出来的提示消息不能被挡住。
   =========================================================== */
.cf-mask {
  position: fixed; inset: 0; z-index: 260;
  background: rgba(8, 21, 44, .42);
  display: flex; align-items: center; justify-content: center;
  padding: 22px;
  animation: cfFade .14s ease-out;
}
@keyframes cfFade { from { opacity: 0 } to { opacity: 1 } }

.cf-box {
  width: 100%; max-width: 392px;
  background: var(--surface);
  border-radius: var(--r-md);
  box-shadow: var(--sh-3);
  padding: 20px 20px 16px;
  animation: cfPop .17s cubic-bezier(.2, .9, .3, 1.15);
}
@keyframes cfPop {
  from { transform: scale(.96) translateY(8px); opacity: 0 }
  to   { transform: none; opacity: 1 }
}

.cf-title { font-size: 16.5px; font-weight: 700; color: var(--ink); margin-bottom: 8px; }
.cf-msg   { font-size: 14px; color: var(--ink-2); line-height: 1.68; word-break: break-word; }
.cf-row   { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }
.cf-row .btn { min-width: 86px; }

/* 手机上两个按钮竖排：并排时「取消 / 确定删除」只隔 10px，
   拇指很容易点到右边那个（也就是危险的那个）。竖排后取消在上、确定在下，
   误触代价小得多。 */
@media (max-width: 430px) {
  .cf-row { flex-direction: column; }
  .cf-row .btn { width: 100%; min-width: 0; }
}

/* ---- 「要保存草稿吗？」的三选一：**竖排**，每个选项各占一整行（第 43 轮）----
   为什么不用 .cf-row 并排：三个按钮并排在手机上会挤成三个小方块，
   而这三个选项点错的代价是**丢掉刚写的内容** —— 必须一眼分清、
   手指不用瞄着点。所以全部竖排、通栏。
   顺序刻意是「保存(主) → 不保存(危险) → 继续编辑(最轻)」：
   最常用的两个在上半屏，安全项放最下，和系统弹窗的手感一致。 */
.cf-col { display: flex; flex-direction: column; gap: 9px; margin-top: 20px; }
.cf-col .btn { width: 100%; }
/* 「继续编辑」必须**明显比另两项轻**（它不离开、也不会丢东西），
   但又不能浅到读不清 —— 用 ink-3 而不是 faint（faint 在手机上几乎看不见）。 */
.cf-col .btn.cf-plain {
  background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-3); font-weight: 600;
}
.cf-col .btn.cf-plain:hover { background: #F7F8FA; border-color: #CBD4E0; color: var(--ink); }

/* ============================================================
   产品档案卡：成对字段「各自独立成框、并排一行」+ 标签加深加粗 + 卖点小竖线
   （2026-09-21 第三 / 四轮反馈 · 末尾追加覆盖层，要回滚整段删掉即可）
   ------------------------------------------------------------
   ① 成对字段（售价+店铺券前价 / 发货地+物流 / 包装袋+上架渠道）由 app.js 的
      pfPairHtml 包成 `.pf-cell.pf-pair` + 两个 `.pf-half`。
      ⚠️ 第三轮写的是 `.pf-pair { display: contents }` —— 把两个半格展平成网格项，
         指望 2/3 列网格「碰巧」让它们同行。**实测不成立**：7 个字段按
         (1,2)(3,4)(5,6) 流动，2 列时售价(第2) 与券前价(第3) 分处两行，
         3 列时包装袋(第6) 与上架渠道(第7) 被行边界拆开。
      第四轮改成「成对组自己占满一整行 + 内部再分两列」，与列数无关；并按帆哥
         的原话「不是放在一行的一个框里，还是各自的框，只不过在一行」——
         外壳完全透明，两个半格各自是一张白卡。
      组里只剩一个字段（另一半没值）时 app.js 不包壳，照旧单独一格。
   ② 灰标签原来用 --faint(#A9B1C4) 太淡；改 --ink-2 并加粗到 700，
      与值（--ink 近黑、字重 620）靠「颜色 + 字重」拉开层级。
      第四轮：标签后补一个全角灰色冒号，值改居左紧挨标签。
   ③ 「产品卖点」标题补上和「产品档案」同一个金色小竖线。
   ============================================================ */
/* 单个字段：宽屏占半行（两个短字段能并排），独占一行时靠 flex-grow 撑满整行
   —— 否则它只有内容宽（实测 186px），右边空一大截。
   手机（≤520px）由下面的断点统一改成整行：值里有「TS2616Z88-012」这种长编码，
   半行宽（166px）必然折行。 */
.pf-cell { flex: 1 1 calc(50% - 4px); }

.pf-cell.pf-pair {
  flex: 1 1 100%;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  padding: 0; background: none; border: 0; border-radius: 0;
}

/* 标签后面补一个灰色冒号（与标签同色），值一律居左、紧挨着标签 ——
   帆哥第四轮：「用户填写的文字都居左，挨着灰色字，中间加个灰色冒号」。
   原来手机端写了一条 `.pf-v { text-align: right }`（值右对齐、离标签老远），
   由这里的 text-align 拉回来（同特异性、位置在后即生效）。 */
.pf-k::after { content: '：'; }
.pf-v { text-align: left; }
/* 🚨 成对的「一半」在 app.js 里挂的是 `class="pf-cell pf-half"` —— **刻意复用 .pf-cell**，
   这样格子该有的底色/描边/圆角/**各断点下的内边距**全都自动跟着走，这里一个字都不用抄。
   第一版我在这里手写了 `padding: 8px 10px`，看着和宽屏一致，其实把 521~759px 那一档
   （`.pf-cell` 是 7px 9px）盖掉了 —— 实测 600px 两列档整卡因此高 2px、一路累积到 6px。
   一个格子里的 padding 会随断点变，就别在覆盖层里写死它。
   第四轮确认这个复用是对的：脱壳的是**外壳**（.pf-pair），半格照旧吃全套外观。 */
/* 标签：--faint(#A9B1C4) 太淡 → 换成 --ink-2 并加粗。
   ⚠️ 刻意不动 line-height（保持原来的 1.3）—— 基线位置一变，宽屏的行高就会跟着变。 */
.pf-k { color: var(--ink-2); font-weight: 700; }

.pfile-sub { display: flex; align-items: center; gap: 7px; }
.pfile-sub i { width: 3.5px; height: 13px; border-radius: 2px; background: var(--gold); flex: none; }

/* 手机（≤520px）：单个字段独占一行 —— 值里有「TS2616Z88-012」这种长编码
   （标签 48 + 冒号 + 值 91 ≈ 182px），半行宽（166px）必然折行。
   成对组照旧「整行 + 内部两列」，每个半格 163px；实测里面最长的一组
   「店铺券前价：¥248」只要 107px、「上架渠道：全渠道」103px，都放得下。 */
@media (max-width: 520px) {
  .pfile-grid { gap: 6px; }
  .pf-cell { flex: 1 1 100%; }
  .pf-cell.pf-pair { gap: 6px; }
}

/* ============================================================
   手机端撤掉页面顶栏 + 「我的消息」入口（2026-09-21 帆哥反馈）
   ------------------------------------------------------------
   帆哥原话：「现在点开每个板块，顶部画红线那个区域都显示这个板块名称
   啥的，但是手机本身显示内容就有限，请把这个区域去掉。」

   .topbar 在 ≥900px 原本就是 display:none（PC 用左栏导航，见文件上方那条
   @media (min-width:900px)），所以这一段只影响手机端，PC 端零变化。

   撤掉顶栏后少掉的东西，逐个都有替代：
     · 页面名 —— 底栏 5 个 tab 已经高亮当前位置
     · 返回键 —— 钉钉工作台自带返回；底栏也能回到上级页面
     · 铃铛（消息）—— 「我的」页新增的「我的消息」入口 .me-msg
       （底栏「我的」上的红点只是角标，点了回个人主页，本来进不了消息页）

   实现方式：末尾追加覆盖层，原规则一行未动，要回滚整段删掉即可。
   上方那两条 :has()（首页 / 圈子撤顶栏）从此冗余但无害，故意留着 ——
   将来若只想改回来其中一页，删掉这里的通用规则就行。
   ============================================================ */
@media (max-width: 899px) {
  .topbar { display: none; }
  /* 顶栏本来占 56px，撤掉后内容直接贴屏幕顶边，补一点呼吸空间 */
  .col-main { padding-top: 20px; }
}

/* ---------- 必填星号（发布 / 编辑帖子表单） ---------- */
.req { color: var(--danger); font-weight: 700; font-style: normal; margin-left: 2px; }

/* ---------- 「我的消息」入口：只在手机端出现 ---------- */
.me-msg { display: none; }

@media (max-width: 899px) {
  .me-msg {
    display: flex; align-items: center; gap: 10px; width: 100%;
    margin-top: 12px; padding: 13px 15px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-md); box-shadow: var(--sh-1);
    color: var(--ink); font-family: inherit; font-size: 14.5px; font-weight: 620;
    text-align: left; cursor: pointer;
  }
  .me-msg .mm-ico { display: grid; place-items: center; width: 20px; height: 20px; color: var(--brand); flex: none; }
  .me-msg .mm-ico svg { width: 19px; height: 19px; }
  .me-msg .mm-t { flex: 1; min-width: 0; }
  .me-msg .mm-b {
    flex: none; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
    background: #E0473C; color: #fff; font-size: 11.5px; font-weight: 700;
    display: grid; place-items: center;
  }
  .me-msg .mm-arrow { flex: none; color: var(--faint); font-size: 18px; line-height: 1; }
}

/* ===========================================================
   帖子卡标题行 / 左右排  ·  2026-09-21 第五轮（帆哥看图后定的四条）
   -----------------------------------------------------------
   ① 标题两行时，第二行首字与第一行首字对齐（原来是贴到竖线上）
   ② 置顶/精华圆标跟在标题最后一个字后面（不再放开头）
   ③ 左右排的缩略图不占用标题/时间那一行 —— 标题独占一行，
      缩略图与正文同一水平线开始
   ④ 左右排的缩略图加 1px 细边框（纯白图片放在白卡上会看不出边界）

   ⚠️ 一律「末尾追加覆盖层」，不去改 566/578/2486 那几段原规则 ——
   它们还被其它形态（产品帖、banner、三宫格）共用。
   ⚠️ 选择器都限定在 `.post-card` 里：`.pc-title` 这个类名**投票卡
   （.card.poll-card）也在用**（`app.js` 里 `<div class="pc-title">`），
   裸写 `.pc-title { display:flex }` 会把投票卡的标题也改成 flex。
   =========================================================== */

/* ---- ① ② 标题行：前导与文字拆成两个块级兄弟 ---- */
.post-card .pc-title {
  display: flex; align-items: flex-start; gap: 6px;
}
/* 前导（板块色竖线 + 待审核/已下架）只占**第一行**的高度：
   1.42em 就是 .pc-title 的 line-height，竖线在其中垂直居中 = 与首行文字齐平。
   改 .pc-title 的 line-height 时这里要跟着改（只差 1~2px，不会崩，但会不齐）。 */
.post-card .pc-lead {
  flex: none;
  height: 1.42em;
  margin-right: 0;                 /* 间距交给 .pc-title 的 gap: 6px 统一管 */
}
/* 标题文字块：自己换行，第二行从本块左边缘开始 = 与第一行首字对齐 */
.post-card .pc-ttl { flex: 1 1 auto; min-width: 0; }

/* 顶/精圆标跟在标题最后一个字后面。vertical-align: middle 让 17px 的圆标
   在行内垂直居中（原来在 flex 容器里靠 align-items: center，效果等价）。 */
.post-card .pc-ttl .pi { margin-left: 5px; vertical-align: middle; }

/* ---- ③ 左右排：标题独占一行，缩略图与正文同排 ---- */
/* 左栏现在只装正文，正文与标题行之间的间距由 .pc-trow 的 7px 下边距负责 */
.pc-side-txt > .pc-body { margin-top: 0; }

/* ---- ④ 缩略图细边框 ---- */
/* 颜色取「品牌深蓝 12% 透明度」而不是 `--line`(#ECE9E2) 那种暖灰：
   卡片本身是暖白底，暖灰边框叠上去会显得图片发脏；深蓝 12% 在白底上约等于
   #E0E2E6，是中性冷灰，跟图片的冷调同一系，只负责勾出边界、不参与配色。
   想更明显改大这个值、更淡改小 —— 只调这一处。 */
.post-card { --pic-edge: rgba(19, 26, 46, .12); }
.pc-side-pic { border: 1px solid var(--pic-edge); }

/* 手机上图片只有 96px，1px 边框会显得更重，微弱一档 */
@media (max-width: 520px) {
  .post-card { --pic-edge: rgba(19, 26, 46, .10); }
}

/* ===========================================================================
   2026-09-21 第六轮（帆哥看图后定的五条）
   ---------------------------------------------------------------------------
   ① 顶/精圆标与标题文字「同心」（圆心落在文字中心那条水平线上）
   ② 首页最新动态右下角：❤️ 由蓝改红、补上评论数
   ③ 首页右侧缩略图加 1px 细边框
   ④ 无正文 + 2 张图改走通栏大图 —— 这一条**只改 app.js**（cardLayout /
      cardMediaOf），本文件不需要任何新 CSS，在下面留个指路的注记
   ---------------------------------------------------------------------------
   本段是覆盖层，必须留在文件最后。要回滚整段删掉即可。
   =========================================================================== */

/* ---------- ① 顶/精圆标：圆心对齐标题文字中心 ----------
   帆哥原话：「这个置顶和精华小标签可以上移一点点，圆心和题目文字的中心点
   要在同一水平线。」

   原来只写了 `vertical-align: middle`。middle 对齐的是「基线 + x-height/2」，
   而汉字字形的视觉中心大约在「基线 + 0.36em」—— 两者差约 1.7~2px，
   所以圆标看着一直偏低。

   ⚠️ 这个差值是**字体度量决定的**，不能手算、也不该猜。实测方法
   （`_qa/probe_pi_align2.js`，逐候选位移试出残差最小的那个）：
     · 圆标中心 = `.pi` 的 rect 中心
     · 文字中心 = 用 Range 圈住 `.pc-ttl` 里的**文本节点**，取
       `getClientRects()` 的**最后一个** rect
       —— 圆标跟在最后一个字后面，所以要看**它所在的那一行**。
       标题折成两行时取「整段文字」的 rect 是错的：那个 rect 跨两行，
       中心落在两行之间，会量出 20 多 px 的假偏移（第一版就栽在这）。
   实测（1440 / 900 / 700 / 390 四个宽度）：
     · 字号 15px（≥900px）→ 偏低 1.97px，位移 -2px 后残差 0.03px
     · 字号 14px（<900px）→ 偏低 1.73px，位移 -1.7px 后残差 0.03px
   （`.pc-title` 的字号实际只有这两档：2088 行的 15px 与 2216 行的 14px；
   1014 行那条 `@media (max-width:380px){font-size:15.5px}` 被后面 2216 行
   的 14px 覆盖了，所以 ≤380px 也是 14px。）
   🚨 **改标题字号时必须回来重测这两个数** —— 偏移量随字号按比例变，
   它不是固定 2px。

   ⚠️ 刻意用 `transform` 而不是 `margin-top` / `position` / `line-height`：
   transform 不参与布局，只挪画面，不会改行高、不会改卡片高度。
   上一轮「档案卡多出 2px」的教训就是「在覆盖层里动了会影响布局的量」。
   ⚠️ 圆标**折行**的情况（标题正好占满一行、圆标被挤到下一行）本条管不到 ——
   那是行内元素本身的换行行为，实测 360px 下那条置顶帖会出现。
   试过两种修法都不划算，记录在 `_qa/probe_pi_align2.js` 的注释里。 */
.post-card .pc-ttl .pi { transform: translateY(-2px); }
@media (max-width: 899px) {
  .post-card .pc-ttl .pi { transform: translateY(-1.7px); }
}

/* ---------- ② 点赞红：收成一个来源，首页与板块卡一致 ----------
   原来板块卡 `.act.on` 写死 #D0473C，而首页 `.fr-foot .fr-like.on` 用的是
   `var(--brand)`（靛蓝 #4A5BF0）—— 同一个「已点赞」动作两个颜色，
   帆哥看到的「首页❤️是蓝色，要红色一致」就是这个。
   抽成一个变量、两处都引用，以后改颜色只改一行。
   `.act.on` 的两处用法（帖子点赞 818 行 / 评论点赞 1597 行）语义都是「已赞」，
   收成同一个红没有问题。 */
:root { --like: #D0473C; }
.act.on { color: var(--like); }
.fr-foot .fr-like.on { color: var(--like); }

/* ---------- ③ 首页右侧缩略图：补 1px 细边框 ----------
   板块卡的 `.pc-side-pic` 上一轮已经加过边框，首页这条 `.fr-side-pic`
   当时漏了 —— 帆哥图4（云帆课堂那条）看的就是它。
   白底/浅色图片放在白卡上看不出边界，一条 rgba(19,26,46,.12) 的细线就能勾出来。
   ⚠️ `--pic-edge` 原来只声明在 `.post-card` 上，**自定义属性不跨选择器继承**
   （`.fr-side-pic` 在 `.feed-row` 里，拿不到 `.post-card` 的值），
   所以这里给 `.feed-row` 也声明一份；手机端与板块卡一样弱一档。 */
.feed-row { --pic-edge: rgba(19, 26, 46, .12); }
.fr-side-pic { border: 1px solid var(--pic-edge); }
@media (max-width: 520px) {
  .feed-row { --pic-edge: rgba(19, 26, 46, .10); }
}

/* ---------- ④ 无正文 + 2 张图 → 通栏大图（本条无 CSS） ----------
   见 `public/app.js` 的 `cardLayout` / `cardMediaOf`：
   判据从 `n === 1` 放宽到 `n <= 2`，并且调用方按 layout 把 media 截到 1 张。
   落到默认结构后走的就是既有的 `.pc-imgs.n1 .ph`（16/10）与
   `.fr-media.n1.single img`（16:9）—— 与「1 张图」那张完全同一条代码路径，
   所以这里一个新类名都不加，避免「同一张图在不同地方好几个比例」。 */

/* ===========================================================================
   首页「最新动态」左右排：标题独立成行（2026-09-21 第七轮）
   ---------------------------------------------------------------------------
   帆哥：「你说的这个，首页也一起改」—— 即圈子页那四条里适用于首页的部分：
     · 缩略图不占标题那一行（标题独占一行，图与摘要同排）← 本段唯一要动的
     · 缩略图 1px 细边框                              ← 第六轮已加（见下面 .fr-side-pic）
     · 标题折两行时第二行首字对齐                      ← 首页本来就成立，无需改
     · 顶/精圆标跟在标题末尾                          ← 首页动态**不渲染**顶/精，不适用
     · 日期落在右上角                                ← 首页的时间在底部作者行里
                                                      （.fr-foot），不在右上角，不适用

   ⚠️ 首页这一套（`.fr-*`）与圈子/板块列表那套（`.pc-*`）是**两套独立的选择器**，
   改一边不会自动影响另一边。圈子那边见上方「第五轮」那段。
   =========================================================================== */

/* ---- 标题行与分栏之间的间距 ----
   分栏里现在只有摘要，而摘要自带的 margin-top: 4px 在「非左右排」的帖上
   就是「标题→摘要」的间距。这里把 4px 从摘要挪到分栏上，两种排法的
   间距完全一致，列表扫下来不会有一半松一半紧。 */
.fr-side { margin-top: 4px; }
.fr-side-txt > .fr-ex { margin-top: 0; }

/* ---- 标题折行对齐：首页无需额外规则，这里只留个证据 ----
   `.fr-title` 本来就是 `display:flex`，竖线（`.pc-bdbar`）与文字
   （`.fr-title-tx`）是**两个 flex 子项**，文字的换行发生在本块内部 ——
   第二行天然从本块左边缘开始，与第一行首字对齐。
   （圈子卡之所以要改，是因为那边竖线是标题**内部的行内元素**，
   第二行会跌回块左边缘、正好贴到竖线上。两处结构不同，别照搬。）
   实测见 `_qa/card_chrome_qa.js`：首页折行标题各行左边缘一致。 */

/* ===========================================================================
   首页「最新动态」❤️ 可独立点击（2026-09-21 第八轮）
   ---------------------------------------------------------------------------
   帆哥：「首页这个帖子下面的❤️，也要和圈子页面一样，不用点开帖子，
   在外面就能直接点赞」。

   JS 侧见 `feedFootHtml()`：点赞元素补上 `data-act="like" data-id`，
   closest 先命中它就不会再冒泡到整行的 `nav`。

   这里只解决**手指够不够得着**的问题：原来 `.fr-like` 的可点区域
   = 13px 图标 + 3px 间隙 + 数字，宽 23~36px、**高仅 13px**，
   手机上点偏一点就落到整行上、照样跳详情页 —— 那帆哥的抱怨就等于没修。
   所以给一个 25px 高的热区（`padding: 6px 5px`），再用**等量负 margin**
   把它抵掉：`.fr-foot` 是 `align-items:center` 的 flex，负 margin 后
   该项的 margin box 仍是 13px，行高不会因为这次改动变松
   （实测 `_qa/feed_like_qa.js`：改动前后 `.fr-foot` 高度逐条一致）。

   水平方向只各扩 5px：`.fr-sp` 的 `gap` 是 11px，热区之间因此仍留 6px
   空隙，不会误触到隔壁的评论数（那个没有 data-act，点到就跳详情）。
   `.pc-*`（圈子/板块卡）那套不动 —— 它一直是可点的。 */ 
.fr-foot .fr-like {
  cursor: pointer;
  padding: 6px 5px;
  margin: -6px -5px;
  border-radius: 8px;
  -webkit-tap-highlight-color: transparent;
}
/* 按下时的即时反馈：手机上没有 hover，给一个浅底才算「点到了」 */
.fr-foot .fr-like:active { background: rgba(19, 26, 46, .06); }


/* ============================================================
   2026-09-21（第十轮）相册尺寸收窄 —— ALBUM-TILE-R10
   ------------------------------------------------------------
   帆哥要求：① 首页「相册」一排要能放下 4 个（原来只放得下 3 个多一点，
                第 4 个要横滑才看得到）
             ② 相册页从一行 2 个改成一行 3 个
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚整段删掉即可。
   ============================================================ */

/* ① 首页相册格（.ktile）
   原来固定 108px：390px 屏一行只能放 3 个（108×3 + 10×2 = 344px + 列边距 > 可容纳宽度），
   第 4 个必须横滑。改成按容器宽度均分 4 份 ——
   屏宽 320~759 区间都正好放下 4 个，不多不少、也不留半张残卡。
   30px = 4 格之间的 3 个 gap（.tile-strip 的 gap: 10px）。 */
@media (max-width: 759px) {
  .ktile {
    width: calc((100% - 30px) / 4);
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: 12px;
  }
  /* 卡片从 108px 缩到 76~100px，文字区必须同步收一档：
     仍用原来的 13px / 10px，两行文字会把卡片底部挤到只剩 1~2px。
     字号按「最长的部门名也要放得下」反推：360px 屏卡宽 77px，
     「文创百货研发部」7 字 × 10px = 70px，减去左右 padding 6px 刚好。 */
  .kt-tx { height: 29px; padding: 0 3px; }
  .kt-tx b { font-size: 11.5px; }
  .kt-tx b.nm { font-size: 10px; }
  .kt-tx span { font-size: 9px; }
}

/* ② 相册页图集网格（.album-grid）：手机从 2 列改 3 列
   基础规则是 repeat(2)，≥900px 才是 3 列、≥1400px 4 列 —— 只补手机这一档。 */
@media (max-width: 899px) {
  .album-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
  /* 每列从约 175px 掉到 110px 左右，日期行「2026.09.09（12张）」
     按原字号（12.5px + 字距 .2px）会折成两行，卡片高度参差不齐。
     字号与字距收一档 —— 具体档位是实测出来的（见下面两段媒体查询）。 */
  .album-cap { font-size: 11px; letter-spacing: 0; }
  .album-title { font-size: 11.5px; line-height: 1.4; }
  /* 右上角「张数」角标：小封面上按原尺寸会顶到卡片中线，同步收一档 */
  .album-n { height: 19px; padding: 0 6px 0 5px; font-size: 11px; border-radius: 6px; }
  .album-n svg { width: 12px; height: 12px; }
}

/* 日期行在小屏上还要再降一档。用 `Range.getClientRects()` 逐屏宽实测过
   「2026.09.09（12张）」这条最长文案（`_qa/probe_r10_capfont.js`）：

     屏宽 430（格宽 127px）→ 11.5px 已是单行
     屏宽 390（格宽 114px）→ 11px  单行
     屏宽 360（格宽 106px）→ 需 ≤10.5px 才单行（11px 会折）
     屏宽 320（格宽  93px）→ 9.5px 仍有 1 张折行，无解，只能让高度对齐

   ⚠️ 别凭「差不多」估字号 —— 126px 与 106px 的格宽只差两个字符宽，
      但 11px 与 10.5px 就是「单行 / 折行」的分界。 */
@media (max-width: 389px) {
  .album-cap { font-size: 10.5px; }
}
@media (max-width: 339px) {
  /* 320px 级极窄屏：日期行放不下了，干脆让它规规矩矩占两行 ——
     用 min-height 把两行的高度固定住，避免网格里「有的卡片一行、
     有的两行」造成整行卡片高低参差。 */
  .album-cap { font-size: 9.5px; line-height: 1.35; min-height: 2.7em; }
}

/* ==========================================================================
   积分体系覆盖层（2026-09-21 · 帆哥要求）
   ---------------------------------------------------------------
   新增两块界面：
     ① 积分榜页的「积分介绍」（如何增加积分 / 积分对应社区等级）
     ② 「我的积分」明细页（.pt-*）
   以及个人主页上「等级 / 积分」两个可点入口（.me-link）。

   ⚠️ 本段是**覆盖层，必须留在文件最后**。里面只新增 .pt-* / .pi-* / .pr-* /
   .pl-* / .me-link 这些类名，卡片、药丸、等级徽章、进度条全部复用既有组件
   （.card / .chip / .lv-badge / .progress.on-light），没有修改任何一条原规则。
   要回滚：整段删掉即可，其余页面一行都不会受影响。
   ========================================================================== */

/* ---------------- 积分榜：积分介绍 ---------------- */
.pt-intro { display: grid; gap: 12px; }
.pi-card { padding: 16px 16px 14px; }

.pi-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 15px; font-weight: 700; color: var(--ink); margin-bottom: 12px;
}
.pi-head svg { width: 19px; height: 19px; flex: none; color: var(--brand-600); }

/* 规则表：用 1px 的网格间隙当分隔线（比给每行加 border 更干净，
   最后一行不会多出一条悬空的线）。

   2026-09-21 帆哥：「这块排版压缩一下，很多不用单独占一行」。
   原来每条规则占两行（名称一行、说明一行；分值一行、上限一行），5 条就撑掉半屏。
   现在改成**一条规则严格一行**：名称 · 说明 | 分值 · 上限 横向排开。
   ⚠️ HTML 结构一个字没动 —— 只是把 `.pr-l` 里的 name/how 从纵向改横向、
      `.pr-r` 的 b/span 同理，所以验收脚本里 `.pr-name` / `.pr-r b` / `.pr-r span`
      这些选择器照常有效。改这里不需要动 app.js。 */
.pi-rules { display: grid; gap: 1px; background: var(--line); border-radius: var(--r-sm); overflow: hidden; }
.pr-row { display: flex; align-items: center; gap: 9px; padding: 8px 12px; background: var(--surface); min-width: 0;
  /* 2026-09-23 帆哥反馈窄屏下右列「分」字被裁：grid 项默认 min-width:auto，
     内容 min-content 超过轨道时会整行溢出、被 .pi-rules 的 overflow:hidden 裁掉右侧。
     min-width:0 让行永远收在轨道内，左列 .pr-how 的省略号照常兜底。 */ }
.pr-l { min-width: 0; flex: 1; display: flex; align-items: baseline; gap: 7px; }
.pr-name { font-size: 13.5px; font-weight: 650; color: var(--ink); flex: none; }
/* 说明退成紧跟名称的灰色小字；窄到放不下时省略号截断，绝不折行（折了就白压了） */
.pr-how { font-size: 11.5px; color: var(--faint); margin-top: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pr-r { flex: none; display: flex; align-items: baseline; gap: 7px; }
.pr-r b { font-size: 15px; font-weight: 760; color: var(--brand-600); font-variant-numeric: tabular-nums; }
.pr-r span { display: inline; font-size: 11px; color: var(--faint); margin-top: 0; white-space: nowrap; }
/* 「不加分」行的右列（2026-09-22 · 帆哥要求把近期积分规则改动写进说明页）：
   不能复用 .pr-r b —— 那是品牌蓝，语义是「加分」；这里用灰色承接「0 分」。
   打赏的负分用 danger 色，与加分形成对照（同 .pt-d.out 的既有口径）。 */
.pr-none { font-size: 11.5px; font-weight: 700; color: var(--faint); white-space: nowrap; }
.pr-r b.minus { color: var(--danger); }

.pi-foot { margin-top: 12px; font-size: 12px; color: var(--ink-3); line-height: 1.65; }
.pi-foot b { color: var(--brand-600); font-weight: 700; }
.pi-foot .me-link { color: var(--brand-600); font-weight: 650; white-space: nowrap; }

/* 「消耗积分会同步降等级」——这条是帆哥点名要提示的，用金色提示条让它显眼，
   但不能做成红色警告（这不是风险，是规则） */
.pi-foot.warn {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 10px 12px; margin-top: 12px;
  background: var(--gold-050); border: 1px solid rgba(200, 161, 90, .34);
  border-radius: var(--r-sm); color: #7A5310;
}
.pi-foot.warn svg { width: 15px; height: 15px; flex: none; margin-top: 1.5px; color: var(--gold); }
.pi-foot.warn b { color: #7A5310; }

/* 等级阶梯：一行两个（2026-09-21 帆哥：「这边也可以一行放两个」）
   8 级从 8 行压到 4 行。单列要放得下「Lv.5 一级警司 + 1200 ~ 2499 分 + 当前」约 270px，
   两列即需约 600px 视口 —— 所以两列断点设在 600px（见文件末尾媒体查询），更窄退回单列。 */
.pi-levels { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 8px; }
.pl-row {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 7px 10px; border-radius: 10px; background: var(--surface-2);
}
.pl-row.on { background: var(--brand-050); box-shadow: inset 0 0 0 1px rgba(74, 91, 240, .22); }
.pl-range { font-size: 12px; color: var(--ink-3); margin-left: auto; font-variant-numeric: tabular-nums; }
.pl-row.on .pl-range { color: var(--brand-ink); font-weight: 650; }
.pl-cur {
  flex: none; font-size: 10.5px; font-weight: 700; color: #fff;
  background: var(--brand-600); border-radius: 999px; padding: 2px 8px;
}

/* ---------------- 可点入口（个人主页的等级 / 积分） ----------------
   只加指针与轻微反馈，不动尺寸 —— 等级徽章、积分标签的排版跟原来一模一样。 */
.me-link { cursor: pointer; transition: .15s; }
.me-link:hover { opacity: .82; }
.ml-arrow { margin-left: 4px; font-weight: 700; color: var(--brand-600); }

/* ---------------- 我的积分（明细页） ---------------- */
.pt-head { padding: 18px 18px 16px; }
.pt-balance { display: flex; align-items: baseline; gap: 8px; }
.pt-balance b {
  font-size: 34px; font-weight: 780; line-height: 1.1;
  color: var(--brand-600); font-variant-numeric: tabular-nums;
}
.pt-balance span { font-size: 12.5px; color: var(--faint); }
/* 「可用 N 分」靠右贴边（2026-09-21 帆哥第③条：等级右侧显示总积分，
   同时别把可用积分藏起来）。用 margin-left:auto 而不是 justify-content，
   否则「总积分」这个标签会被一起推到中间。 */
.pt-balance .pt-avail {
  margin-left: auto; font-style: normal; font-size: 12.5px; color: var(--faint);
  white-space: nowrap;
}
.pt-balance .pt-avail b {
  font-size: 16px; font-weight: 750; color: #9C6F12; font-variant-numeric: tabular-nums;
}
.pt-lvrow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

.pt-sum { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 14px; }
.pt-sum > div { text-align: center; padding: 9px 4px; background: var(--surface-2); border-radius: 11px; }
.pt-sum b { display: block; font-size: 17px; font-weight: 740; color: var(--ink); font-variant-numeric: tabular-nums; }
.pt-sum b i { font-style: normal; font-size: 12px; font-weight: 600; color: var(--faint); }
.pt-sum span { display: block; font-size: 11px; color: var(--faint); margin-top: 2px; }

.pt-tabs { display: flex; gap: 7px; margin: 12px 0 2px; }
.pt-day { font-size: 11.5px; font-weight: 650; color: var(--faint); margin: 14px 0 7px; }
.pt-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; margin-bottom: 7px;
  background: var(--surface); border-radius: 12px; box-shadow: var(--sh-1);
}
/* 收支数字定宽 —— 不定宽的话 +1 / -300 会让左边的文字左右跳 */
.pt-d {
  flex: none; min-width: 46px; text-align: center;
  font-size: 15px; font-weight: 760; font-variant-numeric: tabular-nums;
}
.pt-d.in { color: var(--brand-600); }
.pt-d.out { color: var(--danger); }
.pt-tx { min-width: 0; flex: 1; }
.pt-t1 { font-size: 13.5px; font-weight: 620; color: var(--ink); }
.pt-note { font-size: 11.5px; font-weight: 500; color: var(--ink-3); margin-left: 7px; }
.pt-t2 { font-size: 11px; color: var(--faint); margin-top: 3px; }
.pt-pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin: 16px 0 4px; }

/* 等级表两列放不下就退回单列（两列各需 ~270px，含卡片内边距约需 600px 视口） */
@media (max-width: 600px) {
  .pi-levels { grid-template-columns: 1fr; }
}

@media (max-width: 520px) {
  .pi-card { padding: 14px 14px 12px; }
  .pi-head { font-size: 14.5px; margin-bottom: 10px; }
  /* 规则行继续压；说明收一号，宁可省略号也不折行（折了就白压了） */
  .pr-row { padding: 7px 10px; gap: 7px; }
  .pr-name { font-size: 13px; }
  .pr-how { font-size: 11px; }
  .pr-r b { font-size: 14.5px; }
  .pr-r span { font-size: 10.5px; }
  /* 等级徽章在窄屏收一号，**必须限定在 .pl-row 内** ——
     裸写 .lv-badge 会顺手改到详情页、榜单行里所有的等级徽章 */
  .pl-row { padding: 7px 9px; gap: 7px; }
  .pl-row .lv-badge { height: 19px; padding: 0 6px; font-size: 10.5px; }
  .pl-range { font-size: 11.5px; }
  .pt-balance b { font-size: 30px; }
  .pt-head { padding: 16px 16px 14px; }
  .pt-item { padding: 10px 12px; gap: 10px; }
  .pt-d { min-width: 40px; font-size: 14px; }
  .pt-sum b { font-size: 16px; }
}

/* ============================================================
   2026-09-21（第十一轮）积分商城 —— SHOP-R11
   ------------------------------------------------------------
   帆哥的要求（原文）：
     ① PC 端把「数据看板」撤掉，改成积分商城；管理员可上架商品、
        上传产品图与详情、选发货方式（快递 / 凭下单凭证找某部门某人领取）；
     ② 手机端「我的」页，在顶部积分排名模块右侧加「积分兑换」入口；
     ③ 手机端商品显示参考圈子帖子的形式：上面标题、下面左图右详情、
        底部积分价、底部右侧「兑换」按钮；
     ④ 商品分类只按积分分三档：0-300 / 301-1000 / 1000 以上。

   为什么要有商城（免得日后被当成「又一个花哨页面」砍掉）：
     线上 517 人里 63% 只有 1~10 分、中位数 10 分。积分只赚不花，
     大家就没有赚的动力。商城是让积分「流动起来」的装置。

   命名一览（统一加前缀，避免和已有类名撞车）：
     shc- 商品卡零件   sh- 商城列表 / 兑换浮层
     sd-  商品详情     so- 我的兑换记录
     as-  右栏「积分管家」  sa- 后台商城 / 上架表单   sq- 后台兑换订单

   ⚠️ 本段是新增覆盖层，留在文件最后。
   ============================================================ */

/* ------------------------------------------------------------
   ① 「我的」页的积分兑换入口（整行金色横幅）
   ------------------------------------------------------------
   做成整行横幅、而不是角落里的小按钮，理由：
     ① 入口要一眼看到 —— 商城没人点就等于没做；
     ② 把「我有多少分、能兑几件」直接写在横幅上。只写「积分兑换」
        四个字，没人知道自己现在兑得起什么，也就不会点。
   ⚠️ `.se-tx b` / `.se-tx span` 必须 display:block —— 否则横幅一窄，
      标题和积分数会被挤到同一行折行错乱（`btn-banner` 踩过这个坑）。 */
.shop-entry {
  display: flex; align-items: center; gap: 11px;
  margin-top: 14px; padding: 13px 15px;
  border-radius: var(--r-md);
  background: linear-gradient(112deg, #F7E8C9 0%, var(--gold-050) 58%, #FFFAF0 100%);
  border: 1px solid #EFDCB6;
  box-shadow: 0 2px 10px rgba(200, 161, 90, .16);
  cursor: pointer; transition: .16s;
}
.shop-entry:active { transform: translateY(1px); }
.se-ic {
  flex: none; width: 38px; height: 38px; border-radius: 12px;
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--gold), #B08A45);
  color: #fff; font-size: 20px;
  box-shadow: 0 3px 10px rgba(200, 161, 90, .38);
}
.se-tx { flex: 1; min-width: 0; }
.se-tx b { display: block; font-size: 15px; font-weight: 780; color: #7A5717; }
.se-tx span { display: block; font-size: 12px; color: #96773C; margin-top: 2px; }
.se-tx em { font-style: normal; font-weight: 800; color: #9C6F12; font-variant-numeric: tabular-nums; }
.se-tx i { font-style: normal; }
.se-go {
  flex: none; font-size: 12.5px; font-weight: 750; color: #fff;
  background: #8A6414; padding: 7px 13px; border-radius: 999px; white-space: nowrap;
}

/* ------------------------------------------------------------
   ② 商城列表：积分横条 + 分类 chips + 商品网格
   ------------------------------------------------------------ */
.sh-hero {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 18px; margin-bottom: 13px;
  border-radius: var(--r-md);
  background: linear-gradient(120deg, var(--brand-ink), var(--brand) 70%, #1670C9);
  color: #fff; box-shadow: 0 6px 20px rgba(10, 90, 168, .22);
}
.sh-hero-n {
  font-size: 30px; font-weight: 800; line-height: 1;
  letter-spacing: -.025em; font-variant-numeric: tabular-nums;
}
.sh-hero-lb { font-size: 11.5px; color: rgba(255, 255, 255, .74); margin-top: 4px; }
.sh-hero-r { margin-left: auto; text-align: right; min-width: 0; max-width: 62%; }
.sh-hero-s { font-size: 12.5px; line-height: 1.5; color: rgba(255, 255, 255, .9); }
.sh-hero-s b { font-size: 16px; font-weight: 800; color: var(--gold-300); font-variant-numeric: tabular-nums; }
.sh-hero-lk {
  display: inline-block; margin-top: 8px; cursor: pointer;
  font-size: 11.5px; font-weight: 750; color: #3A2A06;
  background: var(--gold); padding: 5px 12px; border-radius: 999px; white-space: nowrap;
}

.sh-bands {
  display: flex; gap: 7px; overflow-x: auto;
  padding: 2px 2px 11px; -webkit-overflow-scrolling: touch;
}
.sh-bands::-webkit-scrollbar { display: none; }
.sh-bands .chip { flex: none; height: 31px; padding: 0 13px; font-size: 13px; }
.sh-bands .chip.on {
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  border-color: transparent; color: #fff;
  box-shadow: 0 3px 10px rgba(10, 90, 168, .28);
}

.sh-foot { margin-top: 16px; text-align: center; line-height: 1.8; }
.sh-link { color: var(--brand); font-weight: 700; cursor: pointer; }

/* --- 商品卡：**一套 DOM 两种版式** ---
   手机 → grid-template-areas 摆成「标题在上 / 左图右详情 / 底栏通栏」；
   PC   → 同一套 DOM 塌成单列「图上、文字下」的常规网格卡。
   刻意不写两套渲染函数 —— 两套迟早出现「改了手机忘了 PC」，
   而列表是改漏了很难发现的地方。 */
.sh-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 9px; }

.sh-card {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  grid-template-areas:
    "t t"
    "img d"
    "bot bot";
  gap: 7px 12px;
  padding: 12px; min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-1);
  cursor: pointer; transition: .16s;
}
.sh-card:hover { border-color: #DED9CE; box-shadow: var(--sh-2); }
.sh-card:active { transform: translateY(1px); }
.sh-card.out .shc-img img { filter: grayscale(.5); opacity: .72; }

.shc-img {
  grid-area: img; position: relative; overflow: hidden;
  width: 92px; height: 92px;
  border-radius: var(--r-sm); background: var(--surface-2); color: var(--faint);
}
.shc-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shc-ph { display: grid; place-items: center; width: 100%; height: 100%; font-size: 26px; }
.shc-badge {
  position: absolute; left: 0; top: 0;
  font-size: 10px; font-weight: 750; padding: 2px 7px; border-radius: 0 0 8px 0;
}
.shc-badge.new { background: var(--gold); color: #3A2A06; }
.shc-badge.out { background: rgba(8, 21, 44, .7); color: #fff; }

.shc-t {
  grid-area: t; font-size: 14.5px; font-weight: 750; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.shc-d {
  grid-area: d; align-self: center;
  font-size: 12.5px; color: var(--ink-3); line-height: 1.6;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.shc-bot {
  grid-area: bot; display: flex; align-items: center; gap: 10px;
  margin-top: 3px; padding-top: 10px; border-top: 1px dashed var(--hair);
}
.shc-p { display: flex; align-items: baseline; gap: 3px; color: #9C6F12; }
.shc-p b { font-size: 20px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.shc-p span { font-size: 11.5px; font-weight: 650; }
.shc-btn {
  margin-left: auto; flex: none; white-space: nowrap;
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  color: #fff; border-radius: 10px; padding: 8px 18px;
  font-size: 13.5px; font-weight: 750;
  box-shadow: 0 2px 7px rgba(10, 90, 168, .3);
}
.shc-btn.off { background: var(--surface-2); color: var(--faint); box-shadow: none; }

/* --- 商品详情页 --- */
.sd-hero {
  position: relative; overflow: hidden;
  border-radius: var(--r-md); background: var(--surface-2);
  color: var(--faint); margin-bottom: 13px;
}
/* 商品图一律 contain（不裁切）—— 货不对板的观感比留白更伤信任 */
.sd-hero img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1 / 1; object-fit: contain;
}
.sd-hero .shc-ph { aspect-ratio: 1 / 1; font-size: 46px; }
.sd-hero.swiper {
  display: flex; gap: 9px; overflow-x: auto;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.sd-hero.swiper::-webkit-scrollbar { display: none; }
.sd-hero.swiper img {
  flex: none; width: 80%; max-width: 440px;
  border-radius: var(--r-md); scroll-snap-align: center;
}

.sd-main { padding: 15px 16px 16px; margin-bottom: 13px; }
.sd-p { display: flex; align-items: baseline; gap: 4px; color: #9C6F12; margin-bottom: 9px; }
.sd-p b { font-size: 30px; font-weight: 800; line-height: 1; letter-spacing: -.025em; font-variant-numeric: tabular-nums; }
.sd-p span { font-size: 13px; font-weight: 700; }
.sd-t { margin: 0 0 6px; font-size: 19px; font-weight: 780; line-height: 1.4; letter-spacing: -.01em; }
.sd-sub { font-size: 13.5px; color: var(--ink-2); line-height: 1.6; margin-bottom: 11px; }
.sd-meta {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  font-size: 12.5px; color: var(--ink-3);
  padding-top: 11px; border-top: 1px dashed var(--hair);
}
.sd-meta b { color: var(--ink); font-weight: 780; font-variant-numeric: tabular-nums; }
.sd-tip-note { margin-top: 10px; font-size: 12.5px; color: var(--faint); }

.sd-detail { padding: 15px 16px 17px; margin-bottom: 13px; }
.sd-detail .section-head { margin-bottom: 10px; }
.sd-detail p { margin: 0 0 11px; font-size: 14px; color: var(--ink-2); line-height: 1.8; }
.sd-detail p:last-child { margin-bottom: 0; }

.sd-adminbar { display: flex; align-items: center; gap: 8px; padding: 11px 14px; margin-bottom: 13px; }

/* --- 详情页底部操作条 ---
   手机：贴底，抬到悬浮导航（占位 14+62=76px）上面；
   PC  ：sticky 在内容列底部，滚到页尾自然落位。 */
.sd-bar-gap { height: 94px; }
.sd-bar {
  position: fixed; left: 0; right: 0; z-index: 60;
  bottom: calc(76px + env(safe-area-inset-bottom));
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px;
  background: rgba(255, 255, 255, .96);
  backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid var(--line);
}
.sd-bar-l { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sd-bar-p { display: flex; align-items: baseline; gap: 3px; font-size: 12.5px; font-weight: 700; color: #9C6F12; }
.sd-bar-p b { font-size: 21px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.sd-bar-out { font-size: 15px; font-weight: 780; color: var(--ink-2); }
.sd-bar .btn { flex: none; min-width: 116px; }
.sh-disabled { opacity: .55; pointer-events: none; }

/* ------------------------------------------------------------
   ③ 兑换浮层（.sh-mask / .sh-sheet）
   ------------------------------------------------------------
   ⚠️ 浮层用 hidden 属性控制显隐，而 `.sh-mask` 本体是 display:flex ——
      必须显式写 `.sh-mask[hidden]{display:none}`，否则 flex 会盖掉
      浏览器默认的 `[hidden]{display:none}`，点「关闭」关不掉。
   浮层写在页面 HTML 里（在 #root 内），切页时跟着被替换掉，
   不会出现技能里记过的「迟到的异步回调把已关闭的浮层重新弹出来」。 */
body.sh-lock { overflow: hidden; }

.sh-mask {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(8, 21, 44, .46);
  backdrop-filter: blur(2px);
  animation: shFade .18s ease;
}
.sh-mask[hidden] { display: none; }
@keyframes shFade { from { opacity: 0; } }
@keyframes shUp { from { transform: translateY(26px); opacity: .55; } }

.sh-sheet {
  width: 100%; max-width: 520px;
  max-height: 92vh; overflow-y: auto;
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: 0 -8px 40px rgba(8, 21, 44, .24);
  animation: shUp .22s cubic-bezier(.2, .8, .2, 1);
}
.sh-sheet-h {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: 9px;
  padding: 15px 18px 12px; border-bottom: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.sh-sheet-h b { font-size: 16px; font-weight: 780; }
.sh-x {
  margin-left: auto; width: 30px; height: 30px; border-radius: 50%;
  background: var(--surface-2); color: var(--ink-3);
  display: grid; place-items: center; font-size: 15px; cursor: pointer;
}
.sh-sheet-b { padding: 14px 18px 20px; }

/* 待兑商品摘要 */
.sh-pick {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 12px; margin-bottom: 15px;
  background: #FCFBF9; border: 1px solid var(--line); border-radius: var(--r-sm);
}
.sh-pick-img {
  flex: none; width: 54px; height: 54px; border-radius: 10px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 22px;
}
.sh-pick-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sh-pick-tx { flex: 1; min-width: 0; }
.sh-pick-t {
  font-size: 14px; font-weight: 750; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.sh-pick-s {
  font-size: 11.5px; color: var(--ink-3); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sh-pick-p { flex: none; text-align: right; color: #9C6F12; }
.sh-pick-p b { display: block; font-size: 19px; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.sh-pick-p span { font-size: 10.5px; font-weight: 650; }

/* 浮层内表单 */
.sh-fld { margin-bottom: 13px; }
.sh-fl { font-size: 12.5px; font-weight: 650; color: var(--ink-2); margin-bottom: 6px; }
.sh-fl i { font-style: normal; color: var(--danger); }
.sh-in {
  width: 100%; height: 43px; padding: 0 13px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: #FCFBF9; color: var(--ink);
  font-size: 14px; font-family: inherit; line-height: 1.5; outline: none; transition: .16s;
}
.sh-in:focus {
  border-color: var(--brand); background: var(--surface);
  box-shadow: 0 0 0 3.5px rgba(10, 90, 168, .12);
}
.sh-in::placeholder { color: var(--faint); }
.sh-area { height: auto; min-height: 78px; padding: 11px 13px; resize: vertical; }
.sa-area { min-height: 148px; }

.sh-seg { display: flex; gap: 8px; }
.sh-seg-i {
  flex: 1; text-align: center; cursor: pointer;
  padding: 9px 10px; border: 1.5px solid var(--line); border-radius: 11px;
  background: var(--surface); color: var(--ink-2);
  font-size: 13.5px; font-weight: 650; transition: .16s;
}
.sh-seg-i.on {
  border-color: var(--brand); background: var(--brand-050);
  color: var(--brand-ink); font-weight: 750;
}

.sh-pickup {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 13px;
  background: var(--gold-050); border: 1px solid #F0DFBC; border-radius: var(--r-sm);
}
.sh-pickup-ic {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--gold); color: #3A2A06; font-size: 17px;
}
.sh-pickup-t { font-size: 13.5px; font-weight: 750; color: #7A5717; }
.sh-pickup-s { font-size: 12px; color: #96773C; line-height: 1.6; margin-top: 3px; }
.sh-pickup-s b { color: #7A5717; font-weight: 780; }

.sh-balance {
  display: flex; align-items: center; justify-content: center;
  margin-top: 15px; font-size: 12.5px; color: var(--ink-3);
}
.sh-balance b { font-size: 15px; font-weight: 800; color: #9C6F12; margin: 0 3px; font-variant-numeric: tabular-nums; }

.sh-warn {
  margin-top: 11px; padding: 9px 12px; border-radius: 10px;
  background: #FCF3F2; border: 1px solid #EED9D6; color: var(--danger);
  font-size: 12.5px; line-height: 1.55;
}
.sh-warn[hidden] { display: none; }

.sh-submit { margin-top: 14px; height: 46px; font-size: 15.5px; border-radius: 13px; }

/* 兑换成功凭证卡 */
.sh-done { text-align: center; padding: 26px 20px 22px; }
.sh-done-ic {
  width: 58px; height: 58px; margin: 0 auto 13px; border-radius: 50%;
  display: grid; place-items: center;
  background: #E9F6EF; color: var(--ok); font-size: 29px;
}
.sh-done-t { font-size: 18px; font-weight: 800; }
.sh-done-s { font-size: 13px; color: var(--ink-3); margin-top: 6px; }
.sh-voucher {
  margin: 17px 0 18px; padding: 15px 16px;
  border: 1.5px dashed #E0C89A; border-radius: var(--r-sm);
  background: linear-gradient(180deg, #FFFDF8, var(--gold-050));
}
.sh-voucher-l { font-size: 11.5px; color: #96773C; letter-spacing: .12em; }
.sh-voucher-n {
  margin-top: 4px; font-size: 25px; font-weight: 800; color: #8A6414;
  letter-spacing: .06em; font-variant-numeric: tabular-nums;
}
.sh-voucher-d {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid #F0DFBC;
  font-size: 12.5px; color: #7A5717; font-weight: 650;
}
.sh-voucher-d svg { width: 15px; height: 15px; flex: none; }
.sh-done .btn + .btn { margin-top: 9px; }

/* 兑换浮层里的那句「兑换成功后，会告诉你这件东西怎么拿」——
   帆哥的要求是取货方式**兑换前不提**，但要让用户知道「后面会告诉我」，
   否则他会担心「我到底怎么拿到」。 */
.sh-note { margin-top: 10px; text-align: center; font-size: 12px; color: var(--faint); }

/* ---------- 取货方式区块（第 47 轮） ----------
   兑换成功页 + 我的兑换记录共用。左对齐（父级 .sh-done 是 text-align:center，
   表单必须掰回左对齐，否则 label 和输入框会居中参差）。 */
.sh-deliv {
  margin-top: 14px; padding: 13px 13px 12px;
  background: var(--surface-2, #F7F8FA); border-radius: var(--r-sm);
  text-align: left;
}
.sh-deliv-h { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.sh-deliv-t { font-size: 13px; font-weight: 780; color: var(--ink); }
.sh-deliv-seg { margin-left: auto; }
.sh-deliv-seg .sh-seg-i { padding: 5px 10px; font-size: 12px; }
.sh-deliv .sh-fld:last-of-type { margin-bottom: 4px; }
.sh-deliv-save { margin-top: 11px; }
.sh-deliv .sh-warn { margin-top: 8px; }
.sh-deliv-ok { }
.sh-deliv-ok .sh-deliv-h { margin-bottom: 6px; color: var(--ok, #1F7A54); }
.sh-deliv-ok .sh-deliv-h svg { width: 17px; height: 17px; margin-left: auto; }
.sh-deliv-info {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 13px; color: var(--ink-2); line-height: 1.6; word-break: break-all;
}
.sh-deliv-info svg { width: 15px; height: 15px; flex: none; margin-top: 3px; color: var(--ok, #1F7A54); }
.sh-deliv-sub { margin-top: 7px; font-size: 12px; color: var(--faint); }

/* 我的兑换记录里的「填写收货地址 / 选择取货方式」入口 */
.so-fill { margin-top: 8px; }
.so-row [data-slot="deliv"] { margin-top: 2px; }
.so-row [data-slot="deliv"] .sh-deliv { margin-top: 8px; }
.sq-wait span { color: var(--warn-ink, #9A6B10); }
.sq-wait-tx { color: var(--warn-ink, #9A6B10); font-weight: 700; }
.sq-hold { flex: none; padding: 0 2px; }

/* ------------------------------------------------------------
   ④ 我的兑换记录（.so-row）
   ------------------------------------------------------------ */
.so-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 14px; margin-bottom: 9px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--sh-1);
}
.so-img {
  flex: none; width: 58px; height: 58px; border-radius: 11px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 24px;
}
.so-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.so-tx { flex: 1; min-width: 0; }
.so-t { font-size: 14px; font-weight: 750; line-height: 1.45; }
.so-m { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 4px; font-size: 12px; color: var(--ink-3); }
.so-p { color: #9C6F12; font-weight: 750; }
.so-v { margin-top: 6px; font-size: 12px; color: var(--ink-2); }
.so-v b { font-family: var(--mono); font-weight: 700; letter-spacing: .02em; color: #8A6414; }
.so-tip {
  margin-top: 7px; padding: 5px 9px; border-radius: 8px;
  background: var(--brand-050); color: var(--brand-ink);
  font-size: 11.5px; line-height: 1.55;
}
.so-s {
  flex: none; padding: 4px 10px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-3);
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
}
.so-s.pending { background: #FDF3E3; color: var(--warn); }
.so-s.shipped { background: var(--brand-050); color: var(--brand-ink); }
.so-s.done { background: #E9F6EF; color: var(--ok); }
.so-s.canceled { background: var(--surface-2); color: var(--faint); }

/* ------------------------------------------------------------
   ⑤ 右栏「积分管家」（只在积分商城页出现）
   ------------------------------------------------------------
   回答三个问题 —— 我有多少分 / 现在能兑什么 / 还差多少，
   而不是把积分数字再显示一遍（那在个人卡里已经有了）。 */
.aside-shop { padding: 14px 15px 15px; }
.as-pts { display: flex; align-items: baseline; gap: 5px; }
.as-pts b {
  font-size: 26px; font-weight: 800; line-height: 1;
  color: #9C6F12; letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.as-pts span { font-size: 11.5px; color: var(--ink-3); }
.as-sub { font-size: 12px; color: var(--ink-2); margin-top: 6px; }
.as-sub b { color: var(--brand); font-weight: 780; font-variant-numeric: tabular-nums; }
.as-gap {
  margin-top: 10px; padding: 7px 9px; border-radius: 9px;
  background: var(--gold-050); border: 1px solid #F0DFBC;
  font-size: 11.5px; color: #96773C; line-height: 1.6;
}
.as-gap b { font-size: 14px; font-weight: 800; color: #8A6414; font-variant-numeric: tabular-nums; }
.as-gap-n { color: #7A5717; font-weight: 700; }
.as-item {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0; border-top: 1px solid var(--line); cursor: pointer;
}
.as-sub + .as-item { margin-top: 8px; }
.as-item:hover .as-item-t { color: var(--brand); }
.as-item-img {
  flex: none; width: 34px; height: 34px; border-radius: 9px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 16px;
}
.as-item-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.as-item-t {
  flex: 1; min-width: 0; font-size: 12.5px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.as-item-p { flex: none; font-size: 12.5px; font-weight: 780; color: #9C6F12; font-variant-numeric: tabular-nums; }
.as-acts { display: flex; gap: 8px; margin-top: 12px; }
.as-act {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 5px;
  height: 34px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--hair); background: var(--surface);
  color: var(--ink-2); font-size: 12.5px; font-weight: 700;
}
.as-act svg { width: 14px; height: 14px; flex: none; }
/* 两个入口里「去商城」是主行动，给它实心 */
.as-act:last-child {
  border-color: transparent; color: #fff;
  background: linear-gradient(180deg, var(--brand-600), var(--brand));
  box-shadow: 0 2px 7px rgba(10, 90, 168, .28);
}

/* ------------------------------------------------------------
   ⑥ 管理后台：商城管理（商品列表 + 兑换订单）
   ------------------------------------------------------------ */
.sh-sm { height: 32px; padding: 0 12px; font-size: 13px; border-radius: 9px; }
.btn.danger { color: var(--danger); border-color: #EED9D6; }
.btn.danger:hover { background: #FCF3F2; border-color: #E4C4C1; }

.sa-card { padding: 15px 16px 16px; margin-bottom: 14px; }
.sa-card .section-head { flex-wrap: wrap; }
.sh-admin-stats { margin-bottom: 22px; }

.sa-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.sa-item:first-of-type { border-top: 0; padding-top: 4px; }
.sa-img {
  flex: none; width: 52px; height: 52px; border-radius: 10px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 22px;
}
.sa-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sa-tx { flex: 1; min-width: 0; }
.sa-t {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  font-size: 14px; font-weight: 750; line-height: 1.4;
}
.sa-m { display: flex; flex-wrap: wrap; gap: 3px 12px; margin-top: 5px; font-size: 12px; color: var(--ink-3); }
.sa-p { color: #9C6F12; font-weight: 780; font-variant-numeric: tabular-nums; }
.sa-acts { flex: none; display: flex; gap: 7px; }

/* 兑换订单行 */
.sq-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 0; border-top: 1px solid var(--line);
}
.sq-row:first-of-type { border-top: 0; padding-top: 4px; }
.sq-img {
  flex: none; width: 48px; height: 48px; border-radius: 10px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 20px;
}
.sq-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sq-tx { flex: 1; min-width: 0; }
.sq-t { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 14px; font-weight: 750; line-height: 1.4; }
.sq-m { display: flex; flex-wrap: wrap; gap: 3px 12px; margin-top: 5px; font-size: 12px; color: var(--ink-3); }
.sq-m b { color: var(--ink); font-weight: 750; }
.sq-d {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 7px; padding: 6px 9px; border-radius: 8px;
  background: var(--surface-2); color: var(--ink-2);
  font-size: 11.5px; line-height: 1.6; word-break: break-all;
}
.sq-d svg { width: 13px; height: 13px; flex: none; margin-top: 3px; }
.sq-track { background: var(--brand-050); color: var(--brand-ink); font-weight: 650; }
.sq-acts { flex: none; display: flex; flex-direction: column; gap: 7px; }

/* ------------------------------------------------------------
   ⑦ 管理后台：上架 / 编辑商品表单
   ------------------------------------------------------------ */
.sa-import {
  margin-bottom: 14px; padding: 14px 15px;
  border: 1px solid #D8E5F4; border-radius: var(--r-md);
  background: linear-gradient(120deg, #F3F8FE, #FAFCFF);
}
.sa-import-h { display: flex; align-items: center; gap: 11px; }
.sa-import-ic {
  flex: none; width: 36px; height: 36px; border-radius: 11px;
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--brand-600), var(--brand));
  color: #fff; font-size: 18px;
  box-shadow: 0 3px 10px rgba(10, 90, 168, .28);
}
.sa-import-tx { flex: 1; min-width: 0; }
.sa-import-tx b { display: block; font-size: 14px; font-weight: 780; color: var(--brand-ink); }
.sa-import-tx span { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 3px; line-height: 1.5; }
.sa-import-body { margin-top: 13px; padding-top: 13px; border-top: 1px solid #DCE8F6; }
.sa-import-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 9px; margin-top: 11px; max-height: 320px; overflow-y: auto;
}
.sa-pick {
  padding: 7px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); cursor: pointer; transition: .16s; min-width: 0;
}
.sa-pick:hover { border-color: var(--brand); box-shadow: 0 2px 10px rgba(10, 90, 168, .12); }
.sa-pick.done { opacity: .5; }
.sa-pick-img {
  width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; overflow: hidden;
  background: var(--surface-2); color: var(--faint);
  display: grid; place-items: center; font-size: 22px;
}
.sa-pick-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sa-pick-t {
  margin-top: 6px; font-size: 11.5px; font-weight: 650; line-height: 1.4; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.sa-pick-m { margin-top: 3px; font-size: 11px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.sa-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 14px; }
.sa-fld { min-width: 0; margin-bottom: 12px; }
.sa-fld.sa-full { grid-column: 1 / -1; }
.sa-fl { display: block; font-size: 12.5px; font-weight: 650; color: var(--ink-2); margin-bottom: 6px; }
.sa-fl i { font-style: normal; color: var(--danger); }

.sa-imgs { display: flex; flex-wrap: wrap; gap: 9px; }
.sa-img-i {
  position: relative; width: 92px; height: 92px;
  border-radius: var(--r-sm); overflow: hidden;
  border: 1px solid var(--line); background: var(--surface-2);
}
.sa-img-i img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sa-img-x {
  position: absolute; right: 4px; top: 4px;
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(8, 21, 44, .66); color: #fff;
  font-size: 12px; cursor: pointer;
}
.sa-img-c {
  position: absolute; left: 0; bottom: 0;
  padding: 2px 7px; border-radius: 0 8px 0 0;
  background: var(--gold); color: #3A2A06;
  font-size: 10px; font-weight: 750;
}
.sa-img-add {
  width: 92px; height: 92px; border-radius: var(--r-sm);
  border: 1.5px dashed #C9D6E4; background: #FAFCFF;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--brand); font-size: 12px; font-weight: 650; cursor: pointer;
}
.sa-img-add svg { width: 18px; height: 18px; }
.sa-img-tip { font-size: 10px; color: var(--ink-3); font-weight: 500; }

.sa-pts-in { display: flex; align-items: center; gap: 8px; }
.sa-pts-in .sh-in { flex: 1; min-width: 0; }
.sa-pts-in > span { flex: none; font-size: 13px; color: var(--ink-3); }
.sa-band { margin-top: 7px; font-size: 12px; color: var(--ink-3); }
.sa-band b { color: var(--brand-ink); font-weight: 780; }
.sa-tip { margin-top: 6px; line-height: 1.55; }
.sa-helper {
  margin-top: 9px; padding: 9px 11px; border-radius: 10px;
  background: var(--gold-050); border: 1px solid #F0DFBC;
  font-size: 12.5px; color: #7A5717; line-height: 1.6;
}
.sa-helper[hidden] { display: none; }
.sa-helper b { font-size: 14px; font-weight: 800; color: #8A6414; font-variant-numeric: tabular-nums; }
.sa-helper-go {
  display: inline-block; margin-left: 8px; cursor: pointer;
  padding: 2px 10px; border-radius: 999px;
  background: var(--gold); color: #3A2A06;
  font-size: 11.5px; font-weight: 750;
}

.sa-radios { display: flex; flex-direction: column; gap: 9px; }
.sa-radios-row { flex-direction: row; }
.sa-radios-row .sa-r { flex: 1; }
.sa-r {
  display: block; cursor: pointer;
  padding: 11px 12px; border: 1.5px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); transition: .16s; min-width: 0;
}
.sa-r:hover { border-color: #D4CFC3; }
.sa-r.on { border-color: var(--brand); background: var(--brand-050); }
.sa-r i {
  display: inline-block; vertical-align: middle;
  width: 15px; height: 15px; margin-right: 7px; border-radius: 50%;
  border: 1.5px solid #C4C0B6; background: var(--surface);
  box-shadow: inset 0 0 0 3px var(--surface);
}
.sa-r.on i { border-color: var(--brand); background: var(--brand); }
.sa-r b { vertical-align: middle; font-size: 13.5px; font-weight: 750; }
.sa-r span { display: block; margin-top: 4px; font-size: 11.5px; color: var(--ink-3); line-height: 1.55; }
.sa-radios-row .sa-r span { display: none; }

.sa-foot {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin-top: 6px; padding-top: 15px; border-top: 1px solid var(--line);
}
.sa-foot #saMsg { flex: 1 1 100%; order: 2; }
#saMsg.err { color: var(--danger); font-weight: 650; }

/* ------------------------------------------------------------
   ⑧ 桌面端（≥900px）的版式切换
   ------------------------------------------------------------ */
@media (min-width: 900px) {
  /* 商品卡塌成单列：图上、文字下 */
  .sh-grid { grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 14px; }
  .sh-card {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "img" "t" "d" "bot";
    gap: 0; padding: 0; overflow: hidden;
  }
  .shc-img { width: 100%; height: auto; aspect-ratio: 4 / 3; border-radius: 0; }
  .shc-t { padding: 12px 13px 0; font-size: 14px; }
  .shc-d { padding: 4px 13px 0; align-self: start; -webkit-line-clamp: 2; }
  .shc-bot { margin: 10px 0 0; padding: 10px 13px 12px; }
  .shc-p b { font-size: 19px; }
  .shc-btn { padding: 8px 15px; font-size: 13px; }

  /* 详情页底部条改成内容列内 sticky */
  .sd-bar-gap { height: 0; }
  .sd-bar {
    position: sticky; bottom: 18px; z-index: 5;
    padding: 13px 16px; border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: rgba(255, 255, 255, .97);
    box-shadow: var(--sh-2);
  }

  /* 兑换浮层改成居中弹窗 */
  .sh-mask { align-items: center; }
  .sh-sheet { border-radius: var(--r-lg); max-height: 86vh; max-width: 720px; }
  .sh-sheet { animation: shUp .2s cubic-bezier(.2, .8, .2, 1); }

  /* 商品图不让它占满整列宽（PC 上太大会看不到价格） */
  .sd-hero:not(.swiper) img { max-height: 420px; }
}

/* 手机端两栏表单退成一栏 —— 上架表单在窄屏上横着排两个输入框会挤成一团 */
@media (max-width: 720px) {
  .sa-form { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .sa-import-h { flex-wrap: wrap; }
  .sa-import-h .spacer { display: none; }
  .sa-import-h .btn { flex: 1 1 100%; margin-top: 4px; }
  .sa-item { flex-wrap: wrap; }
  .sa-acts { flex: 1 1 100%; justify-content: flex-end; }
  .sq-row { flex-wrap: wrap; }
  .sq-acts { flex: 1 1 100%; flex-direction: row; justify-content: flex-end; }
  .sa-radios-row { flex-direction: column; }
  .sa-radios-row .sa-r span { display: block; }
}

/* 极窄屏：商品卡左右两栏再收一档，给右侧说明留出可读宽度 */
@media (max-width: 359px) {
  .sh-card { grid-template-columns: 78px minmax(0, 1fr); gap: 7px 10px; padding: 11px; }
  .shc-img { width: 78px; height: 78px; }
  .shc-p b { font-size: 18px; }
  .shc-btn { padding: 7px 14px; font-size: 13px; }
  .sh-voucher-n { font-size: 22px; }
  .so-img { width: 50px; height: 50px; }
}

/* ===========================================================
   全站广播条（2026-09-21 帆哥定版 · 版本⑤「素白细描」）
   -----------------------------------------------------------
   出现位置（四选一由 app.js 的 noticeBarHtml() 决定，样式只有这一份）：
     ① 首页「频道」标题上方      ② 圈子页搜索框下方
     ③ 频道页介绍条与列表之间    ④ 帖子详情正文上方
   PC 与手机共用同一份 DOM —— 帆哥要求电脑端也显示，所以这里
   **不写任何 display:none**；宽度天然受限于 .col-main 的内容列。
   设计稿：_design/broadcast/云帆圈子-全站广播滚动条-设计稿.html
   =========================================================== */
.notice-bar{
  display:flex;align-items:center;gap:9px;height:38px;padding:0 12px 0 11px;
  margin:0 0 14px;overflow:hidden;position:relative;
  background:#fff;border:1.2px solid #E5DCC6;border-radius:11px;color:#25303C;
  box-shadow:0 1px 3px rgba(16,24,40,.045);
}
.notice-bar .nhorn{flex:none;display:grid;place-items:center;width:22px;height:22px;color:#C8A15A}
.notice-bar .nhorn svg{width:18px;height:18px}
.notice-bar .nvp{
  flex:1;min-width:0;overflow:hidden;position:relative;
  mask-image:linear-gradient(90deg,transparent,#000 11px,#000 calc(100% - 26px),transparent);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 11px,#000 calc(100% - 26px),transparent);
}
.notice-bar .ntk{display:inline-flex;align-items:center;white-space:nowrap;will-change:transform}
/* .moving 由 initNoticeMotion() 在「内容确实超宽」时才加上 ——
   一条短公告静止显示，比在那儿来回晃更像正式通告 */
.notice-bar .ntk.moving{animation:notice-mq var(--mq-dur,30s) linear infinite}
@keyframes notice-mq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
/* 静止态（内容放得下、不用滚）：把循环用的第二份副本和末尾那个分隔点藏掉，
   就干净地显示一句话 —— 宽屏上不会露出重复的半句 */
.notice-bar .ntk:not(.moving) [data-dup],
.notice-bar .ntk:not(.moving) .ndot-end{display:none}
.notice-bar .nmi{font-size:13.5px;letter-spacing:.01em;cursor:pointer}
.notice-bar .ndot{width:4px;height:4px;border-radius:50%;margin:0 22px;flex:none;background:#E0D8C3}
.notice-bar .nmeta{
  flex:none;font-size:14px;line-height:1;color:#98917C;
  border-left:1px solid #EFE9DA;padding-left:10px;
}
/* 悬停暂停：长公告可以定住看完 */
.notice-bar:hover .ntk.moving{animation-play-state:paused}
@media (prefers-reduced-motion: reduce){ .notice-bar .ntk.moving{animation:none} }

@media (max-width:520px){
  .notice-bar{gap:7px;padding:0 10px 0 9px;margin-bottom:12px}
  .notice-bar .nmi{font-size:12.5px}
  .notice-bar .ndot{margin:0 16px}
}

/* 后台「全站广播」编辑卡：预览条与编辑卡之间不要多一层底 */
.notice-edit .field:last-of-type{margin-bottom:12px}

/* 独立公告详情页 */
.notice-detail { border-left: 3px solid var(--brand); }

/* 后台历史公告列表 */
.notice-history { display: flex; flex-direction: column; gap: 8px; }
.notice-history-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--bg-card);
}
.notice-history-row.on { background: var(--brand-050); border-color: var(--brand-100); }
.nhr-main { flex: 1; min-width: 0; }
.nhr-text { font-size: 14px; font-weight: 600; color: var(--text); margin-bottom: 5px; }
.nhr-meta { display: flex; align-items: center; gap: 8px; }
.nhr-acts { display: flex; gap: 6px; flex-shrink: 0; }

/* 公告正文编辑框放大 */
.textarea-body {
  min-height: 160px;
  line-height: 1.65;
  font-size: 14px;
  padding: 12px 14px;
}

/* ==========================================================================
   消息通知体系覆盖层（2026-09-21 下午 · 帆哥要求）
   --------------------------------------------------------------------------
   帆哥四条要求对应到下面四段：
     ① 底栏「我的」小人右上角一个小红点（.tab-dot，不带数字）
     ② 「我的消息」前面的小铃铛有未读就摇晃（.has-unread 触发）
     ③ 「我的消息」后面显示 +N（+1 = 1 条未读，依次）
     ④ 消息列表按类型分色（.nt-*），一眼扫得出哪条要紧
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚整段删掉即可 ——
      里面只新增类名，不改动上面任何已有选择器。
   ========================================================================== */

/* ---------------- ① 底栏「我的」：小人右上角的小红点 ---------------- */
/* 把图标裹进 .tab-ic 当定位参照。
   旧写法是相对整块 .tab 硬凑坐标（top:5px; left:50%; translateX(3px)），
   那个落点由 tab 高度和字号共同决定，换机型或改字号就会漂：
   实测 390px 下角标中心在 (362,800)，而小人图标右上角是 (362,796)，
   垂直方向已经差了 4px —— 再往里塞数字就直接压到小人头上。 */
.tab .tab-ic { position: relative; display: grid; place-items: center; }
.tab .tab-ic > svg { width: 22px; height: 22px; }
.tab .tab-dot {
  position: absolute; top: -1px; right: -3px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #E0473C;
  /* 白色描边圈：红点直接压在蓝色小人身上会糊成一块，垫一圈底色才分得开 */
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .96);
}

/* ---------------- ②③「我的消息」：铃铛摇晃 + 文案后 +N ---------------- */
/* 标签不再 flex:1 —— 原来它吃掉全部剩余宽度，把角标顶到行最右边；
   帆哥要的是「我的消息 +1」贴着读成一句话，
   所以标签按内容宽，由箭头用 margin-left:auto 顶到行尾。 */
.me-msg .mm-t { flex: 0 1 auto; }
.me-msg .mm-arrow { margin-left: auto; }
.me-msg .mm-b {
  flex: none;
  height: 20px; padding: 0 7px; border-radius: 10px;
  background: #E0473C; color: #fff;
  font-size: 12px; font-weight: 750; letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
  display: inline-grid; place-items: center;
}

/* 铃铛摇晃：一波摇 4 下、然后静一段，每 4 秒一轮。
   为什么不一直摇：满屏都在动会让人烦躁，而且铃铛是入口不是内容；
   为什么尾巴要留长静止段：不停歇的循环动效会被大脑当背景噪声直接过滤掉。 */
@keyframes bellRing {
  0%, 46%, 100% { transform: rotate(0); }
  4%   { transform: rotate(13deg); }
  9%   { transform: rotate(-11deg); }
  14%  { transform: rotate(9deg); }
  19%  { transform: rotate(-7deg); }
  24%  { transform: rotate(5deg); }
  29%  { transform: rotate(-3deg); }
  34%  { transform: rotate(1.5deg); }
  39%  { transform: rotate(0); }
}
.me-msg.has-unread .mm-ico {
  animation: bellRing 4s ease-in-out infinite;
  transform-origin: 50% 14%;   /* 支点靠近铃铛顶部，摇出来才像铃铛而不是钟摆 */
  color: #E0473C;              /* 有未读时铃铛转红，与 +N 呼应 */
}
/* 系统开了「减少动态效果」就不摇：循环动画对前庭敏感人群不友好 */
@media (prefers-reduced-motion: reduce) {
  .me-msg.has-unread .mm-ico { animation: none; }
}

/* ---------------- ④ 消息列表：类型分色 + 未读强调 ---------------- */
.nt-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 15px; margin-bottom: 10px;
}
.nt-item.clickable { cursor: pointer; }
.nt-item.clickable:hover { background: var(--surface-2); }
/* 未读：淡蓝底 + 左侧一道品牌色竖条。
   只靠右上角一个小红点，一屏十条扫下来很容易漏。 */
.nt-item.on {
  background: linear-gradient(90deg, rgba(10, 90, 168, .055), rgba(10, 90, 168, .012) 62%);
  box-shadow: inset 3px 0 0 var(--brand);
}
.nt-item.read { opacity: .74; }
.nt-ico {
  flex: none; width: 38px; height: 38px; border-radius: 11px;
  display: grid; place-items: center;
}
.nt-ico svg { width: 19px; height: 19px; }
.nt-main { min-width: 0; flex: 1; }
.nt-line { font-size: 13.5px; line-height: 1.5; color: var(--ink); word-break: break-word; }
.nt-line b { font-weight: 700; }
.nt-meta { display: flex; align-items: center; gap: 7px; margin-top: 5px; font-size: 11.5px; color: var(--faint); }
.nt-tag {
  flex: none; padding: 1px 6px; border-radius: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
}
.nt-dot {
  flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--danger); margin-top: 7px;
}

@media (max-width: 520px) {
  .nt-item { padding: 12px 13px; gap: 10px; }
  .nt-ico { width: 34px; height: 34px; border-radius: 10px; }
  .nt-ico svg { width: 17px; height: 17px; }
  .nt-line { font-size: 13px; }
}

/* ===========================================================================
   正文富文本编辑器（2026-09-21 帆哥要求）
   ---------------------------------------------------------------------------
   ⚠️ 本段是**末尾追加的覆盖层**，必须留在文件最后。
      要回滚整段删掉即可，前面几千行原样未动。
   为什么另起一套 .rte-* 而不是复用 .textarea：
      .textarea 的样式是给原生 textarea 的（padding/resize/单个块），
      contenteditable 需要「工具栏 + 可编辑区 + 弹层」三层结构，
      硬套会让 .textarea 的规则反过来破坏编辑器布局。
   =========================================================================== */

.rte {
  position: relative;
  border: 1px solid var(--hair);
  border-radius: 11px;
  background: var(--surface);
  transition: .16s;
}
.rte:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 3.5px rgba(10, 90, 168, .12);
}

/* ---------------------------- 工具栏 ---------------------------- */
.rte-bar {
  position: relative;                 /* 弹层的定位参照 */
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px;
  padding: 6px 6px;
  border-bottom: 1px solid var(--line);
  background: #FAF9F6;
  border-radius: 10px 10px 0 0;
}
.rte-b {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 25px; height: 27px; padding: 0 5px;
  border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--ink-2);
  font-family: inherit; font-size: 12.5px; line-height: 1;
  cursor: pointer; transition: .12s;
  -webkit-tap-highlight-color: transparent;
}
.rte-b:hover { background: #F0EEE9; color: var(--ink); }
.rte-b:active { transform: scale(.94); }
.rte-b.on { background: var(--brand-050); color: var(--brand-ink); border-color: rgba(10, 90, 168, .22); }
.rte-b svg { width: 15px; height: 15px; display: block; }
.rte-b b, .rte-b i, .rte-b u, .rte-b s { font-size: 13.5px; }
.rte-w { padding: 0 4px; white-space: nowrap; }
.rte-cv { margin-left: 2px; font-size: 9px; opacity: .55; transform: translateY(1px); }
.rte-sp { flex: none; width: 1px; height: 15px; margin: 0; background: var(--line); }

/* ---------------------------- 弹层 ---------------------------- */
.rte-pop {
  position: absolute; left: 8px; top: 40px; z-index: 40;
  width: 268px; max-width: calc(100% - 16px);
  padding: 9px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 13px;
  box-shadow: 0 14px 34px rgba(9, 22, 46, .16);
}
.rte-pop[hidden] { display: none; }
/* 弹层右上角的 × 关闭按钮（2026-09-23 帆哥）。
   `.rte-pop` 自身是 position:absolute，已经自成包含块，所以直接 absolute 挂上去即可，
   不用改任何一个弹层的内容布局。
   标题（.rte-pop-t）右侧预留 24px，长标题不会钻到 × 底下。 */
.rte-pop-x {
  position: absolute; top: 4px; right: 4px; z-index: 2;
  width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 7px;
  background: transparent; color: var(--ink-3);
  cursor: pointer; transition: .12s;
  -webkit-tap-highlight-color: transparent;
}
.rte-pop-x:hover { background: #F0EEE9; color: var(--ink); }
.rte-pop-x:active { transform: scale(.9); }
.rte-pop-x svg { width: 12px; height: 12px; display: block; }
.rte-pop-t { padding-right: 24px; }
.rte-pop-t { font-size: 11px; font-weight: 700; color: var(--ink-3); letter-spacing: .04em; margin: 0 2px 7px; }
.rte-pop-list { display: flex; flex-direction: column; gap: 3px; }
.rte-opt {
  display: block; width: 100%; padding: 7px 9px;
  border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--ink);
  font-family: inherit; font-size: 13px; text-align: left; line-height: 1.35;
  cursor: pointer; transition: .12s;
}
.rte-opt:hover { background: var(--brand-050); border-color: rgba(10, 90, 168, .16); }

/* 颜色 / 高亮：一排色块 */
.rte-sw { display: flex; flex-wrap: wrap; gap: 7px; padding: 2px; }
.rte-sw-b {
  width: 27px; height: 27px; padding: 0; border-radius: 50% !important;
  border: 1px solid rgba(19, 26, 46, .10);
  box-shadow: inset 0 0 0 2px #fff;
}
.rte-none {
  display: grid; place-items: center; width: 100%; height: 100%;
  font-size: 10px; color: var(--ink-3); border-radius: 50%;
  background: #fff; box-shadow: inset 0 0 0 1px var(--line);
}

/* 表情 */
.rte-emo { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.rte-emo-b {
  aspect-ratio: 1 / 1; padding: 0; border: 0; border-radius: 8px;
  background: transparent; font-size: 19px; line-height: 1;
  cursor: pointer; transition: .12s; -webkit-tap-highlight-color: transparent;
}
.rte-emo-b:hover { background: var(--brand-050); }

/* ---------------------------- 编辑区 ---------------------------- */
.rte-area {
  position: relative;
  min-height: 156px; max-height: 60vh; overflow-y: auto;
  padding: 12px 13px;
  font-size: 15px; line-height: 1.78; color: var(--ink-2);
  outline: none; word-break: break-word; white-space: pre-wrap;
}
.rte-area.is-empty::before {
  content: attr(data-ph);
  position: absolute; left: 13px; top: 12px;
  color: var(--faint); pointer-events: none;
}
.rte-area p { margin: 8px 0; }
.rte-area p:first-child { margin-top: 0; }
.rte-area p:last-child { margin-bottom: 0; }
.rte-area ul, .rte-area ol { margin: 8px 0; padding-left: 22px; }
.rte-area li { margin: 3px 0; }
.rte-area blockquote {
  margin: 8px 0; padding: 2px 0 2px 11px;
  border-left: 3px solid var(--line); color: var(--ink-3);
}
.rte-area a { color: var(--brand); text-decoration: underline; }
.rte-area table { border-collapse: collapse; margin: 8px 0; }
.rte-area td, .rte-area th { border: 1px solid var(--line); padding: 4px 8px; font-size: 13px; }

.rte-foot {
  display: flex; align-items: center; gap: 10px;
  padding: 0 12px 9px;
  font-size: 11.5px; color: var(--faint);
}
.rte-tip { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#cpRteCount { flex: none; }
#cpRteCount.over { color: var(--danger); font-weight: 700; }

/* ---------------------------- 手机端 ---------------------------- */
@media (max-width: 899px) {
  /* 手机端把工具栏压成**一行横滑**：折行会占掉 3 行（实测 107px），
     而首屏最宝贵的就是正文编辑区。横滑与相册筛选行是同一套交互语言，
     最常用的「加粗 / 字体 / 字号 / 颜色 / 表情」都在首屏可见范围内。 */
  .rte-bar {
    flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    padding: 6px; gap: 2px;
    mask-image: linear-gradient(90deg, #000 0, #000 96%, transparent 100%);
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 96%, transparent 100%);
  }
  .rte-bar::-webkit-scrollbar { display: none; }
  .rte-bar > * { flex: none; }                     /* 不压缩、不换行，只滚动 */
  .rte-b { min-width: 30px; height: 30px; }        /* 手指点得准的最小高度 */
  .rte-b svg { width: 16px; height: 16px; }
  .rte-area { min-height: 176px; padding: 11px 12px; font-size: 15px; line-height: 1.76; }
  .rte-area.is-empty::before { left: 12px; top: 11px; }
  .rte-pop { left: 6px; width: auto; right: 6px; max-width: none; padding: 10px; }
  .rte-pop-x { top: 5px; right: 5px; width: 26px; height: 26px; }   /* 手指点得准 */
  .rte-sw { gap: 9px; }
  .rte-sw-b { width: 32px; height: 32px; }
  .rte-emo { grid-template-columns: repeat(8, 1fr); gap: 1px; }
  .rte-emo-b { font-size: 21px; }
  .rte-tip { display: none; }                       /* 手机上留给字数，说明文字省掉 */
  .rte-foot { justify-content: flex-end; padding: 0 12px 8px; }
}

/* ===== 消息列表头像修复（2026-09-21 晚 · 帆哥反馈头像太大） =====
   根因：JS 生成 class="avatar s38"，但尺寸体系里没有 .s38 ——
   体系只有 s20/24/28/30/32/36/40/44/48/64/72/96。
   aside-me(s46)、me-av(s92) 没崩是因为父容器给了尺寸覆盖；
   消息列表 .nt-item 没有父级兜底，头像失控占半屏。
   修法与项目既有模式一致（aside-me / me-av 同款）：父级选择器覆盖尺寸，
   同时补上 .avatar.s38 防止未来再有人用 38。 */
.avatar.s38 { width: 38px; height: 38px; font-size: 14px; }
.nt-item .avatar { width: 42px; height: 42px; font-size: 15px; }
@media (max-width: 899px) {
  .nt-item .avatar { width: 40px; height: 40px; font-size: 14px; }
}

/* ===========================================================
   2026-09-21（第19轮）覆盖层 —— 本段留在文件最后，前面的规则一行未动，
   要回滚整段删掉即可。
   ① 全站广播滚动条：PC 端也要滚（位移改用 --mq-shift）
   ② 积分榜「榜单」行：等级徽章左边缘对齐
   =========================================================== */

/* ① 位移 = 「一份内容的宽」，由 initNoticeMotion() 按实测宽度写进像素值。
      原来的 to{translateX(-50%)} 在轨道铺 3 份时只走了 1.5 份，接缝会跳一下。
      保留 -50% 作兜底：万一变量没设上（脚本没跑到），退回原行为。 */
@keyframes notice-mq{
  from{transform:translateX(0)}
  to{transform:translateX(var(--mq-shift,-50%))}
}

/* ② 积分榜榜单行：分数列宽由 JS 按本榜最大位数写成内联 min-width（N ch），
      这里只负责「右对齐 + 数字等宽 + 不被 flex 压缩」。
      三者齐备，等级徽章的左边缘才会每行落在同一竖线上（原来随分数位数右侧游走）。 */
.lb-row .lv-badge { flex: none; }
.lb-row .lb-pts {
  flex: none; text-align: right; font-variant-numeric: tabular-nums;
  font-weight: 700; color: var(--brand-600); font-size: 15px;
}


/* ===========================================================================
   2026-09-21 云帆圈子六项需求（1~6）新增组件
   ---------------------------------------------------------------------------
   全部追加在文件末尾 —— 靠「后者覆盖前者」的层叠顺序生效，不动上面任何既有
   选择器。要回滚这一批 UI，删掉这一段即可，不会牵连老样式。
   配色一律取 :root 里的变量（品牌色 --brand、金色 --gold 等），不写死色值，
   免得以后换主色时这里漏掉。
   =========================================================================== */

/* ---------------------------------------------------------------------------
   需求 2：发布页「同步到群」滑动开关
   --------------------------------------------------------------------------- */
.sw-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px;
  background: var(--surface-2);
  border-radius: var(--r-sm);
}
.sw-tx { min-width: 0; }
.sw-n { font-size: 14px; font-weight: 600; color: var(--ink); }
.sw-d { margin-top: 3px; font-size: 12px; line-height: 1.6; color: var(--ink-3); }

/* 开关本体：轨道 50×30、滑块 24，开启 = 品牌色 + 滑块右移 20px（50-24-3-3）。
   用 <button role="switch"> 而不是 <input type="checkbox">：本项目的表单控件
   是统一重写样式的，原生 checkbox 在钉钉 WebView / iOS Safari 里的渲染差异太大，
   做不到「左右移动」这个明确要求。 */
.sw {
  flex: none; position: relative;
  width: 50px; height: 30px; padding: 0;
  border: none; border-radius: 999px;
  background: #CBD2DE; cursor: pointer;
  transition: background .22s ease;
}
.sw i {
  position: absolute; top: 3px; left: 3px;
  width: 24px; height: 24px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 4px rgba(16, 24, 40, .28);
  transition: transform .22s cubic-bezier(.3, .9, .3, 1);
}
.sw.on { background: var(--brand); }
.sw.on i { transform: translateX(20px); }
.sw:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   需求 6：详情页浏览者头像（小眼睛前面那一串小圆圈）
   --------------------------------------------------------------------------- */
.pv-viewers {
  display: inline-flex; align-items: center;
  padding-left: 2px; cursor: pointer;
}
.pv-viewers:empty { display: none; }
/* 头像互相压 7px，读起来是「一串人」而不是「一排按钮」 */
.pv-av { display: inline-block; margin-left: -7px; }
.pv-av:first-child { margin-left: 0; }
.pv-av .avatar {
  border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgba(16, 24, 40, .10);
}
/* 超过 5 人 → 第 5 个（最后一个可见的）向右逐渐虚化，暗示「后面还有一大堆」。
   用 mask 渐变而不是 opacity：整块变淡看起来像「禁用」，
   右半边淡出去才读得出「被截断、还有更多」。 */
.pv-viewers.over .pv-av:nth-child(5) .avatar {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, rgba(0, 0, 0, .06) 100%);
  mask-image: linear-gradient(90deg, #000 0%, rgba(0, 0, 0, .06) 100%);
}
.pv-hit { cursor: pointer; white-space: nowrap; }
.pv-viewers:hover .avatar { transform: translateY(-1px); }

/* ---------------------------------------------------------------------------
   需求 3 / 6 共用弹层（预览二维码、浏览者名单）
   --------------------------------------------------------------------------- */
.mk-mask {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(8, 21, 44, .55);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: mkFade .18s ease;
}
@keyframes mkFade { from { opacity: 0 } to { opacity: 1 } }
.mk-card {
  width: 100%; max-width: 470px;
  max-height: 88vh; overflow: auto;
  padding: 18px 20px 20px;
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
  animation: mkPop .2s cubic-bezier(.3, .9, .3, 1);
}
@keyframes mkPop {
  from { transform: translateY(10px) scale(.98); opacity: 0 }
  to { transform: none; opacity: 1 }
}
.mk-h { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
.mk-t { font-size: 16px; font-weight: 700; color: var(--ink); }
.mk-x {
  flex: none; width: 30px; height: 30px;
  border: none; border-radius: 50%;
  background: var(--surface-2); color: var(--ink-2);
  font-size: 19px; line-height: 1; cursor: pointer;
}
.mk-x:hover { background: var(--line); color: var(--ink); }
.mk-tip { margin-top: 10px; text-align: center; font-size: 13px; color: var(--ink-2); }
.mk-note { margin-top: 12px; text-align: center; font-size: 12px; line-height: 1.7; color: var(--ink-3); }

/* 预览弹层：二维码 + 链接 */
.pv-qr { display: flex; justify-content: center; padding: 2px 0; }
.pv-qr img {
  width: 220px; height: 220px; display: block;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #fff;
}
.pv-link { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.pv-link .input { flex: 1; min-width: 0; font-size: 12px; }

/* 浏览者名单：每排 10 个（帆哥指定的列数）。
   窄屏**不降列数**，只等比缩小头像与字号 —— 降列数就不是他要的东西了。 */
.vw-grid {
  display: flex; flex-wrap: wrap;
  gap: 13px 0;
  /* 每排 10 个：每格固定 10% 宽、横向不留 gap（留了就会 9 个换行）。
     用 flex 而不是 grid，是为了让**不满 10 人的最后一行居中** ——
     grid 固定 10 列时，7 个人会全挤在左边、右边空一大块，看着像没渲染完。 */
  justify-content: center;
}
.vw-i { flex: 0 0 10%; min-width: 0; text-align: center; }
.vw-i .avatar { margin: 0 auto; }
.vw-n {
  margin-top: 4px; font-size: 11px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vw-t {
  font-size: 10px; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 560px) {
  .mk-card { padding: 16px 14px 18px; }
  .vw-grid { gap: 10px 0; }
  /* 与 .avatar.s44 同特异度（都是两个 class），本段在文件末尾 → 覆盖生效 */
  .vw-i .avatar { width: 30px; height: 30px; font-size: 11px; }
  .vw-n { font-size: 9px; }
  .vw-t { display: none; }   /* 手机上一列只有 30px，时间放不下，改由 title 提示 */
}

/* ---------------------------------------------------------------------------
   需求 3：#/preview/:token 只读预览页
   --------------------------------------------------------------------------- */
.pv-banner {
  margin-bottom: 12px; padding: 10px 14px;
  background: var(--gold-050);
  border-left: 3px solid var(--gold);
  border-radius: var(--r-xs);
  font-size: 13px; color: #8A6415;
}
.pv-bad { font-size: 15px; font-weight: 600; color: var(--danger); }

/* ---------------------------------------------------------------------------
   需求 3：「我的草稿」卡片（个人主页「我的内容」上面那一块）
   --------------------------------------------------------------------------- */
.draft-card {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 10px; padding: 12px 14px;
  /* 草稿是「未完成」的东西：左侧一道金边 + 极浅的暖底，跟已发布内容拉开层次 */
  background: linear-gradient(180deg, #FFFDF7, var(--surface));
  border-left: 3px solid var(--gold);
}
.dc-cov {
  flex: none; width: 54px; height: 54px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-xs); overflow: hidden;
  background: var(--surface-2); color: var(--faint);
}
.dc-cov img { width: 100%; height: 100%; object-fit: cover; }
.dc-tx { flex: 1; min-width: 0; }
.dc-t {
  font-size: 14px; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dc-e {
  margin-top: 2px; font-size: 12px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dc-m { margin-top: 6px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.dc-edit { flex: none; }
@media (max-width: 520px) {
  .dc-cov { width: 44px; height: 44px; }
  .dc-e { display: none; }   /* 手机上标题 + 两个标签已经够识别了 */
}

/* ---------------------------------------------------------------------------
   需求 5：正文编辑器里的插图
   --------------------------------------------------------------------------- */
/* 正文插图不设死宽高（那是作者在编辑器里拖出来的），只约束「不许撑破版面」：
   宽度不超过正文区，高度按比例。手机端正文区本来就只有 320 来 px，
   一张 4000px 的原图直接顶出去会把整个详情页撑出横向滚动条。 */
.rte-area img,
.rt-body img,
.pd-body img {
  max-width: 100%; height: auto;
  border-radius: var(--r-xs);
  display: block;
  margin: 10px 0;
}
/* 编辑态给插图一个可见的边框，让作者知道「这是一张图、不是装饰」 */
.rte-area img { border: 1px solid var(--line); }
/* ============================================================
   第二十轮覆盖层（2026-09-21 第二轮需求）
   ① 侧栏「云帆官网」外链项
   ② 云帆故事页（使命/愿景/价值观/文化专题/典型案例/发展史）
   ③ 编辑器扩展：插图、附件、表格、视频链接、图片拖动与尺寸手柄
   ④ 发帖页「谁可以看」与「@ 提醒谁看」
   ⑤ 详情页的可见范围提示
   前十九轮的规则一行未动；要回滚，整段删掉即可。
   ============================================================ */

/* ---------- ① 侧栏外链项 ----------
   NAV 里的外链用 <a>（新窗口）而不是 <div data-act="nav">（站内 hash 路由）。
   <a> 自带下划线与颜色，必须显式清掉，否则侧栏里会出现一条带下划线的蓝字。 */
.nav-item.nav-ext { text-decoration: none; color: inherit; }
.nav-out {
  margin-left: auto; flex: none;
  font-size: 12px; opacity: .45; transition: opacity .16s;
}
.nav-item.nav-ext:hover .nav-out { opacity: .95; }

/* ---------- ② 云帆故事 ---------- */
.sy-hero {
  position: relative;
  padding: 34px 30px 28px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 150% at 88% -20%, rgba(200, 161, 90, .30), transparent 58%),
    linear-gradient(140deg, #08152C 0%, #10305F 62%, #17457F 100%);
  color: #fff;
  overflow: hidden;
  margin-bottom: 14px;
}
.sy-kicker {
  font-size: 11px; font-weight: 700; letter-spacing: .16em;
  color: var(--gold-300); text-transform: uppercase; margin-bottom: 14px;
}
.sy-title {
  margin: 0 0 14px; font-size: 30px; line-height: 1.32; font-weight: 750;
  letter-spacing: -.01em;
}
.sy-title em { font-style: normal; color: var(--gold-300); }
.sy-lead {
  margin: 0 0 22px; max-width: 620px;
  font-size: 14px; line-height: 1.85; color: rgba(255, 255, 255, .80);
}
.sy-stats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  padding-top: 18px; border-top: 1px solid rgba(255, 255, 255, .14);
}
.sy-stat b {
  display: block; font-size: 21px; font-weight: 750; color: #fff;
  letter-spacing: -.01em; margin-bottom: 3px;
}
.sy-stat span { font-size: 11.5px; line-height: 1.5; color: rgba(255, 255, 255, .62); }

.sy-nav {
  display: flex; flex-wrap: wrap; gap: 7px;
  margin-bottom: 14px;
}
.sy-nav-b {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 14px;
  border: 1px solid var(--hair); border-radius: 999px;
  background: var(--surface); color: var(--ink-2);
  font-size: 13px; font-weight: 600; cursor: pointer;
  transition: .16s;
}
.sy-nav-b:hover { border-color: var(--brand); color: var(--brand-ink); background: var(--brand-050); }
.sy-nav-no { font-size: 10.5px; font-weight: 800; color: var(--faint); letter-spacing: .05em; }
.sy-nav-b:hover .sy-nav-no { color: var(--brand); }

.sy-sec { padding: 26px 28px; margin-bottom: 14px; scroll-margin-top: 18px; }
.sy-sec-head { display: flex; align-items: baseline; gap: 11px; margin-bottom: 16px; flex-wrap: wrap; }
.sy-sec-head h2 { margin: 0; font-size: 18.5px; font-weight: 750; letter-spacing: -.01em; }
.sy-sec-no {
  font-size: 12px; font-weight: 800; color: var(--gold);
  letter-spacing: .06em;
}
.sy-sec-sub { margin-left: auto; font-size: 12px; color: var(--ink-3); }

/* 使命(01) + 愿景(02) 一行两块（2026-09-22 帆哥：「两个模块并列放，一排放两个」）。
   ------------------------------------------------------------------
   并排是**可选**的：只有两块都配了图时 app.js 才会套上 .sy-pair（见 storyInner）。
   两张图都是 1279×720（≈16:9），满宽时高度 ≈ 宽度的 56%，一块就吃掉大半屏；
   并排后每格半宽，图高直接减半 —— 1440 下实测 383px 高 → 171px。

   横向间距 14px，与 .sy-sec 的 margin-bottom 同值，横竖看起来是一个体系。
   不写 align-items：默认 stretch，两块卡片等高，比一高一矮好看（两张图同尺寸、本来也等高，
   但编辑态里图片地址条长短不同会把高度拉开）。

   ⚠️ **列数交给 auto-fit，不写「多少 px 以上才并排」的硬断点。**
      这个页面的内容列宽不是单调的：.shell 在 900px 加左栏、1100px 再加右栏，
      于是 899→871px、900→574px、1100→496px（最窄）、1284→680px、1440→736px ——
      中间 1100~1199 是一道「谷」。硬断点只会把这道谷切得很难看，实测 1100 下
      每格图只剩 183px 宽，图上的字全糊；而 899px 那条又宽达 871px。
      auto-fit + minmax(280px, 1fr) 的语义正好是「放得下两块才放两块」：
        内容列 ≥ 574px(=280×2+14) → 两块；否则自动回落一块，图反而看得清。
      实测：899→两块 428px；1100→单块（图 438px）；1284/1440→两块。
      注：auto-fit 会把**空轨道折叠**，所以列数比条目多时两块会各自撑开，不会挤在左边。

   ⚠️ **row-gap 必须是 0**。.sy-sec 自带 margin-bottom:14px，而 grid item 的 margin
      不会和 gap 合并（外层是 grid，不是普通块流），写 gap:14px 就成了
      「14 边距 + 14 间隙 = 28」—— 回落单列时两块之间凭空多 14px。
      实测抓到的：899/820/760/600/430 这几档页面比改造前各高 14px，改回 gap:0 14px 后归零。

   ⚠️ 手机（<600px）显式锁单列。auto-fit 到 585px 左右本来也会自己回落，
      但「手机上就是一列」是不该靠算出来才知道的结论，写死更好读。 */
.sy-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 0 14px;
}
@media (max-width: 599px) {
  .sy-pair { grid-template-columns: 1fr; }
}
.sy-quote {
  padding: 16px 20px;
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--r-xs) var(--r-xs) 0;
  background: var(--brand-050);
  color: var(--brand-ink); font-size: 17px; font-weight: 700; line-height: 1.6;
  margin-bottom: 14px;
}
.sy-p { margin: 0; font-size: 14px; line-height: 1.9; color: var(--ink-2); }

.sy-vals { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.sy-val {
  display: flex; gap: 13px; padding: 16px 17px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.sy-val-no {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand); color: #fff; font-size: 12px; font-weight: 800;
}
.sy-val b { display: block; font-size: 14.5px; font-weight: 700; margin-bottom: 6px; }
.sy-val p { margin: 0; font-size: 13px; line-height: 1.8; color: var(--ink-3); }

.sy-culs { display: grid; grid-template-columns: repeat(2, 1fr); gap: 11px; margin-top: 14px; }
.sy-cul {
  padding: 15px 17px; border-radius: var(--r-sm);
  background: linear-gradient(140deg, var(--brand-050), #fff);
  border: 1px solid rgba(10, 90, 168, .12);
}
.sy-cul b { display: block; font-size: 14px; font-weight: 700; color: var(--brand-ink); margin-bottom: 6px; }
.sy-cul p { margin: 0; font-size: 12.5px; line-height: 1.8; color: var(--ink-2); }

.sy-cases { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.sy-case {
  display: flex; flex-direction: column;
  padding: 17px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
}
.sy-case-t { font-size: 14px; font-weight: 700; line-height: 1.55; margin-bottom: 8px; }
.sy-case-d { margin: 0 0 14px; font-size: 12.5px; line-height: 1.8; color: var(--ink-3); flex: 1 1 auto; }
.sy-case-k {
  display: flex; gap: 16px; padding-top: 13px;
  border-top: 1px dashed var(--hair);
}
.sy-case-k b { display: block; font-size: 17px; font-weight: 750; color: var(--brand-600); letter-spacing: -.01em; }
.sy-case-k span { font-size: 11px; color: var(--faint); }

/* 发展史时间轴（2026-09-22 帆哥：「年份和后面那个圆都挨住了，不好看」）
   ------------------------------------------------------------------
   老版本的几何是错的，四个值各写各的、互相对不上：
     .sy-hiss padding-left 26  +  年份格 46  +  gap 16  → 正文列起点 x=88
     圆点 left:-24 → 圆点占 x=64~73，而年份格占到 x=72
   → 圆点**压在年份格的右边缘上**，年份文字（15px/800 的「2018」约 35px 宽，
     实际占到 x≈61）离圆点只剩 3px；实测量出来是 **0.5px**（手机档 -9.2px，圆点直接压住年份），
     看着就是贴在一起。竖线（老值 left:62）也落在年份格**里面**，语义上就不对。

   现在改成「先定死三件事，其余由它们推出来」，整条链子只有一处能错：
     ① 圆点要离年份 13px
     ② 圆点**真实占位 13px**（⚠️ 不是声明值 9px，见下方 box-sizing 说明）
     ③ **正文列左边缘保持原值 88px 不动** ← 这一条最关键，见下面的「不改宽度」说明
   由 ①② 反推：年份右边缘 → 圆点左边缘 13px，圆点占 13px
              ⇒ gap 取 26px：留给「圆点右边缘 → 正文」8px 的呼吸位
              ⇒ 圆点相对 .sy-his-b 的偏移 = 13(离年份) - 26(gap) = -13px
   由 ③：padding-left + 年份列宽 + gap = 88，gap = 26 ⇒ padding-left + 46 = 62 ⇒ padding-left = 16
   竖线：圆点圆心 = 88 - 13 + 13/2 = 81.5 ⇒ left = 81.5 - 1（线宽 2）= 80.5，圆心正中

   ⚠️ box-sizing 的坑（真机实测才暴露，第一版按 9px 推导致圆心反向偏 2px）：
     全局那句是 `* { box-sizing: border-box }` —— 星号**不匹配伪元素**，
     所以 .sy-his-b::before 的 width:9px 是 content-box 宽度，两侧各加 2.5px 边框后
     真实占位 = 9 + 2.5×2 = 14px；而且 border-width 的 getComputedStyle 返回的是**用化后**的值：
     dsf=1 的桌面读到 2px、dsf=2 的手机读到 2.5px —— 即真机上圆点实际是 13~14px。
     所以圆心按 13px（实测值）定，桌面偏移 0；dsf=2 时残留 0.5px，肉眼不可辨。
     注意：**圆点外观一行没动**（仍是白芯 + 蓝环的 13px 圆），只挪竖线。
     用户抱怨的是「年份和圆挨住」，没抱怨圆点大小，就不该顺手改它。

   🚨 **不改宽度**：正文列左边缘必须留在 88px。老代码里年份格是**左对齐**的，正文从 88px 开始；
      第一版修复把它推到了 96px（padding-left 24 + 46 + 26），看着没问题，但正文列凭空窄了 8px ——
      实测 1100px 下「发展史」整块高了 **47px**（两行描述各多折一行），
      1440/1364 因为正文列够宽才没暴露。宁可把年份往左挪 10px，也不动正文的起点。
      年份改**右对齐**：七个年份都是 4 位数，视觉完全不变，但保证间距恒定 ——
      左对齐时间距会随数字实际宽度浮动（实测 2022/2024/2025/2026 宽 38.5~39.2px，
      2018 只有 37.5px），那就又要靠肉眼去赌了。 */
.sy-hiss { position: relative; padding-left: 16px; }
.sy-hiss::before {
  content: ''; position: absolute; left: 80.5px; top: 6px; bottom: 6px;
  width: 2px; background: var(--line); border-radius: 2px;
}
.sy-his { display: flex; gap: 26px; padding: 11px 0; position: relative; }
.sy-his-y {
  flex: none; width: 46px; text-align: right; padding-top: 1px;
  /* nowrap 是必需项，不是保险：年份格一旦不够宽，浏览器会把「2024」折成「202 4」
     两行（390×844 上实测抓到过）。折行后 .sy-his 是 flex、元素高度反而不变，
     靠量高度根本发现不了。实测：老值 36px 的格子里，2022/2024/2025/2026 四个
     年份文字（36.8px）全超格。宁可溢出（方向是往左、有 padding-left 兜着）也不折行。 */
  white-space: nowrap;
  font-size: 15px; font-weight: 800; color: var(--brand); letter-spacing: -.01em;
}
.sy-his-b { position: relative; padding-left: 4px; }
.sy-his-b::before {
  content: ''; position: absolute; left: -13px; top: 6px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--surface); border: 2.5px solid var(--brand);
}
.sy-his-b b { display: block; font-size: 14px; font-weight: 700; margin-bottom: 4px; }
.sy-his-b p { margin: 0; font-size: 13px; line-height: 1.82; color: var(--ink-3); }

.sy-foot {
  padding: 20px 22px; border-radius: var(--r-md);
  background: var(--gold-050); border: 1px solid rgba(200, 161, 90, .28);
}
.sy-foot-t { font-size: 14px; font-weight: 700; color: #8A6415; margin-bottom: 7px; }
.sy-foot-d { font-size: 12.5px; line-height: 1.8; color: #8A6415; opacity: .9; }
.sy-foot-d a { color: #8A6415; font-weight: 700; }

/* ---------- ③ 编辑器扩展 ---------- */

/* 正文里的图片：可拖动排序，所以要给出「能拖」的指针提示 */
.rte-area img { max-width: 100%; height: auto; border-radius: 6px; cursor: grab; }
.rte-area img.rte-img-sel { outline: 2px solid var(--brand); outline-offset: 2px; }
.rte-area img.rte-img-dragging {
  opacity: .78; cursor: grabbing; z-index: 5; position: relative;
  box-shadow: 0 12px 30px rgba(8, 21, 44, .22);
  transition: none;
}

/* 拖出来的尺寸手柄（只在有鼠标的设备上创建） */
.rte-img-handle {
  position: fixed; z-index: 91;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--brand); border: 2.5px solid #fff;
  box-shadow: 0 3px 10px rgba(8, 21, 44, .30);
  cursor: nwse-resize; touch-action: none;
}
.rte-img-handle[hidden] { display: none; }

/* 表格：编辑器里与渲染页（.rt-body）都要。老帖的 .rtable 规格表样式不动。 */
.rte-table { border-collapse: collapse; width: 100%; margin: 10px 0; font-size: 13.5px; }
.rte-table td, .rte-table th {
  border: 1px solid var(--hair); padding: 7px 10px;
  vertical-align: top; min-width: 44px; line-height: 1.7;
}
.rte-table th { background: var(--surface-2); font-weight: 700; color: var(--ink); }
.rt-body table.rte-table { margin: 12px 0; }

/* 表格选择器（工具栏「插入表格」拖选行列数） */
.rte-tp {
  position: fixed; z-index: 92;
  padding: 10px 11px;
  background: var(--surface); border: 1px solid var(--hair); border-radius: var(--r-sm);
  box-shadow: 0 16px 44px rgba(8, 21, 44, .18);
  animation: cpBoardDown .16s ease;
}
.rte-tp[hidden] { display: none; }
.rte-tp-h {
  font-size: 11.5px; font-weight: 700; color: var(--ink-3);
  margin-bottom: 7px; letter-spacing: .02em;
}
.rte-tp-g { display: grid; gap: 2px; }
.rte-tp-c {
  width: 15px; height: 15px; display: block;
  border: 1px solid var(--hair); border-radius: 2.5px;
  background: var(--surface); transition: background .1s;
}
.rte-tp-c.on { background: var(--brand); border-color: var(--brand); }

/* 单元格操作条 */
.rte-cb {
  position: fixed; z-index: 92;
  display: flex; align-items: center; gap: 2px;
  padding: 5px 6px; border-radius: 10px;
  background: var(--navy-800);
  box-shadow: 0 12px 34px rgba(8, 21, 44, .32);
}
.rte-cb[hidden] { display: none; }
.rte-cb button {
  height: 27px; padding: 0 9px;
  border: none; border-radius: 7px;
  background: transparent; color: rgba(255, 255, 255, .86);
  font-size: 12px; font-weight: 600; cursor: pointer;
  white-space: nowrap; transition: .14s;
}
.rte-cb button:hover { background: rgba(255, 255, 255, .16); color: #fff; }
.rte-cb-sp { width: 1px; height: 15px; margin: 0 3px; background: rgba(255, 255, 255, .22); }

/* 正文附件卡片 */
a.rte-file {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 3px 0; padding: 8px 13px;
  border: 1px solid var(--hair); border-radius: var(--r-xs);
  background: var(--surface-2); color: var(--brand-ink) !important;
  font-size: 13.5px; font-weight: 650; text-decoration: none !important;
  transition: .16s;
}
a.rte-file:hover { border-color: var(--brand); background: var(--brand-050); }

/* 正文视频链接卡片 */
a.rte-video {
  display: inline-flex; align-items: center; gap: 9px;
  margin: 4px 0; padding: 11px 16px;
  border-radius: var(--r-xs);
  background: linear-gradient(135deg, #0B1E3C, #17457F);
  color: #fff !important; font-size: 13.5px; font-weight: 650;
  text-decoration: none !important;
  box-shadow: 0 6px 18px rgba(8, 21, 44, .18);
}
a.rte-video:hover { filter: brightness(1.12); }

/* 视频弹层里的输入行 */
.rte-vd { display: flex; gap: 7px; align-items: center; }
.rte-vd-in {
  flex: 1 1 auto; min-width: 0; height: 36px; padding: 0 11px;
  border: 1px solid var(--hair); border-radius: 9px;
  font-size: 13px; background: var(--surface); color: var(--ink);
}
.rte-vd-in:focus { outline: none; border-color: var(--brand); }
.rte-vd-tip {
  margin-top: 9px; font-size: 11.5px; line-height: 1.7;
  color: var(--ink-3); max-width: 330px;
}

/* ---------- ④ 发帖页：谁可以看 + @提醒谁看 ---------- */
.cp-hint { margin-top: 7px; line-height: 1.7; }

.cp-sel { position: relative; }
.cp-sel-bar {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 42px; padding: 0 13px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface); cursor: pointer; transition: .16s;
  font-family: inherit; text-align: left;
}
.cp-sel-bar:hover { border-color: var(--brand); }
.cp-sel-tx { font-size: 14px; color: var(--ink-3); }
.cp-sel-tx.on { color: var(--brand-ink); font-weight: 650; }
.cp-sel-pop {
  margin-top: 6px; padding: 8px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(8, 21, 44, .12);
  animation: cpBoardDown .18s ease;
}
.cp-sel-pop[hidden] { display: none; }
.cp-sel-search { margin-bottom: 6px; }
.cp-sel-list { max-height: 250px; overflow-y: auto; }
.cp-vis-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border-radius: 9px;
  cursor: pointer; transition: .14s;
}
.cp-vis-item:hover { background: var(--surface-2); }
.cp-vis-item.on { background: var(--brand-050); }
.cp-vis-item input { flex: none; width: 16px; height: 16px; accent-color: var(--brand); cursor: pointer; }
.cp-vis-name { font-size: 13.5px; font-weight: 600; }
.cp-vis-n { margin-left: auto; font-size: 11.5px; color: var(--faint); }

.cp-mt { position: relative; }
.cp-mt-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cp-mt-chips:not(:empty) { margin-bottom: 8px; }
.cp-mt-chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 27px; padding: 0 6px 0 11px;
  border-radius: 999px;
  background: var(--brand-050); color: var(--brand-ink);
  font-size: 13px; font-weight: 650;
}
.cp-mt-chip button {
  width: 17px; height: 17px; border: none; border-radius: 50%;
  background: rgba(10, 90, 168, .14); color: var(--brand-ink);
  font-size: 13px; line-height: 1; cursor: pointer; padding: 0;
}
.cp-mt-chip button:hover { background: rgba(10, 90, 168, .3); }
.cp-mt-inwrap { position: relative; }
.cp-mt-res {
  position: absolute; left: 0; right: 0; top: calc(100% + 5px);
  z-index: 30; max-height: 300px; overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--surface);
  box-shadow: 0 14px 38px rgba(8, 21, 44, .16);
  animation: cpBoardDown .16s ease;
}
.cp-mt-res[hidden] { display: none; }
.cp-mt-group {
  padding: 8px 10px 5px;
  font-size: 11px; font-weight: 700; color: var(--faint);
  letter-spacing: .06em;
}
.cp-mt-row {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 8px 10px;
  border: none; border-radius: 9px; background: transparent;
  cursor: pointer; text-align: left; font-family: inherit;
  transition: .14s;
}
.cp-mt-row:hover { background: var(--brand-050); }
.cp-mt-ico {
  flex: none; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--ink-3);
}
.cp-mt-ico svg { width: 15px; height: 15px; }
.cp-mt-tx { min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.cp-mt-tx b { font-size: 13.5px; font-weight: 650; color: var(--ink); }
.cp-mt-tx em { font-style: normal; font-size: 11.5px; color: var(--faint); }

/* ---------- ⑤ 详情页可见范围提示 ---------- */
.pd-vis {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 10px 0 2px; padding: 8px 13px;
  border-radius: var(--r-xs);
  background: var(--gold-050); border: 1px solid rgba(200, 161, 90, .3);
  color: #8A6415; font-size: 12.5px; line-height: 1.6;
}
.pd-vis svg { width: 14px; height: 14px; flex: none; }
.pd-vis b { font-weight: 700; }

/* ---------- 手机端适配 ---------- */
@media (max-width: 760px) {
  /* 故事页：多列全部回落到单列，否则 390px 宽会把案例卡压成一条 */
  .sy-hero { padding: 26px 20px 22px; }
  .sy-title { font-size: 23px; }
  .sy-lead { font-size: 13.5px; }
  .sy-stats { grid-template-columns: repeat(2, 1fr); gap: 14px 10px; }
  .sy-sec { padding: 20px 17px; }
  .sy-vals, .sy-culs, .sy-cases { grid-template-columns: 1fr; }
  .sy-quote { font-size: 15px; padding: 13px 15px; }
  /* 发展史：同一套「先定三件事再推其余」的算法，数字收窄一档。
       ⚠️ 手机这一档**没法**保住正文列起点：窄屏下年份格至少要 42px（最宽年份 36.8px），
          圆点 13px 加两侧间距，留给年份的只剩很小一块，正文列必定左移约 14px。
          代价实测：390px 上「发展史」整块高 24px（一行描述多折一行）。
          这是让年份和圆点不再贴住所必须付的、且已经是最小的代价 —— 想靠缩小年份字号
          省回来会连带把年份做得比正文标题还小，不值当。
       算式：年份右边缘 = 10 + 42 = 52 → 正文列左边缘 = 52 + 24 = 76
             gap 24 ⇒ 年份→圆点 = 24 - 13 = 11px
             圆点实占 63~76（13px，非声明值 9px），圆心 69.5 ⇒ 竖线 left 68.5 穿圆心 */
  .sy-hiss { padding-left: 10px; }
  .sy-hiss::before { left: 68.5px; }
  .sy-his { gap: 24px; }
  .sy-his-y { width: 42px; font-size: 14px; }
  .sy-his-b::before { left: -13px; }
  .sy-sec-sub { margin-left: 0; width: 100%; }
  /* 故事页锚点条：手机上一行放不下，允许横向滚动 */
  .sy-nav { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 3px; -webkit-overflow-scrolling: touch; }
  .sy-nav-b { flex: none; }
  /* 表格：手机上宽表横向滚动，不要撑破卡片 */
  .rte-area .rte-table, .rt-body .rte-table { display: block; overflow-x: auto; white-space: nowrap; }
  .rte-cb { max-width: calc(100vw - 16px); overflow-x: auto; }
  .rte-vd-tip { max-width: none; }
}

/* ===========================================================================
   2026-09-21 频道页顶部合并条 + 底栏发布按钮跟频道色
   ---------------------------------------------------------------------------
   帆哥拍板（依据设计稿「频道条定稿（方案 C 调整版）」）：
   ① 频道页顶部原来两块（频道白卡 76 + 间隙 14 + 公告条 38 = 128px）合成一条
   ② 频道名后的「N 帖」去掉、右侧「+」去掉、版主头像前加上「版主」二字
   ③ 底栏发布按钮：圆角长方形 → 正圆，且**在哪个频道就跟哪个频道的色**
   ④ 首页 / 圈子 / 相册 / 我的没有所属板块，保持原来的蓝紫不动
   结构： [频道名胶囊]  📢 公告（弹性，占满剩余）  ……  版主 [头像][名字]
   ---------------------------------------------------------------------------
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚：整段删掉，
      再把 app.js 里的 boardBarHtml() 一并回滚即可（server.js / db.js 无关）。
   =========================================================================== */

/* ---------- ⓐ 实底色（大色块专用的沉色版） ----------
   上面 :root 里那组 --bd-* 是给「3.5×14px 的小竖线 / 小圆点」用的鲜艳版；
   而频道条胶囊（26px 高、装整个频道名）和发布按钮（⌀42）是**大色块**，
   同样这几个鲜色铺上去会发飘，白字压不住。
   尺寸差着两个数量级，取色本来就不该共用一套 —— 故另开这组沉一点的实底版。 */
:root {
  --bd-blue-s:   linear-gradient(135deg, #0B63B8, #10305F);
  --bd-indigo-s: linear-gradient(135deg, #6272C4, #3C49A0);
  --bd-amber-s:  linear-gradient(135deg, #D9A24A, #B07A22);
  --bd-teal-s:   linear-gradient(135deg, #35A392, #16786A);
  --bd-rose-s:   linear-gradient(135deg, #D4798F, #B04E68);
  --bd-slate-s:  linear-gradient(135deg, #8593A2, #5F6B78);
  --bd-gold-s:   linear-gradient(135deg, #C9A24A, #9E7A2E);
}
/* ---------- ⓑ 频道条本体 ---------- */
.board-bar {
  display: flex; align-items: center; gap: 10px;
  height: 50px; padding: 0 11px; margin: 0 0 14px;
  border-radius: 12px; overflow: hidden;
  background: var(--bd-soft, #EFF5FC);        /* 各 accent 在上面那组变量里给 */
  border: 1px solid rgba(19, 26, 46, .05);
}
/* ⚠️ 每行同时给两个地方供色：频道页顶部那条（.board-bar）和后台「频道版主」页里
   那个小频道名胶囊（.bdm-name）。共用一组变量，改色只改这一处。
   🔴 关键在于**浅底只给 .board-bar、渐变只给 .bdm-name**：
   一开始把 background 直接写在下面这条规则里，结果 .bdm-name 也吃到了那个浅底色，
   白字压在近白底上等于看不见（后台一眼就露馅）。所以拆成两个变量：
     --bd-grad = 实底渐变（胶囊、按钮用）    --bd-soft = 对应的浅底（整条用） */
.board-bar.a-blue,   .bdm-name.a-blue   { --bd-grad: var(--bd-blue-s);   --bd-soft: #EFF5FC; --bb-deep: #0B63B8; }
.board-bar.a-indigo, .bdm-name.a-indigo { --bd-grad: var(--bd-indigo-s); --bd-soft: #F1F2FC; --bb-deep: #3C49A0; }
.board-bar.a-amber,  .bdm-name.a-amber  { --bd-grad: var(--bd-amber-s);  --bd-soft: #FDF6EA; --bb-deep: #B07A22; }
.board-bar.a-teal,   .bdm-name.a-teal   { --bd-grad: var(--bd-teal-s);   --bd-soft: #EEF8F6; --bb-deep: #16786A; }
.board-bar.a-rose,   .bdm-name.a-rose   { --bd-grad: var(--bd-rose-s);   --bd-soft: #FDF2F5; --bb-deep: #B04E68; }
.board-bar.a-slate,  .bdm-name.a-slate  { --bd-grad: var(--bd-slate-s);  --bd-soft: #F2F4F6; --bb-deep: #5F6B78; }
.board-bar.a-gold,   .bdm-name.a-gold   { --bd-grad: var(--bd-gold-s);   --bd-soft: #FBF6EA; --bb-deep: #9E7A2E; }

/* 频道名胶囊。⚠️ 必须用 block + line-height 而不是 inline-flex：
   flex 容器会把里面的文字变成匿名 flex item，text-overflow:ellipsis 就失效了
   —— 长频道名（如「产品档案与上架」）会直接撑出去把公告挤成 0 宽。 */
.board-bar .bb-cap {
  flex: none; display: block; max-width: 36%;
  height: 26px; padding: 0 10px; line-height: 26px; border-radius: 8px;
  background: var(--bd-grad); color: #fff;
  font-size: 13px; font-weight: 750; letter-spacing: -.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  box-shadow: 0 2px 6px rgba(19, 26, 46, .13);
}

/* ---------- ⓒ 条里的公告区：把独立那一版的白壳重置掉 ----------
   公告的 DOM 是 noticeBarHtml() 的原样产物（.notice-bar/.nvp/.ntk 三个类名照旧），
   这样 initNoticeMotion() 完全不用改就继续工作 —— 跑马灯的份数、位移、
   无缝循环那些逻辑一行都没碰。这里只把「独立一条」时的白底米框去掉，
   让它坐在频道条的 accent 浅底上。 */
.board-bar .notice-bar {
  flex: 1; min-width: 0;
  height: auto; margin: 0; padding: 0;
  background: none; border: 0; box-shadow: none;
}
.board-bar .notice-bar .nhorn { width: 15px; height: 15px; color: var(--bb-deep); opacity: .85; }
.board-bar .notice-bar .nhorn svg { width: 15px; height: 15px; }
/* 右侧那个「›」在合并条里省掉：整条本来就是 data-act="notice" 可点，
   箭头只是提示，却要占掉约 11px 的公告宽度。 */
.board-bar .notice-bar .nmeta { display: none; }
.board-bar .notice-bar .nmi { font-size: 13px; color: #49535F; }
/* 左边不需要渐隐（前面就是喇叭图标），只留右侧；手机端在下面加宽 */
.board-bar .notice-bar .nvp {
  mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent);
}
.board-bar .notice-bar .ndot { margin: 0 18px; background: var(--bb-deep); opacity: .3; }
/* 没有公告时的静态占位：不可点、不许滚 */
.board-bar .notice-bar.is-empty .nmi { color: var(--ink-3); cursor: default; }

/* ---------- ⓓ 版主组 ----------
   margin-left:auto 是「贴到最右边」的实现 —— 公告区是 flex:1 会把剩余宽度吃满，
   靠这个 auto 把版主顶到条尾，而不是靠固定宽度凑。 */
.board-bar .bb-mod {
  flex: none; margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
}
.board-bar .bb-lb {
  font-style: normal; font-size: 11px; font-weight: 600;
  color: var(--ink-3); letter-spacing: .02em; white-space: nowrap;
}
.board-bar .bb-avs { display: inline-flex; align-items: center; }
.board-bar .bb-av {
  width: 21px; height: 21px; border-radius: 50%; flex: none;
  object-fit: cover; display: block;
  border: 1.5px solid #fff; box-shadow: 0 1px 3px rgba(19, 26, 46, .16);
}
.board-bar .bb-av + .bb-av { margin-left: -7px; }      /* 双版主时头像叠放 */
.board-bar .bb-avt {                                    /* 没头像的兜底：首字渐变块 */
  display: grid; place-items: center;
  background: var(--bd-grad); color: #fff;
  font-size: 10px; font-weight: 700; font-style: normal;
}
.board-bar .bb-nm {
  font-size: 12px; font-weight: 650; color: var(--ink-2);
  max-width: 120px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- ⓔ 底栏发布按钮跟频道色 ----------
   只在频道页生效：render() 在 route.name === 'board' 时给 <body> 挂 data-bd="rose"，
   离开时把属性删掉（**删**而不是写回一个默认色 —— 默认色是基础规则里那句
   var(--brand)/var(--violet)，写死两份的话以后换品牌色要改两处）。
   特异度 (0,3,1) 高于前面主题段的 .tab-pub .pub-circle (0,2,0)，能稳稳盖住。 */
body[data-bd="blue"]   .tab-pub .pub-circle { background: var(--bd-blue-s);   box-shadow: 0 6px 15px rgba(11, 99, 184, .36); }
body[data-bd="indigo"] .tab-pub .pub-circle { background: var(--bd-indigo-s); box-shadow: 0 6px 15px rgba(60, 73, 160, .36); }
body[data-bd="amber"]  .tab-pub .pub-circle { background: var(--bd-amber-s);  box-shadow: 0 6px 15px rgba(176, 122, 34, .36); }
body[data-bd="teal"]   .tab-pub .pub-circle { background: var(--bd-teal-s);   box-shadow: 0 6px 15px rgba(22, 120, 106, .36); }
body[data-bd="rose"]   .tab-pub .pub-circle { background: var(--bd-rose-s);   box-shadow: 0 6px 15px rgba(176, 78, 104, .36); }
body[data-bd="slate"]  .tab-pub .pub-circle { background: var(--bd-slate-s);  box-shadow: 0 6px 15px rgba(95, 107, 120, .36); }
body[data-bd="gold"]   .tab-pub .pub-circle { background: var(--bd-gold-s);   box-shadow: 0 6px 15px rgba(158, 122, 46, .36); }

/* ---------- ⓕ 手机端 ----------
   390px 里要放「频道名 + 公告 + 版主」三组。减法只做一处：**版主的名字不显示**，
   只留「版主」二字 + 头像 —— 头像叠着看已经能认出人，名字留给 PC。 */
@media (max-width: 760px) {
  .board-bar { height: 48px; gap: 8px; padding: 0 10px; margin-bottom: 12px; }
  .board-bar .bb-cap { height: 25px; line-height: 25px; padding: 0 9px; font-size: 12.5px; max-width: 38%; }
  .board-bar .bb-lb { font-size: 10px; }
  .board-bar .bb-av { width: 19px; height: 19px; }
  .board-bar .bb-nm { display: none; }
  .board-bar .notice-bar .nmi { font-size: 12.5px; }
  /* 渐隐加宽到 34px：公告是硬裁的，过渡太窄会看到半截字紧贴着「版主」 */
  .board-bar .notice-bar .nvp {
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent);
  }
  .board-bar .notice-bar .ndot { margin: 0 14px; }
}

/* ---------- ⓖ 后台「频道版主」页（2026-09-21） ----------
   一个频道一行：频道名胶囊 + 当前版主 chips + 「+ 添加」。
   点「+ 添加」在下面展开候选面板（搜索 + 一排可点的候选人）。
   频道名胶囊与频道页顶部那条共用 --bd-grad，颜色不会两处对不上。 */
.bdm-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 0; border-bottom: 1px solid var(--line);
}
.bdm-name {
  flex: none; display: block; max-width: 160px;
  height: 24px; padding: 0 10px; line-height: 24px; border-radius: 7px;
  background: var(--bd-grad, var(--brand)); color: #fff;
  font-size: 12px; font-weight: 700; letter-spacing: -.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bdm-mods { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.bdm-none { font-size: 12px; color: var(--faint); }
.bdm-chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 28px; padding: 0 5px 0 3px; border-radius: 14px;
  background: var(--surface-2); border: 1px solid var(--line); font-size: 12px;
}
.bdm-chip b { font-weight: 600; color: var(--ink-2); }
.bdm-chip i {
  font-style: normal; cursor: pointer; flex: none;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center; color: var(--faint); font-size: 13px; line-height: 1;
}
.bdm-chip i:hover { background: #F7DEDB; color: #C0392B; }

.bdm-picker { padding: 2px 0 14px; border-bottom: 1px solid var(--line); }
.bdm-picker[hidden] { display: none; }
.bdm-q { height: 36px; margin-bottom: 9px; font-size: 13.5px; }
.bdm-list { display: flex; flex-wrap: wrap; gap: 6px; max-height: 216px; overflow-y: auto; }
.bdm-opt {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 11px 0 4px; border-radius: 15px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 12.5px; cursor: pointer; transition: .13s;
}
.bdm-opt:hover { border-color: var(--brand); background: var(--brand-050); }
.bdm-opt b { font-weight: 600; }
.bdm-opt i { font-style: normal; font-size: 11px; color: var(--faint); }

/* ---------------------------------------------------------------------------
   我的草稿卡 · 右侧按钮组（2026-09-21 帆哥要求「编辑后面加个按钮，删除」）
   ---------------------------------------------------------------------------
   原来只有一颗「编辑」，直接挂成 .draft-card 的 flex item 就够用；
   现在两颗并排，用一个容器把它们绑在一起 —— 不包一层的话，.draft-card 的
   gap:12px 会在两颗按钮之间也插 12px，看着像两个互不相干的控件。
   .dc-acts 用 flex:none 保证「标题再长也不挤到按钮」。
   --------------------------------------------------------------------------- */
.dc-acts { flex: none; display: flex; align-items: center; gap: 6px; }
.dc-acts .btn { flex: none; }
@media (max-width: 520px) {
  /* 手机端 44px 封面 + 标题 + 两颗按钮同排：把按钮横向留白收一档，
     保证标题仍有 170px 以上可显示（390px 视口实测）。 */
  .dc-acts { gap: 5px; }
  .dc-acts .btn { padding: 0 10px; }
}

/* =====================================================================
   成员管理：搜索 + 「圈子职务 / 职务权限」面板（2026-09-21 第二轮 · 帆哥）
   ===================================================================== */

.am-card { padding: 0 18px 8px; }
.am-head { position: sticky; top: 0; z-index: 4; background: var(--surface);
  padding: 14px 0 8px; border-bottom: 1px solid var(--line); margin-bottom: 2px; }

/* 搜索框：跟首页那个 .home-search 同一套观感，只是宽度撑满 */
.am-search { position: relative; display: flex; align-items: center; gap: 8px; }
.am-search svg { position: absolute; left: 12px; width: 17px; height: 17px;
  color: var(--ink-3); pointer-events: none; }
.am-search input {
  flex: 1; height: 42px; padding: 0 38px 0 38px;
  border: 1px solid var(--hair); border-radius: 13px;
  background: var(--surface-2); color: var(--ink);
  font-family: inherit; font-size: 14px; outline: none; transition: .15s;
}
.am-search input::placeholder { color: var(--faint); }
.am-search input:focus { background: var(--surface); border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-050); }
.am-clr {
  position: absolute; right: 8px; width: 26px; height: 26px; padding: 0;
  display: grid; place-items: center; border: 0; border-radius: 50%;
  background: var(--surface-2); color: var(--ink-3);
  font-size: 12px; line-height: 1; cursor: pointer;
}
.am-clr:hover { background: var(--line); color: var(--ink); }

.am-stat { display: flex; align-items: center; margin-top: 8px; }

/* ⚠️ .row 是 display:flex，光写 hidden 属性是不生效的 —— 搜索过滤靠的就是 hidden */
.am-row[hidden] { display: none; }
.am-row { padding: 11px 0; border-bottom: 1px solid var(--line); }
.am-row:last-child { border-bottom: 0; }

.am-cv { margin-left: 3px; font-size: 9px; opacity: .55; }

/* 列表右侧那个职务按钮：三种身份三种颜色，一眼扫过去就知道谁是干嘛的 */
.am-btn-full { border-color: rgba(74, 91, 240, .35); background: var(--brand-050); color: var(--brand-ink); font-weight: 600; }
.am-btn-board { border-color: rgba(34, 184, 230, .4); background: #E8F7FC; color: #0B6E8C; font-weight: 600; }

/* ---------------------------- 面板 ---------------------------- */
#amMask .mk-card { max-width: 660px; }
.am-who { margin: -8px 0 14px; }

.am-box { border: 1px solid var(--line); border-radius: 14px; overflow: hidden; margin-bottom: 10px; }
.am-box-h {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 11px 13px; border: 0; background: var(--surface-2);
  color: var(--ink); font-family: inherit; font-size: 14px; font-weight: 600;
  text-align: left; cursor: pointer;
}
.am-box-h:hover { background: var(--line); }
.am-box-h .am-cv { margin-left: 2px; transition: transform .16s; }
.am-box.folded .am-box-h .am-cv { transform: rotate(-90deg); }
.am-step {
  width: 19px; height: 19px; flex: none; border-radius: 50%;
  background: var(--brand); color: #fff;
  font-size: 11.5px; font-style: normal; font-weight: 700;
  display: grid; place-items: center;
}
.am-sum { font-size: 12px; font-weight: 500; color: var(--ink-3); }
.am-box-b { padding: 11px 13px 13px; }

/* 勾选项：整块可点，标题一行 + 说明一行 */
.am-chk { display: flex; align-items: flex-start; gap: 9px; padding: 7px 2px; cursor: pointer; }
.am-chk input { margin: 2px 0 0; width: 16px; height: 16px; flex: none; accent-color: var(--brand); cursor: pointer; }
.am-chk-t { min-width: 0; font-size: 13.5px; }
/* ⚠️ 只作用于 .am-chk-t 的**直接子元素** b。
   写成后代选择器会把说明文字里的 <b>不</b>／<b>全站</b> 这类强调也变成块级，
   结果「头像 / 不 / 显示在频道顶部版主位」被硬拆成三行（浏览器实测截图里一眼看到）。 */
.am-chk-t > b { display: block; font-weight: 600; }
.am-chk-t i { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); line-height: 1.6; }
.am-chk-t i b { display: inline; font-weight: 600; color: var(--ink-2); }
.am-chk-sm { padding: 6px 2px; }
.am-chk-sm .am-chk-t > b { font-size: 13px; display: flex; align-items: center; gap: 6px; }
.am-chk-sm .am-chk-t i { font-size: 11.5px; }

/* 板块小圆点：.aside-row .dot 的 a-* 配色是**后代选择器**限定的，
   这里的路径不同，得自己接一遍（颜色仍取同一组 --bd-* 变量，不另抄一套） */
.am-col-b .dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--brand); }
.am-col-b .dot.a-blue   { background: var(--bd-blue); }
.am-col-b .dot.a-indigo { background: var(--bd-indigo); }
.am-col-b .dot.a-amber  { background: var(--bd-amber); }
.am-col-b .dot.a-teal   { background: var(--bd-teal); }
.am-col-b .dot.a-rose   { background: var(--bd-rose); }
.am-col-b .dot.a-slate  { background: var(--bd-slate); }
.am-col-b .dot.a-gold   { background: var(--bd-gold); }

/* 第 2 步的两栏：只勾一种职务时出一栏，两种都勾时左右并排。
   每栏各自一条滚动条（帆哥原话：「两侧都有下拉滚动条」）。 */
.am-cols { display: grid; grid-template-columns: 1fr; gap: 10px; }
.am-cols.two { grid-template-columns: 1fr 1fr; }
.am-cols[hidden] { display: none; }
.am-col { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; min-width: 0; }
.am-col[hidden] { display: none; }
.am-col-h {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 10px; background: var(--surface-2);
  font-size: 12.5px;
}
.am-col-h b { font-weight: 600; color: var(--ink-2); white-space: nowrap; }
.am-mini {
  border: 0; background: transparent; color: var(--brand);
  font-family: inherit; font-size: 11.5px; padding: 1px 4px;
  border-radius: 6px; cursor: pointer;
}
.am-mini:hover { background: var(--brand-050); }
.am-tip { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.am-col-b { max-height: 196px; overflow-y: auto; padding: 4px 10px 8px; scrollbar-width: thin; }
.am-col-b::-webkit-scrollbar { width: 7px; }
.am-col-b::-webkit-scrollbar-thumb { background: var(--hair); border-radius: 4px; }
.am-col-b::-webkit-scrollbar-track { background: transparent; }

.am-note { padding: 10px 2px; font-size: 12.5px; color: var(--ink-3); }
.am-note[hidden] { display: none; }

.am-foot {
  display: flex; align-items: center; gap: 9px;
  margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--line);
}
.am-self { flex: 1; line-height: 1.6; }

/* 手机端：两栏改成上下堆叠，按钮撑满，别让人在两个窄栏里找勾选框 */
@media (max-width: 620px) {
  .am-cols.two { grid-template-columns: 1fr; }
  .am-col-b { max-height: 168px; }
  .am-foot { flex-wrap: wrap; }
  .am-foot .btn { flex: 1; }
  .am-self { flex: 0 0 100%; order: 3; }
  .am-row .btn-sm { padding: 0 9px; font-size: 12px; }
  #amMask .mk-card { max-width: 100%; }

  /* 发布页：按钮组等分一行。
     grid-auto-flow: column 让列数自动等于按钮个数 ——
     发新帖是 4 个（发布/预览/保存草稿/取消），编辑已发布帖只有 3 个
     （没有「保存草稿」），两种情况都不用改列数，也不会留空格子。 */
  .cp-foot { display: block; }
  .cp-foot-btns {
    display: grid; grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 8px;
  }
  .cp-foot-btns .btn {
    width: 100%; height: 42px; padding: 0 6px; font-size: 13.5px;
    overflow: hidden; text-overflow: ellipsis;
  }
  .cp-foot-hint { display: block; margin: 10px 0 0; text-align: center; }
}


/* ===========================================================
   头像惊喜卡（第 26 轮 · 帆哥 2026-09-22）
   从被点头像的位置 spring 放大弹出；照片二次弹跳、文字逐行浮入、
   三颗小星光外飞；2 秒后整体缩回头像原点消失。
   transform-origin 由 JS 按头像中心动态写入。
   =========================================================== */
.upop {
  /* 9100：要压住浏览者名单/预览弹层（.mk-mask 9000）——
     名单里点头像时卡片必须在弹层之上 */
  position: fixed; z-index: 9100; width: 236px;
  animation: upopIn .48s cubic-bezier(.34, 1.56, .64, 1) both;
  will-change: transform, opacity;
  pointer-events: auto;
}
.upop.out { animation: upopOut .3s cubic-bezier(.55, 0, .8, .4) both; }
@keyframes upopIn {
  0% { transform: scale(.12) rotate(-5deg); opacity: 0; }
  55% { opacity: 1; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
@keyframes upopOut {
  0% { transform: scale(1) rotate(0deg); opacity: 1; }
  100% { transform: scale(.06) rotate(4deg); opacity: 0; }
}
.upop-card {
  display: flex; align-items: center; gap: 13px;
  padding: 13px 15px 13px 13px;
  background: #fff; border-radius: 20px;
  border: 1px solid rgba(19, 26, 46, .06);
  box-shadow: 0 18px 48px rgba(19, 26, 46, .20), 0 4px 14px rgba(19, 26, 46, .10);
}
/* 正方形照片：卡片落定后再补一拍弹跳，是「惊喜感」的主拍 */
.upop-photo {
  flex: none; width: 62px; height: 62px; border-radius: 15px; overflow: hidden;
  background: linear-gradient(150deg, #E8EDF4, #D7DEE8);
  display: grid; place-items: center;
  animation: upopPhoto .52s .12s cubic-bezier(.34, 1.56, .64, 1) both;
  box-shadow: inset 0 0 0 1px rgba(19, 26, 46, .06);
}
@keyframes upopPhoto {
  0% { transform: scale(.35); }
  100% { transform: scale(1); }
}
.upop-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.upop-letter { font-size: 22px; font-weight: 700; color: var(--brand-ink); }
/* 文字逐行浮入（延迟比照片再晚一点，形成 照片→名字→部门 的入场序列） */
.upop-tx { min-width: 0; }
.upop-tx > * {
  opacity: 0;
  animation: upopTxt .3s cubic-bezier(.2, .8, .3, 1) both;
}
.upop-tx > :nth-child(1) { animation-delay: .22s; }
.upop-tx > :nth-child(2) { animation-delay: .3s; }
.upop-tx > :nth-child(3) { animation-delay: .38s; }
@keyframes upopTxt {
  0% { opacity: 0; transform: translateY(7px); }
  100% { opacity: 1; transform: translateY(0); }
}
.upop-name { font-size: 15.5px; font-weight: 750; color: var(--ink); line-height: 1.35; }
.upop-dept { margin-top: 3px; font-size: 12px; color: var(--ink-2); }
.upop-job { margin-top: 1px; font-size: 11px; color: var(--ink-3); }
/* 尾巴箭头：指向被点的头像，JS 写入 left；above 时翻到卡片下方 */
.upop-tail {
  position: absolute; top: -5px; width: 12px; height: 12px;
  background: #fff; transform: translateX(-50%) rotate(45deg);
  border-left: 1px solid rgba(19, 26, 46, .06);
  border-top: 1px solid rgba(19, 26, 46, .06);
}
.upop.above .upop-tail {
  top: auto; bottom: -5px;
  border: none;
  border-right: 1px solid rgba(19, 26, 46, .06);
  border-bottom: 1px solid rgba(19, 26, 46, .06);
}
/* 三颗小星光：弹出瞬间从卡缘向外飞散，0.7s 内消失 */
.upop-sp {
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--violet));
  opacity: 0; pointer-events: none;
  animation: upopSpark .68s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.upop-sp.sp1 { left: -4px; top: 12px; }
.upop-sp.sp2 { right: -3px; top: 34%; width: 5px; height: 5px; animation-delay: .18s; }
.upop-sp.sp3 { left: 40%; top: -4px; width: 4px; height: 4px; animation-delay: .26s; }
@keyframes upopSpark {
  0% { opacity: 0; transform: scale(0); }
  30% { opacity: .95; transform: scale(1.15); }
  100% { opacity: 0; transform: scale(.4) translate(var(--sx, 0), var(--sy, -14px)); }
}
.upop-sp.sp1 { --sx: -14px; --sy: -8px; }
.upop-sp.sp2 { --sx: 13px; --sy: -10px; }
.upop-sp.sp3 { --sx: 2px; --sy: -16px; }
/* 点头像本身给一个轻微下压反馈，暗示「有反应」 */
.avatar[data-upop] { cursor: pointer; }
.avatar[data-upop]:active { transform: scale(.92); transition: transform .08s; }

/* ============================================================
   2026-09-22（第 27 轮 · 图二）：圈子卡右上角的发帖时间上移，与题目垂直中心对齐
   ------------------------------------------------------------
   症状（帆哥截图）：卡片标题行的「6小时前 / 09-14」比左侧题目低一截。
   根因（实测，不是目测）：`.pc-trow` 是 `align-items: baseline`，而标题 `<h3>`
   自己也是 flex 容器（`.post-card .pc-title { align-items: flex-start }`，
   没有基线对齐项）→ 浏览器对它的基线是**合成基线**（取盒子下沿），
   于是 10.5px 的时间被按这个下沿对齐，落到标题首行中心以下 4.3px。
   像素带实测（424×900 @DPR3，与帆哥截图同口径）：标题带中心 656.0 / 时间带中心 669.5
   → 差 13.5px = 4.5 CSS px，与量出来的 4.34px 吻合。

   修法：时间改 `flex-start`（= 始终贴**第一行**），再补 1px 复位到该行的视觉中心。
   · 不用 `align-self: center` 的原因：那会让折成两行的长标题把时间带到**两行之间**
     （424px 实测偏差 +10.4px），而现状本来就是「时间永远贴第一行」——
     列表里长标题不少，贴第一行是更稳的排法。
   · 1px 是量出来的，不是拍的：`flex-start` 时时间中心比标题首行中心高 1.1px
     （手机 14/10.5 号字）/ 0.8px（桌面 15/11.5 号字），补 1px 后残差 ≤0.23px。
   量测脚本 `_qa/r27_tune/tune.js`（DPR3 像素带 + Range 行盒中心），改前/改后残差：
     320/360/380/390/424/768/899 → +4.34px ⇒ -0.10px
     901/1440                    → +4.34px ⇒ +0.20px
   ⚠️ 只动 `.pc-when` 的对齐，`margin-left: auto`（贴最右）来自上面那条基础规则，
      这里不覆盖它 —— 只补 `margin-top`。
   ============================================================ */
.pc-trow .pc-when { align-self: flex-start; margin-top: 1px; }
/* ===========================================================
   详情页互动区 v2：去框、去底色，效果集中在图标上
   （第 28 轮 · 帆哥 2026-09-22）
   -----------------------------------------------------------
   帆哥三条反馈的落点：
     ① 两个按钮**不要外框和底色** —— 变成「图标 + 文案 + 次数」的裸按钮。
        状态全部由图标承担：没做过是灰色描边，做过就实心着色（红 / 蓝紫）。
        这一行因此在阅读页里彻底安静下来，不跟正文抢注意力。
     ② 两组头像必须一眼分清 —— 分三层表达，各管一件事：
          · 图标颜色 = 我做过没有
          · 文案深浅（.cur）= 我正在看哪一组
          · 头像带上方分组标签（图标 + 「N 人点赞鼓励 / N 人积分打赏」）= 主答案
     ③ 反馈动作保持极简：心 = 一拍心跳 + 两点小火花；钻 = 一亮 + 轻转。
   =========================================================== */
.pd-flags { margin-top: 16px; gap: 10px; flex-wrap: wrap; }
/* 只留圆标的胶囊：去掉文字后左右内边距收窄，让「浏览数据 + 浏览者头像」
   能稳稳待在同一行（原来带「置顶/精华」文字会把它们挤到第二行） */
.pi-lab.only { padding: 0 4px; gap: 0; }

.pd-social { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.pd-social .pd-acts { margin: 0; padding: 0; border: 0; gap: 6px; }

/* —— 裸按钮：无边框、无背景、无阴影 —— */
.pd-sbtn {
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 42px; padding: 0 4px; margin: 0;
  border: 0; background: none; box-shadow: none; outline: none;
  color: var(--ink-3);                        /* 未选中：浅灰 */
  font-size: 14px; font-weight: 600; line-height: 1; font-family: inherit;
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
  transition: color .18s ease;
}
/* 文案深浅 = 「我正在看哪一组」：深色那个，就是下面那排头像的来源 */
.pd-sbtn.cur { color: var(--ink); font-weight: 700; }
.pd-sbtn:hover { color: var(--ink-2); }
.pd-sbtn.cur:hover { color: var(--ink); }

.pd-sbtn-ico { display: inline-flex; align-items: center; position: relative; }
.pd-sbtn-ico svg { width: 19px; height: 19px; display: block; }
/* 按下反馈也落在图标上：没有外框了，整块缩放会显得空落 */
.pd-sbtn:active .pd-sbtn-ico { transform: scale(.86); transition: transform .08s; }
.pd-sbtn-n { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pd-sbtn-n:empty { display: none; }           /* 0 次不显示，空「0」是噪声 */

/* 图标颜色 = 「我做过没有」：只有图标与次数着色，文案保持中性 */
.pd-sbtn-like.on .pd-sbtn-ico,
.pd-sbtn-like.on .pd-sbtn-n { color: #D93A2E; }
.pd-sbtn-tip.on .pd-sbtn-ico,
.pd-sbtn-tip.on .pd-sbtn-n { color: #3B49C8; }

/* 心形落定：一拍心跳 + 两点小火花（0.52s，不拖泥带水） */
.pd-sbtn-ico.beat { animation: pdBeat .52s cubic-bezier(.32, 1.5, .5, 1) both; }
@keyframes pdBeat {
  0% { transform: scale(.86); }
  38% { transform: scale(1.34); }
  62% { transform: scale(.96); }
  80% { transform: scale(1.09); }
  100% { transform: scale(1); }
}
.pd-sbtn.burst .pd-sbtn-ico::before,
.pd-sbtn.burst .pd-sbtn-ico::after {
  content: ''; position: absolute; width: 4px; height: 4px; border-radius: 50%;
  background: #E4567A; opacity: 0;
  animation: pdDot .58s ease-out both;
}
.pd-sbtn.burst .pd-sbtn-ico::before { --dx: -15px; --dy: -9px; }
.pd-sbtn.burst .pd-sbtn-ico::after { --dx: 14px; --dy: -11px; animation-delay: .05s; background: #F08AA0; }
@keyframes pdDot {
  0% { opacity: 0; transform: translate(0, 0) scale(.4); }
  25% { opacity: .95; transform: translate(calc(var(--dx) * .5), calc(var(--dy) * .5)) scale(1); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.35); }
}
/* 钻石打赏成功：一亮 + 轻轻转一下，暗示「值钱的动了」 */
.pd-sbtn-ico.flash { animation: pdFlash .7s cubic-bezier(.3, 1.4, .5, 1) both; }
@keyframes pdFlash {
  0% { transform: rotate(0) scale(1); filter: drop-shadow(0 0 0 rgba(59, 73, 200, 0)); }
  35% { transform: rotate(-9deg) scale(1.28); filter: drop-shadow(0 3px 10px rgba(59, 73, 200, .55)); }
  70% { transform: rotate(6deg) scale(1.08); filter: drop-shadow(0 2px 7px rgba(59, 73, 200, .35)); }
  100% { transform: rotate(0) scale(1); filter: drop-shadow(0 0 0 rgba(59, 73, 200, 0)); }
}

/* ===========================================================
   打赏菜单（第 44 轮 · 帆哥 2026-09-23：修手机出屏 + 重设计 + 弹出动效）
   ---------------------------------------------------------------
   🚨 出屏根因（2026-09-23 本地三档视口实测）：
      原来是 position:absolute + right:0，定位锚点是 .pd-tipbox（flex:1 1 0），
      手机 375 屏上它只有 154.5px 宽，而菜单写死 196px。
      **菜单比锚点宽 → 向左伸出屏幕**：
        375 屏 → 菜单左边缘 -15.5px（出屏 15.5px；帆哥截图就是这个）
        320 屏 → 菜单左边缘 -43px  （出屏 43px）
      第 43 轮把打赏按钮从右挪到左、锚点跟着缩到左半区，这个老毛病才暴露出来。
   ✅ 正解：position:fixed + JS 按**按钮中心**定位（见 placeTipMenu()）。
      祖先链实测无 transform / filter / will-change / contain —— 把 left/top
      写死成 40/120 读回就是 40/120，fixed 不会被劫持（可放心用）。
   ⚠️ 为什么不能再改回 absolute：absolute 的水平活动范围被锚点宽度框死，
      而菜单（244px）永远比锚点（154.5px）宽 → 任何 absolute 方案都必然溢出。
      要根治只能脱开「锚点宽度」这个约束，所以必须是 fixed。
   ⚠️ z-index 120：要盖住 .tabbar(70)，但必须低于 .cf-mask(260) 与 .toast-wrap(300)
      —— 打赏成功后要弹 toast，菜单不能压住它。 */
.pd-tipbox { position: relative; flex: 1 1 0; min-width: 0; display: flex; }
.pd-tip-menu {
  /* left / top / transform-origin / --tip-tail 全部由 JS 写（placeTipMenu） */
  position: fixed; left: 0; top: 0; z-index: 120;
  width: 244px; max-width: calc(100vw - 20px);
  padding: 13px 14px 12px;
  background: #fff;
  border: 1px solid var(--line); border-radius: 20px;
  box-shadow: 0 18px 44px rgba(19, 26, 46, .17), 0 5px 14px rgba(19, 26, 46, .08);
  -webkit-tap-highlight-color: transparent;
}
/* flex 型浮层必须显式写 [hidden]（项目老规矩：flex 会盖掉浏览器默认的
   [hidden]{display:none}），这里虽然是块级，一并写上免得以后改成 flex 时踩坑 */
.pd-tip-menu[hidden] { display: none; }

/* 弹入：从按钮中心 spring 放大 —— 与头像惊喜卡（.upop）同一套语言，
   只是幅度更收敛（这是个要操作的浮层，不是惊喜） */
.pd-tip-menu.in { animation: pdTipIn .44s cubic-bezier(.34, 1.56, .64, 1) both; }
@keyframes pdTipIn {
  0% { opacity: 0; transform: scale(.16) rotate(-5deg); }
  55% { opacity: 1; }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}
/* 尾巴箭头指向按钮中心，水平位置由 JS 写进 --tip-tail */
.pd-tip-menu::after {
  content: ''; position: absolute; left: var(--tip-tail, 50%); bottom: -5px;
  width: 10px; height: 10px; margin-left: -5px;
  background: #fff; transform: rotate(45deg);
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
/* 菜单翻到按钮**下方**时（上方塞不下），尾巴翻到顶边 */
.pd-tip-menu.below::after {
  bottom: auto; top: -5px;
  border: none; border-left: 1px solid var(--line); border-top: 1px solid var(--line);
}

/* ---- 头部：图标 + 标题 + 规则胶囊 ---- */
.pd-tip-hd {
  display: flex; align-items: center; gap: 6px;
  font-size: 14.5px; font-weight: 750; color: var(--ink); line-height: 1;
  margin-bottom: 12px;
}
.pd-tip-ico { display: inline-flex; align-items: center; color: #3B49C8; }
.pd-tip-ico svg { width: 16px; height: 16px; display: block; }
/* 「每帖一次」做成右侧一枚胶囊 —— 规则仍写在用户做决定的地方，
   但不再是一行灰字（那正是「有点 low」的一半来源） */
.pd-tip-once {
  margin-left: auto; font-style: normal; font-weight: 650;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(59, 73, 200, .09); color: #3B49C8;
  font-size: 10.5px; line-height: 1; letter-spacing: .2px;
}

/* ---- 三档面额 ---- */
.pd-tip-row { display: flex; gap: 8px; }
.pd-tip-opt {
  flex: 1 1 0; min-width: 0; height: 46px; border-radius: 13px; cursor: pointer;
  border: 1px solid rgba(59, 73, 200, .20);
  background: linear-gradient(180deg, #F8F9FF, #EFF1FC);
  color: #3B49C8; font-size: 17px; font-weight: 800; font-family: inherit;
  letter-spacing: -.2px; font-variant-numeric: tabular-nums;
  transition: transform .12s ease, background .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.pd-tip-opt:hover:not(:disabled) {
  background: linear-gradient(180deg, #EFF2FE, #E4E8FB);
  border-color: rgba(59, 73, 200, .34);
  box-shadow: 0 3px 10px rgba(59, 73, 200, .18);
  transform: translateY(-1px);
}
.pd-tip-opt:active:not(:disabled) { transform: scale(.94); }
/* 余额不足的档位**直接禁用**：点了必然被服务端拒（「您的积分不足」），
   摆一个注定失败的按钮比不摆更让人恼火（与第 43 轮「草稿按钮不给摆」
   同一个判断标准）。 */
.pd-tip-opt:disabled {
  cursor: default; color: #AEB4C2; border-color: #E8EAEF;
  background: #F6F7FA; box-shadow: none;
}

/* ---- 底部：我的积分 ---- */
.pd-tip-foot {
  display: flex; align-items: baseline; gap: 6px;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-3);
}
.pd-tip-foot b {
  margin-left: auto; color: var(--brand-600); font-weight: 800;
  font-size: 16px; line-height: 1; font-variant-numeric: tabular-nums;
}
/* 三档全禁用时（余额 0）才出现的一行引导 ——
   否则用户只看到一个整框点不动，比看到一句解释更糟 */
.pd-tip-hint { margin-top: 8px; font-size: 11.5px; color: var(--ink-3); }

/* ---- 入场序列：头 → 三档 → 底部 依次浮入（比整块硬弹更有层次）----
   ⚠️ 基础态 opacity:0、只在 .in 里挂 animation 且 fill 为 both ——
      这样每次打开都重播（移掉 .in 就回到 0）。
      代价是「动画一旦没播，元素就永远看不见」，所以验收里配了一条
      「打开后所有子元素 opacity 为 1」的断言兜底。 */
.pd-tip-menu .pd-tip-hd,
.pd-tip-menu .pd-tip-opt,
.pd-tip-menu .pd-tip-foot,
.pd-tip-menu .pd-tip-hint { opacity: 0; }
.pd-tip-menu.in .pd-tip-hd { animation: pdTipRow .3s .14s cubic-bezier(.2, .8, .3, 1) both; }
.pd-tip-menu.in .pd-tip-opt { animation: pdTipRow .3s .20s cubic-bezier(.2, .8, .3, 1) both; }
.pd-tip-menu.in .pd-tip-opt:nth-child(2) { animation-delay: .26s; }
.pd-tip-menu.in .pd-tip-opt:nth-child(3) { animation-delay: .32s; }
.pd-tip-menu.in .pd-tip-foot { animation: pdTipRow .3s .36s cubic-bezier(.2, .8, .3, 1) both; }
.pd-tip-menu.in .pd-tip-hint { animation: pdTipRow .3s .40s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes pdTipRow {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ---- 三颗小星光：弹出瞬间从框缘向外飞（学头像惊喜卡的 .upop-sp）---- */
.pd-tip-sp {
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--violet));
  opacity: 0; pointer-events: none;
}
.pd-tip-menu.in .pd-tip-sp { animation: pdTipSpark .68s .1s cubic-bezier(.2, .7, .3, 1) both; }
.pd-tip-sp.s1 { left: -3px; top: 14px; --sx: -13px; --sy: -7px; }
.pd-tip-sp.s2 { right: -3px; top: 38%; width: 5px; height: 5px; --sx: 12px; --sy: -9px; animation-delay: .18s; }
.pd-tip-sp.s3 { left: 42%; top: -3px; width: 4px; height: 4px; --sx: 3px; --sy: -15px; animation-delay: .26s; }
@keyframes pdTipSpark {
  0% { opacity: 0; transform: scale(0); }
  30% { opacity: .95; transform: scale(1.15); }
  100% { opacity: 0; transform: scale(.4) translate(var(--sx, 0), var(--sy, -14px)); }
}

/* —— 头像气泡：一个方块框 + 顶上一条会走的小尾巴 —— STRIPTAIL-R56（帆哥 2026-09-24）
   帆哥原话：「所有打赏过的人或者点赞过的人显示在下端的时候，都是从头显示，不容易分清
   这个头像是点赞过的人还是打赏过的人。你可以做个方形的气泡框……点击点赞，那气泡框的
   小尾巴就从点赞那里向下把下面的头像圈起来，点击打赏，打赏过的人的头像就从打赏按钮
   中间下的位置出个小尾巴，把下面打赏人的头像圈起来……头像签名那个钻石、小手、和小心心
   都可以去掉了。」
   方案 A（帆哥选定）：**一个**方框 + 一条会走到当前那一侧的小尾巴，不收起。

   历史沿革（别改回去）：第 43 轮这里是「一行小图标（♦/♡/👍）+ 头像带」，
   靠那个小图标告诉用户这排头像是哪一组 —— 帆哥反馈那个小图标根本不够醒目。
   现在整排头像被框起来、尾巴直接落在对应按钮正下方，归属一眼可见，
   于是 `.pd-strip-head` 的三条规则**连同 HTML 里的元素一起删除**。
   ⚠️ 要回滚：把这段换回第 43 轮那版（flex 行 + .pd-strip-head 三条），
      并在 app.js 里恢复 pdStripHeadHtml() 与那段 HTML。 */
.pd-strip-wrap {
  position: relative;                 /* 尾巴的定位基准 */
  display: block;                     /* 原来是 flex 一行（图标 + 头像）；方框要竖直堆叠 */
  margin-top: 12px;                   /* 原来 4px（紧贴图标）；现在要给尾巴留出上方的空间 */
  padding: 9px 10px;
  border: 1px solid var(--hair);
  border-radius: 6px;                 /* 帆哥要的「方形」，所以圆角只收一点点 */
  background: #F7F8FB;                /* ⚠️ 必须是纯色：尾巴用 background:inherit 跟它同色 */
}
.pd-strip-wrap[hidden] { display: none; }
/* 小尾巴：10×10 方块转 45° 成菱形，只留「上 + 左」两条边描边 ——
   转过来正好是朝上的 ^；菱形的下半截被自身背景盖住，于是尾巴与气泡顶边自然连通、
   接缝处不会露出一小段横着的边框线。
   · top:-5px 让菱形中心正好压在气泡顶边上（露出的可见高度 ≈7px）；
   · 颜色一律 inherit / 同变量：气泡底色或描边改了，尾巴自动跟上，不会脱节。 */
.pd-strip-tail {
  position: absolute; top: -5px; left: var(--tail-x, 50%);
  width: 10px; height: 10px;
  transform: translateX(-50%) rotate(45deg);
  background: inherit;
  border-left: 1px solid var(--hair);
  border-top: 1px solid var(--hair);
  /* 切换「看点赞 / 看打赏」时尾巴滑过去 —— 比瞬间跳更有指向感。
     故意不做位移/缩放动画：--tail-x 是像素值，left 过渡最稳、也不影响 rotate。 */
  transition: left .24s cubic-bezier(.3, .9, .3, 1);
}
.pd-strip {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 3px;                                   /* ≈0.1 个字符宽，帆哥指定的「一点点」 */
  flex: 1 1 auto; min-width: 0;               /* 人多了在剩余宽度里换行，不把整行撑破 */
}
/* 🚨 类名撞车（第 43 轮实测挖出来的）：`.pd-strip` 最早是**产品帖图片带**的类
   （见文件上方「⑦ 产品帖：图片带」那条），详情页这排头像复用了同一个名字，
   于是白捡了它三样东西 ——
     · margin-top: 11px  → 把头像整体往下推，和左边那个小图标**差 5px 对不齐**；
     · overflow: hidden  → 头像的弹入动画被裁；
     · mask-image 左右渐隐 → 第一个头像的左边缘被啃掉 12px。
   三样都是「横滑条」才需要的，一排行头像素完全不需要。
   这里**只加作用域前缀收窄**，不动那条原规则 —— 产品帖的横滑条还要靠它。 */
.pd-strip-wrap .pd-strip {
  margin-top: 0; overflow: visible;
  -webkit-mask-image: none; mask-image: none;
}
.pd-strip .avatar { flex: none; }
.pd-strip.pop .avatar { animation: pdAvIn .34s cubic-bezier(.24, 1.3, .4, 1) both; }
.pd-strip.pop .avatar:nth-child(1) { animation-delay: 0s; }
.pd-strip.pop .avatar:nth-child(2) { animation-delay: .03s; }
.pd-strip.pop .avatar:nth-child(3) { animation-delay: .06s; }
.pd-strip.pop .avatar:nth-child(4) { animation-delay: .09s; }
.pd-strip.pop .avatar:nth-child(5) { animation-delay: .12s; }
.pd-strip.pop .avatar:nth-child(n+6) { animation-delay: .15s; }
@keyframes pdAvIn {
  0% { opacity: 0; transform: scale(.5) translateY(4px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}

/* ===========================================================
   首页相册「按时间 / 按部门」：从独立一行挪到「相册」标题右侧（2026-09-22 · 第 27 轮）
   ALBUM-TAB-R27
   ⚠️ 本段是覆盖层，必须留在文件最后。要回滚整段删掉即可。

   帆哥原话：「两个按钮调整位置，放在相册标题右侧，空一个字符，形式也调整一下，
   不要现在这种按钮效果，简约一些，可以不那么明显。」
   → 去掉胶囊底 / 边框 / 阴影，只留文字；选中态靠品牌色 + 加粗区分。
   =========================================================== */
.section-head .album-tabs {
  display: inline-flex; align-items: center; gap: 12px;
  margin: 0 0 0 6px;                 /* 与「相册」之间那「一个字符」：父级 gap 10px + 6px = 16px ≈ 1 个中文字宽 */
}
.album-tab {
  height: auto; padding: 0; border: 0; border-radius: 0;
  background: none; box-shadow: none;
  font-size: 12.5px; font-weight: 600; color: var(--ink-3);
  line-height: 1.2; transition: color .16s;
}.album-tab:hover { color: var(--brand); background: none; }
.album-tab.on {
  background: none; box-shadow: none;
  color: var(--brand); font-weight: 700;
}
/* 窄屏再收一档字号与间距，保证「相册 + 切换器 + 全部 N 张 ›」同排不挤 */
@media (max-width: 430px) {
  .section-head .album-tabs { gap: 10px; margin-left: 4px; }
  .album-tab { font-size: 12px; }
}

/* ==================================================================
   云帆故事 · 编辑态样式（2026-09-22 帆哥：管理员可编辑各板块内容）
   ------------------------------------------------------------------
   阅读态与编辑态共用同一套 DOM（见 app.js 的 storyInner），
   这里只画三样东西：哪块字能改、条目能怎么调、改完去哪保存。

   ⚠️ 一条硬约束：**编辑态不许改变原来的排版**。
      所以可编辑框一律不用 padding / border 去撑 —— 那会动到盒模型，
      让文字的换行位置变化，编辑时看到的分行跟保存后不一样，
      「所见即所得」就成了假的。只用 box-shadow 外描边 + 半透明底色，
      两者都不占空间、也不触发重排。
   ================================================================== */

/* 管理员入口条：只在有编辑权的人眼里存在（canEdit 由服务端下发） */
.sy-adminbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 12px; padding: 8px 12px;
  border: 1px dashed rgba(10, 90, 168, .35); border-radius: var(--r-md);
  background: var(--brand-050);
}
.sy-adminbar > span { font-size: 12.5px; color: var(--brand-ink); }
.sy-adminbar .btn { margin-left: auto; }

/* 能改的那块字。
   ⚠️ 这里**故意不写** white-space: pre-wrap。换行是靠 br 标签表达的（见 app.js 的 V()），
      一旦改成 pre-wrap，white-space 从 normal 变掉，断行规则跟着变 ——
      手机端 36px 宽的年份格里「2024」会被折成「202 4」两行，实测截图抓到的。 */
.sy-edit {
  outline: none; cursor: text; border-radius: 5px;
  box-shadow: 0 0 0 1.5px rgba(10, 90, 168, .3);
  background: rgba(10, 90, 168, .05);
  transition: box-shadow .15s, background .15s;
}
/* 🚨 这一行是必需的，不是保险：Chrome 给 contenteditable 元素默认套了
   overflow-wrap: break-word。手机端年份格只有 36px，「2024」正好放不下多出来的那
   零点几像素，于是被断成「202 4」两行挂在页面上 —— 而 .sy-his 是 flex 容器、
   .sy-his-y 被拉伸到行高，**元素高度一点没变**，靠量高度是发现不了的
   （2026-09-22 实测截图里才看出来）。用属性选择器提高权重，压过 UA 那条规则。 */
.sy-edit[contenteditable="true"] { overflow-wrap: normal; word-break: normal; }
.sy-edit:hover { box-shadow: 0 0 0 1.5px rgba(10, 90, 168, .55); background: rgba(10, 90, 168, .1); }
.sy-edit:focus { box-shadow: 0 0 0 2px var(--brand); background: rgba(10, 90, 168, .13); }
/* 首屏那张深色卡里，深蓝描边等于没有 —— 换成金色 */
.sy-hero .sy-edit { box-shadow: 0 0 0 1.5px rgba(230, 201, 140, .5); background: rgba(255, 255, 255, .07); }
.sy-hero .sy-edit:hover { box-shadow: 0 0 0 1.5px rgba(230, 201, 140, .8); background: rgba(255, 255, 255, .12); }
.sy-hero .sy-edit:focus { box-shadow: 0 0 0 2px var(--gold-300); background: rgba(255, 255, 255, .16); }

/* 星号标记渲染出的强调。hero 里的 em 由老的 .sy-title em 接管（金色），
   这里只管正文里的 —— 用品牌蓝，跟链接区分开。 */
.sy-hl { font-style: normal; font-weight: 700; color: var(--brand-600); }

/* 列表条目：relative 是给右上角那几颗按钮定位用的 */
.sy-ew { position: relative; }

/* 三颗小按钮「骑」在条目边框上沿（top 为负），正好落进条目之间的间隙里，
   不压正文。默认半透明，鼠标移上去或键盘聚焦时才全亮。 */
.sy-tools {
  position: absolute; top: -11px; right: 8px; z-index: 3;
  display: flex; gap: 4px; opacity: .45; transition: opacity .15s;
}
.sy-ew:hover > .sy-tools, .sy-tools:focus-within { opacity: 1; }
/* 指标格子只有条目的三分之一宽，按钮组骑边框会压到隔壁格子 → 收进格子内部 */
.sy-tools-mini { top: 3px; right: 3px; opacity: .35; }
.sy-tb {
  width: 23px; height: 23px; padding: 0;
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 700; line-height: 1;
  color: var(--ink-2); background: var(--surface);
  border: 1px solid var(--hair); border-radius: 7px;
  box-shadow: 0 1px 3px rgba(8, 21, 44, .12);
  cursor: pointer;
}
.sy-tb:hover:not(:disabled) { border-color: var(--brand); color: var(--brand-ink); }
.sy-tb:disabled { opacity: .3; cursor: default; }
.sy-tb-x:hover:not(:disabled) { border-color: var(--danger); color: var(--danger); background: #FCF3F2; }

/* 「＋ 添加一条 / 一个案例 / 一个年份」 */
.sy-add {
  display: block; width: 100%; margin-top: 10px; padding: 8px 10px;
  font-size: 12.5px; font-weight: 600; color: var(--brand-ink);
  background: transparent; border: 1px dashed rgba(10, 90, 168, .45);
  border-radius: var(--r-sm); cursor: pointer;
}
.sy-add:hover { background: var(--brand-050); }
/* 案例卡里那颗「＋ 加一个指标」 */
.sy-add-mini { margin-top: 8px; padding: 5px 8px; font-size: 11.5px; }

/* 编辑态给页面底部让出工具条的高度。
   ⚠️ 这条不是锦上添花：不留白，最后一个「＋ 添加」和最后一条的工具按钮
      永远压在工具条底下——点不着、也看不见，等于那几个板块加不了条目。
      390×844 实测时先撞上的是这个，不是猜的。
   值 = 工具条高度（约 56）+ 底部间距（18/68）+ 一点余量。 */
#syRoot.sy-editing { padding-bottom: 150px; }

/* 编辑工具条：固定悬浮在屏幕底部。
   ⚠️ 「保存」是唯一能把改动写进库的按钮 —— 手机端必须抬到底栏（高 58px）之上，
      被底栏盖住就等于整条编辑链路不可用。这也是它 z-index 高过 .tabbar(70) 的原因。 */
.sy-ebar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(18px + env(safe-area-inset-bottom));
  z-index: 80;
  width: min(620px, calc(100vw - 24px));
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: 14px;
  background: rgba(11, 30, 60, .95); color: #fff;
  box-shadow: 0 12px 34px rgba(8, 21, 44, .38);
  backdrop-filter: saturate(180%) blur(12px);
}
.sy-ebar-h { flex: 1 1 190px; font-size: 12px; line-height: 1.55; color: rgba(255, 255, 255, .82); }
.sy-ebar-h code {
  padding: 1px 5px; border-radius: 5px; font-size: 11.5px;
  background: rgba(255, 255, 255, .16); color: #fff;
}
.sy-ebar-b { display: flex; gap: 7px; margin-left: auto; }
/* 条上三颗按钮另配色：默认 .btn 是白底深字，压在深色条上会糊成一团 */
.sy-ebar .btn {
  border-color: rgba(255, 255, 255, .32); background: rgba(255, 255, 255, .12); color: #fff;
}
.sy-ebar .btn:hover { background: rgba(255, 255, 255, .2); border-color: rgba(255, 255, 255, .5); }
.sy-ebar .btn-primary {
  background: var(--brand-600); border-color: transparent; color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 6px 18px rgba(10, 90, 168, .4);
}
.sy-ebar .btn-primary:hover { background: #0B6BC6; }

@media (max-width: 899px) {
  .sy-ebar { bottom: calc(68px + env(safe-area-inset-bottom)); }
  .sy-ebar-h { flex: 1 1 100%; }
  .sy-ebar-b { flex: 1 1 100%; margin-left: 0; }
  .sy-ebar-b .btn { flex: 1 1 0; padding: 0 8px; }
  /* 手机端工具条更高（提示语另起一行），留白也要跟着加 */
  #syRoot.sy-editing { padding-bottom: 210px; }
}

/* ===========================================================
   首页 hero 搜索胶囊上的「爬边公仔」（2026-09-22 · 第 32 轮上线 / 第 33 轮修订）
   HOME-FIG-R32
   ⚠️ 覆盖层，必须留在文件最后。要撤掉：删掉本段 + app.js 里那个 <img class="hero-fig">。

   素材来自帆哥给的四宫格：取右上那套「实景渲染」公仔形象 + 右下那张
   「趴边只露头、双手搭在边上」的姿态。形象按原图重绘（原图是跳跃/迈步姿态，
   变不成趴姿）。最后一句反馈：「最后这个娃娃一个手超出去了，整体往左一个半手」。

   ⚠️ 为什么 right 是 22.5 / 34.3 这种怪数 —— 不能凭感觉给：
      .hero-search 是 999px 全圆角药丸。在胶囊**上沿**那条水平线上，圆角已经把
      实际边界往里收掉了「一个半径」——PC 24px、手机 22px。公仔底边正压在上沿，
      所以右端若按「胶囊右端」对齐，看上去就"探出去"了一块（帆哥圈的就是这里）。
      实测（1440 / 390 视口，见 _design/police_ip/geo.json）：
        PC   胶囊 x=320..1048 → 上沿圆角边界 1024.0，公仔右端落在 1024.5
        手机 胶囊 x=16..374  → 上沿圆角边界  352.0，公仔右端落在 338.7
      手机这 13px 的余量 = 帆哥要的「再左移一个半手宽」：
      素材单手宽 71.2px，手机缩放后 21.4 CSS → 1.5 手 = 32.1。

   ⚠️ 第 33 轮修订（手机端「太靠左 + 有点大」）—— 左移过头了，往回拿：
      左移到 338.7 之后，公仔左端落到 192.0，而**欢迎语第二行
      「让我们一起创造属于自己的未来！」的墨迹右端实测 203.5**（Range.getClientRects，
      见 /tmp/r33/text.js）→ 压住 11.5px，就是帆哥看到的「把后面文字盖住了」。
      改法：右移（right 34.3 → 25）＋ 缩到原来的 4/5（146.7 → 117.4）：
        公仔右端 349.0（距上沿圆角边界 352.0 留 3px，仍在胶囊内）
        公仔左端 231.6（距文字 203.5 留 28.1px）
      📌 定这条线只能靠**文字墨迹的 getClientRects**，不能用 .hero-desc 的块级 rect
      （块级是整行宽 16..374，会误判成「永远重叠」）。
   =========================================================== */
.hero-search { position: relative; }
.hero-fig {
  position: absolute;
  right: 22.5px;                 /* 见上：胶囊右端 − 圆角半径 − 1.5 个手宽 */
  bottom: 100%;                  /* 底边正好压在胶囊外沿上（占 1px 盖住硬切口） */
  width: 160px; height: auto;    /* PC：原 960 的 1/3 */
  pointer-events: none;          /* 绝不挡搜索框点击 */
  user-select: none; -webkit-user-drag: none;
  z-index: 3;
}
@media (max-width: 899px) {
  .hero-fig { right: 25px; width: 117.4px; }     /* 手机：右端 349.0（原 660 的 2/3 再 ×0.8 = 4/5） */
}

/* ===========================================================
   第 37 轮 · 部门账号（2026-09-22 · 帆哥）
   -----------------------------------------------------------
   帆哥的需求：「在管理后台顶部，新增一个模块，叫『部门账号』。现在 pc 端顶部管理后台
   加上这个会有 8 个按钮，你可以重新设计一下，简约一下，让这 8 个按钮都能排在一行」；
   「在官方公告板块，不允许个人发帖，只允许部门账号发帖」。

   三块，各自独立：
     ① .adm-tabs   —— 后台导航条，8 个按钮排一行（PC）
     ② .dept-badge —— 部门徽章，替代部门帖的「头像 + 姓名 + 团队」
     ③ .dp-*       —— 部门账号管理页：部门架构树 + 勾选弹层
   =========================================================== */

/* ---------- ① 后台导航条：8 个按钮一行 ----------
   原来是一排 .chip（33px 高 / 13.5px 字 / 左右各 14px 内边距 / 间隔 7px），7 个刚好。
   加上「部门账号」变成 8 个，在 1100~1399px 这档最窄的内容列（实测约 680px）会溢出成两行。

   ⚠️ 只在这个容器里压缩 .chip 的尺寸，**不动全局 .chip** ——
      别处（内容管理的状态筛选、积分榜、相册、公告历史）还在用它，
      全局改小会把这些地方一起弄难看。

   算式（PC 三档，内容列宽 = .shell 减去两栏侧栏与内边距）：
     900~1099px  → 内容列约 854px → 每个 101px
     1100~1399px → 内容列约 680px → 每个 79.7px   ← 最紧的一档
     1400px+     → 内容列约 736px → 每个 86.8px
   单格需要：字宽 4×12.5 = 50 + 内边距 16 + 边框 2 = 68px，三档都排得下。
   min-width + 容器 overflow-x:auto 是**兜底**：极端窄的窗口宁可横滑也不折成两行
   （帆哥要的就是「排在一行」）。 */
.adm-tabs {
  display: flex; gap: 6px; flex-wrap: nowrap;
  margin-bottom: 16px; padding-bottom: 4px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
.adm-tabs::-webkit-scrollbar { display: none; }
.adm-tab {
  flex: 1 1 0; min-width: 68px;
  height: 32px; padding: 0 8px;
  justify-content: center;
  font-size: 12.5px; letter-spacing: .01em;
}
/* 手机（<900px）：8 个挤在一行在 360px 上根本按不准，横滑又要用户先发现「这行能滑」。
   4 列 × 2 行是唯一一眼就懂的排法，每格 80px 上下，拇指也够得着。 */
@media (max-width: 899px) {
  .adm-tabs {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 6px; overflow: visible; padding-bottom: 0;
  }
  .adm-tab { min-width: 0; height: 34px; }
}

/* ---------- ② 部门徽章 ----------
   帆哥参考图 2：金点 + 部门名，米底色 + 金细边 + 胶囊圆角。
   🚨 尺寸是「高度档位」，与 avatar() 的 size 一一对应 ——
      帆哥原话「图标高度和其他用户在这里显示的头像高度一致」：
        .s20 = 列表卡片 / 首页动态（与 .avatar.s20 等高）
        .s28 = 帖子详情页头部（第 46 轮起，不再追平等高）
   高度写成固定 px 而不是靠 padding 撑出来，就是为了让「等高」这件事可断言。 */
.dept-badge {
  display: inline-flex; align-items: center; gap: 6px;
  flex: none; max-width: 100%; min-width: 0;
  border-radius: 999px;
  background: var(--gold-050); color: #8A6415;
  box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .45);
  font-weight: 700; letter-spacing: .01em; white-space: nowrap;
}
.dept-badge > i {
  flex: none; width: .42em; height: .42em; border-radius: 50%;
  background: var(--gold);
}
.dept-badge-tx { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.dept-badge.s20 { height: 20px; padding: 0 9px 0 8px; font-size: 11.5px; }
/* 第 46 轮：详情页头部从 s48 大胶囊降为 s28 —— 48px 高 + 16px 字在 390px 屏上
   喧宾夺主，还把「由 X 发布」挤换行。28px 与列表卡视觉语言一致，
   头像（个人帖）仍 48px，部门帖不再等高是刻意的。 */
.dept-badge.s28 { height: 28px; padding: 0 12px 0 11px; font-size: 13px; }

/* 列表 / 首页动态里给徽章一个宽度上限：
   「新媒体事业部」这种 6 字部门名 + 右侧「时间 / 赞 / 评 / 览」四项，
   在 360px 上会互相挤。宁部门名收成省略号，也不能把计数挤没。 */
.pc-foot > .dept-badge { max-width: 42%; }
@media (max-width: 560px) {
  .fr-foot .dept-badge { max-width: 40vw; gap: 5px; padding: 0 8px 0 7px; font-size: 11px; }
  .pc-foot > .dept-badge { max-width: 46%; }
}

/* 「由 某某 发布」——只有全站管理员看得到的溯源信息（帆哥参考图 3）。
   与 .fr-dept / .pd-sub 同一档灰，刻意做得比部门徽章轻：
   徽章是「谁发的」，这一句是「背后是谁」，主次要分明。 */
.fr-by, .pc-by, .pd-by { color: var(--faint); font-weight: 400; }
.fr-by, .pc-by { font-size: 11.5px; flex: none; }
.pd-by { font-size: 13.5px; color: var(--ink-3); white-space: nowrap; flex: none; }

/* 部门帖的详情页头部：左边换成 48px 徽章，右边只剩发帖时间
   （全站管理员还会多一句「由 X 发布」）。没有姓名行时两行结构塌成一行，
   给正文列一个垂直居中，免得徽章看着悬空。 */
.pd-head.dept .pd-head-tx { justify-content: center; }
.pd-head.dept .pd-author { min-height: 0; }

/* ---------- ②b 发帖页：「发帖部门」下拉 + 提示条（需求 3） ---------- */
.cp-dept-hint {
  display: flex; align-items: center; gap: 7px;
  margin: 0 0 16px; padding: 10px 13px; border-radius: var(--r-sm);
  background: var(--gold-050); color: #8A6415;
  font-size: 12.5px; line-height: 1.65; font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .35);
}
.cp-dept-hint[hidden] { display: none; }
.cp-dept-fixed {
  display: flex; align-items: center; gap: 8px;
  height: 42px; padding: 0 13px; border-radius: var(--r-sm);
  background: var(--gold-050); color: #8A6415;
  font-size: 13.5px; font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(200, 161, 90, .35);
}
.cp-dept-fixed svg { flex: none; width: 15px; height: 15px; }

/* ---------- ②d 发帖页：发布身份切换（第 38 轮 · 帆哥） ----------
   帆哥原话：「该发帖人在进入发帖页面，选择了这三个板块发帖的时候，标题上方
             会自动出现两个选项：个人身份，部门身份…如果点击部门身份，
             那么部门身份按钮后面会再显示一个按钮」。
   所以这一行是 flex：「个人身份 / 部门身份」两个胶囊，**右边紧跟着**
   「发帖部门」控件（选部门身份时才出现；窄屏自动换行成上下两行）。
   官方公告板块没有身份切换，这一行只剩「发帖部门」，与第 37 轮视觉完全一致。

   ⚠️ 两个 .field 都要收掉自带的下边距 —— .field 本身是 block + margin-bottom:16px，
      放进 flex 行里会把后面「标题」推得太远。间距交给 .cp-id-wrap。 */
.cp-id-wrap {
  display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap;
  margin-bottom: 16px;
}
.cp-id-wrap > .field { margin-bottom: 0; }
/* 身份段只有两个固定宽度的胶囊，宽度由内容定，剩余空间全留给右边的「发帖部门」。 */
.cp-id-wrap > #cpIdentField { flex: none; }
.cp-id-wrap > #cpDeptField { flex: 1 1 auto; min-width: 240px; }
.cp-id-seg { display: inline-flex; gap: 6px; }

/* 描边式浅胶囊（与后台那 8 个按钮同一套视觉语言）：
   未选中 = 白底 + 细边 + 深蓝字；选中 = 填深蓝 + 白字。
   高度 42px 与右边的 .cp-board-bar / .cp-dept-fixed **齐平**（这两个本来就是 42px）。
   🚨 「这条帖子最终以谁的名义发出去」全靠这一眼，所以选中态必须一眼可辨：
      深底白字 + 底部一道内阴影，既有分量又不需要额外图标。 */
.cp-id-opt {
  height: 42px; padding: 0 16px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm);
  background: var(--surface); color: var(--brand);
  border: 1px solid rgba(10, 90, 168, .28);
  font-size: 13.5px; font-weight: 600; font-family: inherit;
  transition: background .15s, color .15s, border-color .15s;
}
.cp-id-opt:hover { background: var(--brand-050); }
.cp-id-opt.on {
  background: var(--brand); color: #fff;
  border-color: var(--brand); font-weight: 700;
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .14);
}
@media (max-width: 560px) {
  .cp-id-wrap > #cpDeptField { min-width: 0; flex-basis: 100%; }
}

/* ---------- ②c 圈子列表的「只看某部门」筛选片（需求 5） ---------- */
.filt-tag { display: inline-flex; align-items: center; gap: 5px; }
.filt-tag.dept { color: #8A6415; font-weight: 700; }
.filt-tag.dept i {
  font-style: normal; cursor: pointer; padding: 0 2px;
  color: var(--ink-3); font-weight: 400;
}
.filt-tag.dept i:hover { color: var(--danger); }

/* ---------- ③ 部门账号管理页 ---------- */
.dp-card { padding: 20px; }
.dp-tip { font-size: 12.5px; color: var(--ink-3); line-height: 1.9; margin-bottom: 14px; }
.dp-tip b { color: var(--ink-2); }
.dp-fold-bar { display: flex; gap: 14px; margin: 2px 0 8px; }
.dp-fold { font-size: 12.5px; color: var(--brand); font-weight: 600; cursor: pointer; }
.dp-fold:hover { text-decoration: underline; }
.dp-tree { border-top: 1px solid var(--line); }

/* 折叠：一个 .collapsed 管整棵子树（比逐个 toggle 子节点稳，嵌套层级也不会错） */
.dp-node.collapsed > .dp-kids { display: none; }
.dp-row {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 6px 0;
  border-bottom: 1px solid var(--line);
}
.dp-caret {
  flex: none; width: 20px; height: 20px; border-radius: 6px;
  display: grid; place-items: center; color: var(--ink-3);
  cursor: pointer; transition: transform .16s;
}
.dp-caret svg { width: 14px; height: 14px; transform: rotate(180deg); }   /* 收起：指右 */
.dp-caret.empty { cursor: default; opacity: 0; }
.dp-node:not(.collapsed) > .dp-row > .dp-caret svg { transform: rotate(-90deg); } /* 展开：指下 */
.dp-name {
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dp-count {
  flex: none; display: inline-flex; align-items: center;
  height: 18px; padding: 0 7px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-3);
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* 已授权头像：叠压式（-7px），一眼看出「这个部门给了几个人」；
   白描边是为了叠在一起时仍分得清是几个头。 */
.dp-avs { display: flex; align-items: center; min-width: 0; overflow: hidden; }
.dp-avs .avatar { margin-left: -7px; box-shadow: 0 0 0 2px var(--surface); }
.dp-avs .avatar:first-child { margin-left: 0; }
.dp-plus {
  flex: none; width: 28px; height: 28px; padding: 0;
  border: 1px dashed var(--hair); border-radius: 999px;
  background: var(--surface); color: var(--brand);
  display: grid; place-items: center; cursor: pointer; transition: .15s;
}
.dp-plus svg { width: 15px; height: 15px; }
.dp-plus:hover { border-style: solid; border-color: var(--brand); background: var(--brand-050); }
/* 缩进 + 竖向引导线 = 一眼看出层级（121 行 5 层，没有引导线会散掉） */
.dp-kids { margin-left: 19px; padding-left: 10px; border-left: 1px solid var(--line); }

/* 勾选弹层 */
.dp-mask { align-items: center; }
.dp-sheet {
  max-width: 560px; padding: 20px 20px 18px;
  border-radius: var(--r-xl);
  display: flex; flex-direction: column; max-height: 86vh;
}
.dp-sh-head { display: flex; align-items: flex-start; gap: 10px; }
.dp-sh-head h3 { text-align: left; font-size: 17px; margin: 0 0 2px; }
.dp-sh-sub { font-size: 11.5px; color: var(--ink-3); }
.dp-sh-x {
  flex: none; margin-left: auto; width: 30px; height: 30px;
  border: 0; border-radius: 50%; background: var(--surface-2); color: var(--ink-2);
  display: grid; place-items: center; cursor: pointer;
}
.dp-sh-x svg { width: 15px; height: 15px; }
.dp-sh-search {
  display: flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 12px; margin: 12px 0 8px;
  border-radius: var(--r-sm); background: var(--surface-2);
}
.dp-sh-search svg { flex: none; width: 16px; height: 16px; color: var(--ink-3); }
.dp-sh-search input {
  flex: 1; min-width: 0; border: 0; outline: none; background: transparent;
  font-family: var(--font); font-size: 13.5px; color: var(--ink);
}
.dp-sh-note { font-size: 11.5px; color: var(--ink-3); line-height: 1.75; margin-bottom: 8px; }
.dp-sh-note b { color: var(--ink-2); }
.dp-sh-list {
  flex: 1 1 auto; min-height: 180px; max-height: 46vh; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
/* ⚠️ 勾选框是「纯装饰」：行本身带 data-act，点整行切换。
   所以那个 <input type=checkbox> 根本没渲染（见 dpMemberRow），
   靠 .on 类换底色 —— 行高 46px 比 18px 的方框好按得多，手机上也一样。 */
.dp-mrow {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 11px; border-bottom: 1px solid var(--line); cursor: pointer;
}
.dp-mrow:last-child { border-bottom: 0; }
.dp-mrow:hover { background: var(--surface-2); }
.dp-mrow.on { background: var(--brand-050); }
.dp-cb {
  flex: none; width: 18px; height: 18px; border-radius: 5px;
  border: 1.5px solid var(--hair); background: var(--surface);
  display: grid; place-items: center; color: transparent;
}
.dp-cb svg { width: 12px; height: 12px; }
.dp-mrow.on .dp-cb { background: var(--brand); border-color: var(--brand); color: #fff; }
.dp-mname { flex: none; font-size: 13.5px; font-weight: 600; }
.dp-mmeta {
  min-width: 0; font-size: 11.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dp-sh-foot { display: flex; align-items: center; gap: 9px; margin-top: 14px; }

@media (max-width: 899px) {
  .dp-sheet { max-height: 92vh; border-radius: var(--r-xl) var(--r-xl) 0 0; }
  .dp-sh-list { max-height: 44vh; }
  .dp-kids { margin-left: 13px; padding-left: 8px; }
  .dp-row { min-height: 42px; padding: 5px 0; }
  .dp-count { display: none; }   /* 窄屏先让位给部门名与头像 */
}


/* ==================================================================
   云帆故事 · 使命 / 愿景 / 价值观 配图（STORY-FIG-R43 · 2026-09-22 帆哥）
   ------------------------------------------------------------------
   这三块原来是引用句 + 正文 / 条目列，帆哥要求「不要放内容，直接放这些图」。
   本段是**覆盖层**：新类名（.sy-fig / .sy-vfigs / .sy-vfig / .sy-figbar /
   .sy-figcode）此前全站不存在，与既有规则零交集；要回滚整段删掉即可。

   图片一律 width:100%，靠自身比例撑高（原图 16:9 上下）。
   边框用 var(--line) —— 使命/愿景那张图左右是浅蓝渐变到底，没有描边时
   在暖白卡片上会「糊」进背景，看不出图的边界在哪。
   ================================================================== */
.sy-fig { margin: 0; }
.sy-fig img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: #fff;
}

/* 价值观：PC 两列、手机一列（与 .sy-vals 的断点保持一致） */
.sy-vfigs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.sy-vfig { position: relative; margin: 0; }

/* 编辑态：图片地址条（只在 storyEditing 时渲染） */
.sy-figbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--ink-3);
}
.sy-figbar > span { flex: none; }
.sy-figcode {
  flex: 1 1 auto;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  padding: 5px 8px;
  border-radius: 7px;
  word-break: break-all;
}

/* 手机端：价值观单列。图上那行拼音（KEWANGTIAOZHAN 之类）在 170px 宽的格子里
   会糊成一条，宁可让页面长一点也要看得清字。 */
@media (max-width: 899px) {
  .sy-vfigs { grid-template-columns: 1fr; }
  .sy-fig img, .sy-vfig img { border-radius: 11px; }
}


/* ===========================================================
   第 39 轮（2026-09-22）首页摘要：可见行数与缩略图几何绑定
   -----------------------------------------------------------
   帆哥反馈的三类首页观感问题及对应修法：

   ① 「正文里还有半句话，首页看不到，点开才发现多了半句」
      根因在 JS 侧：旧 excerptOf 只在超过 72 字时才补省略号，
      26~72 字这一档是「无声截断」。已改为把完整正文交给 CSS ——
      内容溢出时浏览器必然给出省略号，截断从此看得见。

   ② 「有图帖左侧只有两行，明明可以多显示一行，左右看起来更美观」
      就是下面这段要解决的事。旧值：左侧 2 行、右侧缩略图 78px。
        手机（≤899px）单行 = 14.5px x 1.7 = 24.65px，2 行 = 49.3px
        → 与 78px 的缩略图差出 28.7px（约 1.16 行），白白空着。
        PC 更浪费：单行 12.5px x 1.6 = 20px，2 行 = 40px，
        缩略图 92px → 空出 52px（约 2.6 行）。
      修法：行数与缩略图边长由同一组变量推导，两者永远齐平。

   ③ 「纯文字帖显示两行，点开只剩一句话」
      由 ① 的改动自动消失：正文不满可见行数就整段显示、不加省略号。
      再叠加 JS 侧 relaxExcerpts() 处理「只多出一行」的边缘情况
      —— 注意判据是「被藏起来的行数 === 1」，不是像素区间：
      浏览器换行以整行为单位，溢出量恒为行高的整数倍（实测无中间值）。

   变量口径
   -----------------------------------------------------------
   --ex-lines  可见行数：PC 无图 3 / PC 有图 4 / 手机一律 3
   --ex-lh     单行行高，必须等于 .fr-ex 的 font-size x line-height
                 PC    12.5px x 1.6  = 20px
                 手机  14.5px x 1.7  = 24.65px
   --ex-lines 与 --ex-lh 的乘积同时是缩略图边长（正方形，随行数自动变）：
     手机有图 3 x 24.65 = 73.95px（与原来的 78px 基本一致）
     PC  有图 4 x 20    = 80px   （比原来的 92px 略小，但文字列更宽）

   ⚠️ 这一段必须留在文件**最末尾**：它靠「同特异性、后写胜出」覆盖上方的
      .fr-ex（1912 行）与 .fr-side-pic（2691 行、含 520px 断点里的
      width: 78px）。将来若要挪位置，必须一并核对这三处的先后顺序。
   ⚠️ .fr-side 上重新声明的 --ex-lines 会盖掉从 .feed-card 继承来的值，
      这是有意为之：首页「有图」与「无图」两种形态行数不同。
   =========================================================== */
.feed-card { --ex-lines: 3; --ex-lh: 20px; }
.fr-side { --ex-lines: 4; }
.fr-ex { -webkit-line-clamp: var(--ex-lines); }
.fr-side-pic {
  width: calc(var(--ex-lines) * var(--ex-lh));
  height: calc(var(--ex-lines) * var(--ex-lh));
  aspect-ratio: auto;
}
@media (max-width: 899px) {
  .feed-card { --ex-lines: 3; --ex-lh: 24.65px; }
  .fr-side { --ex-lines: 3; }
}

/* ===========================================================================
   2026-09-23（第 45 轮）个人页标签统一 —— METAGS-R45
   ---------------------------------------------------------------------------
   帆哥：个人页三个标签（等级徽章 / 总积分 / 积分榜第 N 名）大小不一样，
         以第一个（.lv-badge，20px 高）为准。
   根因：.lv-badge 是 20px 高 / 11px 字 / 圆角 5px / 内边距 7px，
         而 .tag 是 22px 高 / 11.5px 字 / 圆角 6px / 内边距 8px，
         两者并排就看出高差（20 vs 22）。
   做法：只在 .me-tags 作用域内把 .tag 对齐到 .lv-badge 的尺寸。
         不动全局 .tag —— 帖子列表、详情页、后台等处的标签不受影响。
   要回滚：删掉这一段即可，其余页面一行都不会受影响。
   =========================================================================== */
.me-tags .tag {
  height: 20px; padding: 0 7px; border-radius: 5px;
  font-size: 11px; font-weight: 700;
}

/* ===========================================================================
   2026-09-24（第 60 轮）个人页三标签 2px 错位收尾 —— METAGS-R60
   ---------------------------------------------------------------------------
   帆哥截图：Lv.1 徽章与后两个标签仍差 2px（R45 把高度统一到 20px 后还剩的）。
   根因：isMe 时第一个徽章外面包了一层 <span class="me-link">，它是 display:inline，
         作为 flex 子项被块化成 block 后高度由「行盒」决定（受 line-height 影响，
         Chrome 实测 24px），徽章在行盒内不参与 align-items:center 的精确对齐；
         而后两个 .tag 是 inline-flex，块化后高度就是内容高 20px → top/bottom 各差 2px。
   做法：只把 .me-tags 作用域内的 .me-link 变成 flex 容器，高度收敛到内容高 20px，
         与 .tag 同高同轴。积分页 .pt-lvrow 里的 .me-link 是另一处使用，不受影响。
   要回滚：删掉这一段即可。
   =========================================================================== */
.me-tags .me-link { display: flex; align-items: center; }


/* ===========================================================================
   第 49 轮（2026-09-23 帆哥）云帆故事整页版式重做 + 践行案例系统 —— STORY-R49
   ---------------------------------------------------------------------------
   帆哥的原话拆解：
   ① 顶部蓝区只留一句话（「云帆文化的坚守」变色），kicker / 大标题 / 数据条不再渲染；
   ② 六个板块不标序号、不要导航按钮 —— 企业形象页，往下滑自然看完；
   ③ 使命 / 愿景仍并排，但白框太大、图上的字看不清 → 卡片内边距收窄，图贴边放大；
   ④ 价值观四张图一横排（原来两列），同样尽量大；
   ⑤ 文化专题：顶部三行是注释，下面按「××为××：」分块（正能量 2 块、目标导向 1 块）；
   ⑥ 践行案例 = 真实帖子：故事页最多 5 张卡（左头像名部门 / 右内容 + 点赞评论浏览），
      独立的案例列表页（部门 + 年份筛选、20/页、下一页）、管理员弹窗录入；
   ⑦ 首页最新动态：小红花 + 红底黄字标题、右侧钉钉头像、不显示发帖人；
   ⑧ 详情页：无作者无时间、红金喜庆边框、案例人名片浮右上、点赞鼓励 → 点赞学习 👍。

   本段是**覆盖层**：.sy-mv / .sy-vrow / .sy-cle / .sy-cul2* / .csc* / .csl-* /
   .csm-* / .fr-case-* / .fr-flower / .case-detail / .pd-case-* / .cs-thumb
   全是新类名，与既有规则零交集；少数既有类的覆盖（.sy-hero/.sy-lead/.sy-fig）
   都写成更高优先级或更具体的后代选择器。要回滚：删掉本段 + app.js 第 49 轮段即可。
   =========================================================================== */

/* ---- ① 顶部蓝区：一句话居中 ---- */
.sy-hero { padding: 42px 36px 38px; text-align: center; }
.sy-hero .sy-lead {
  margin: 0 auto; max-width: 720px;
  font-size: 15.5px; line-height: 2.05; color: rgba(255, 255, 255, .88);
}
/* 强调词：白底卡片上用深金（#8A6415 与页脚同一支），蓝区里用亮金 */
.sy-hl { font-style: normal; font-weight: 700; color: #8A6415; }
.sy-hero .sy-hl { color: var(--gold-300); }

/* ---- ③ 使命 / 愿景：收窄白框，图贴边放大 ----
   原来 .sy-sec 的 padding 是 26/28px，图四周一大圈白，1279×720 的图在半宽格子里
   只剩约 380px 宽，图上的字自然糊。收窄到 14px 后图宽直接 +28px，
   标题行保留（使命 / 愿景四个字是板块名，不能去）。 */
.sy-mv { padding: 14px 14px 16px; }
.sy-mv .sy-sec-head { margin-bottom: 11px; padding: 2px 4px 0; }
.sy-mv .sy-fig img { border-radius: 10px; }

/* ---- ④ 价值观：四图一横排 ----
   PC 一律四列（帆哥：「四张图一排」）；内容列最窄 496px（1100 断点谷）时每格
   约 115px，图上拼音会糊，但这道谷只存在 100px 区间，899 以下已转两列，
   接受这一点比再引入一档断点干净。 */
.sy-vrow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.sy-vrow .sy-vfig { position: relative; margin: 0; }

/* ---- ⑤ 文化专题：注释 + 分组子块 ---- */
.sy-cle {
  margin: 0 0 15px; padding: 13px 16px;
  border-left: 3px solid var(--gold); border-radius: 0 var(--r-xs) var(--r-xs) 0;
  background: var(--gold-050);
  font-size: 13.5px; line-height: 1.9; color: var(--ink-2);
}
.sy-cul2s { display: flex; flex-direction: column; gap: 12px; }
.sy-cul2 {
  padding: 15px 17px 16px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.sy-cul2-t {
  margin-bottom: 11px; padding-left: 10px;
  border-left: 3px solid var(--gold); line-height: 1.3;
  font-size: 15px; font-weight: 800; color: var(--brand-ink);
}
.sy-cul2-bs { display: grid; gap: 10px; }
.sy-cul2-bs.n2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sy-cul2-b {
  padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--hair); border-radius: var(--r-xs);
}
.sy-cul2-b b { display: block; font-size: 13.5px; font-weight: 750; color: var(--brand-ink); margin-bottom: 6px; }
.sy-cul2-b p { margin: 0; font-size: 13px; line-height: 1.85; color: var(--ink-3); }

/* ---- ⑥ 践行案例卡（故事页模块 + 案例列表页共用） ----
   左列：方形头像 + 名字 + 事业部；右列：表述（最多 3 行截断）+ 点赞/评论/浏览。
   整卡可点（跳列表页或帖子），点赞那颗单独响应（事件里已 stopPropagation）。 */
.sy-sec-acts { margin-left: auto; align-self: center; display: flex; align-items: center; gap: 12px; }
.sy-sec-sub + .sy-sec-acts { margin-left: 14px; }   /* 小注的 margin-left:auto 已经把两组一起顶到右边 */
.sy-case-more { font-size: 12.5px; color: var(--ink-3); cursor: pointer; white-space: nowrap; }
.sy-case-more:hover { color: var(--brand); }

.csc-list { display: flex; flex-direction: column; gap: 11px; }
.csc {
  display: flex; gap: 14px; padding: 15px 16px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.csc:hover { border-color: rgba(198, 40, 40, .38); box-shadow: var(--sh-1); }
.csc-side { flex: none; width: 76px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 5px; }
.csc-ava {
  width: 56px; height: 56px; border-radius: 10px; overflow: hidden;
  display: grid; place-items: center;
  background: var(--brand-050); border: 1px solid var(--line);
}
.csc-ava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.csc-ava-t { font-size: 17px; font-weight: 800; color: var(--brand); }
.csc-nm { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.csc-dp { font-size: 11px; line-height: 1.45; color: var(--ink-3); }
.csc-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.csc-tx {
  font-size: 13px; line-height: 1.8; color: var(--ink-2);
  white-space: pre-line;                         /* 保留管理员写的换行 */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.csc-acts { display: flex; gap: 16px; margin-top: auto; padding-top: 10px; font-size: 12px; color: var(--ink-3); }
.csc-acts i { font-style: normal; display: inline-flex; align-items: center; gap: 4px; }
.csc-acts svg { width: 13px; height: 13px; }
.csc-lk { cursor: pointer; }
.csc-lk.on { color: var(--like); }
.csc-empty {
  padding: 30px; text-align: center; font-size: 13px; color: var(--faint);
  border: 1px dashed var(--hair); border-radius: var(--r-sm);
}

/* ---- ⑥b 案例列表页（帆哥叫它「案例详情页」） ---- */
.csl-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.csl-head h2 { margin: 0; font-size: 18px; font-weight: 750; letter-spacing: -.01em; }
.csl-back { font-size: 13px; color: var(--ink-3); cursor: pointer; white-space: nowrap; }
.csl-back:hover { color: var(--brand); }
.csl-filter { padding: 12px 16px; margin-bottom: 12px; }
.csl-row { display: flex; gap: 10px; align-items: baseline; padding: 4px 0; }
.csl-lb { flex: none; font-size: 12px; font-weight: 700; color: var(--faint); }
.csl-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.csl-chip {
  font-size: 12.5px; padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--hair); color: var(--ink-2); cursor: pointer;
  transition: .15s;
}
.csl-chip:hover { border-color: var(--brand); color: var(--brand-ink); }
.csl-chip.on { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }
.csl-more { margin-top: 12px; }
.csl-total { text-align: center; margin-top: 12px; }

/* ---- ⑥c 添加 / 编辑案例弹窗 ----
   z-index 92 与站内其他整屏遮罩同档（shop 弹层等）。 */
.csm-mask {
  position: fixed; inset: 0; z-index: 92;
  background: rgba(10, 16, 30, .45);
  display: grid; place-items: center; padding: 18px;
}
.csm {
  width: min(520px, 100%); max-height: 88vh; overflow: auto;
  background: var(--surface); border-radius: var(--r-md);
  padding: 20px 22px; box-shadow: var(--sh-3);
}
.csm-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.csm-h b { font-size: 16px; font-weight: 750; }
.csm-x { display: inline-flex; padding: 4px; color: var(--ink-3); cursor: pointer; }
.csm-x:hover { color: var(--ink); }
.csm-x svg { width: 16px; height: 16px; }
.csm-fld { margin-bottom: 13px; }
.csm-fl { font-size: 12.5px; font-weight: 700; color: var(--ink-3); margin-bottom: 7px; }
.csm-person {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2);
}
.csm-pava {
  flex: none; width: 42px; height: 42px; border-radius: 8px; overflow: hidden;
  display: grid; place-items: center;
  background: var(--brand-050); border: 1px solid var(--line);
}
.csm-pava.sm { width: 34px; height: 34px; }
.csm-pava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.csm-pava .csc-ava-t { font-size: 14px; }
.csm-ptx { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.csm-ptx b { font-size: 14px; color: var(--ink); }
.csm-ptx span { font-size: 12px; color: var(--ink-3); }
.csm-repick { flex: none; font-size: 12px; color: var(--brand); cursor: pointer; }
.csm-plus {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 15px; border: 1.5px dashed var(--hair); border-radius: var(--r-sm);
  background: none; color: var(--ink-3); font-size: 14px; cursor: pointer;
  transition: .15s;
}
.csm-plus:hover { border-color: var(--brand); color: var(--brand); }
.csm-pick {
  margin: -4px 0 13px; padding: 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2);
}
.csm-pick .sh-in { width: 100%; }
.csm-plist { margin-top: 8px; max-height: 220px; overflow: auto; display: flex; flex-direction: column; }
.csm-prow { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 8px; cursor: pointer; }
.csm-prow:hover { background: var(--brand-050); }
.csm-ta { width: 100%; min-height: 120px; resize: vertical; }

/* ---- ⑦ 首页最新动态的案例卡 ----
   小红花顶替频道竖条；标题做成红底黄字的胶囊（喜庆、庄重）；
   右侧缩略图位置放案例人的钉钉头像（方形圆角，尺寸跟 .fr-side-pic 同体系）。 */
.fr-title.case-t { align-items: center; }
.fr-flower { flex: none; font-size: 14px; line-height: 1; }
.fr-case-pill {
  display: inline-block; max-width: 100%;
  padding: 3px 11px; border-radius: 7px;
  background: linear-gradient(135deg, #B71C1C, #D32F2F 62%, #C62828);
  box-shadow: inset 0 0 0 1px rgba(255, 220, 130, .38);
  color: #FFE9A8; font-weight: 700; font-size: .92em; line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fr-case-ava {
  flex: none; width: 78px; height: 78px; border-radius: 11px; overflow: hidden;
  display: grid; place-items: center;
  background: var(--brand-050); border: 1px solid var(--pic-edge);
}
.fr-case-ava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fr-case-ava .csc-ava-t { font-size: 22px; }
/* 底部没有发帖人：.fr-sp 本来就 margin-left:auto，整行只剩时间 + 三个数据，自然靠右 */
.case-foot { margin-top: 8px; }

/* ---- ⑧ 案例帖详情页 ----
   红金双环边框（外红内金）= 喜庆庄重；红底黄字横幅替标题；
   案例人名片浮在正文右上，正文从左上起、名片下方自动回满宽（名片效果）。 */
.post-detail.case-detail { position: relative; border: 1px solid rgba(198, 40, 40, .32); }
.post-detail.case-detail::before {
  content: ''; position: absolute; inset: 5px; pointer-events: none;
  border: 1px solid rgba(200, 161, 90, .45); border-radius: calc(var(--r-lg) - 6px);
}
.pd-case-band {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin: 2px 0 16px; padding: 12px 18px; border-radius: 10px;
  background: linear-gradient(135deg, #B71C1C, #D32F2F 62%, #C62828);
  box-shadow: inset 0 0 0 1px rgba(255, 220, 130, .38);
  color: #FFE9A8; font-size: 18px; font-weight: 800; letter-spacing: .02em;
  text-align: center; line-height: 1.5;
}
.pd-case-flower { font-size: 17px; }
.pd-case-wrap { overflow: hidden; }              /* 包住右浮的名片 */
.pd-case-card {
  float: right; width: 148px; margin: 2px 0 12px 18px;
  padding: 14px 12px 12px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  border: 1px solid rgba(200, 161, 90, .55); border-radius: 12px;
  background: linear-gradient(160deg, #FFFDF6, #FBF3DF);
}
.pd-case-ava {
  width: 76px; height: 76px; border-radius: 12px; overflow: hidden;
  display: grid; place-items: center;
  background: var(--brand-050); border: 1px solid var(--line);
}
.pd-case-ava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pd-case-ava .csc-ava-t { font-size: 24px; }
.pd-case-card b { font-size: 15px; font-weight: 800; color: var(--ink); }
.pd-case-card > span:last-child { font-size: 11.5px; line-height: 1.5; color: var(--ink-3); }

/* 点赞学习 👍：未点是灰的（去色 + 半透明 ≈ 描边感），点了恢复彩色；
   次数跟着点中的金色走（案例帖不用点赞红）。emoji 改不了描边，滤镜是最接近的方案。 */
.cs-thumb { font-size: 18px; line-height: 1; filter: grayscale(1) opacity(.5); transition: filter .15s; }
.cs-thumb.on { filter: none; }
.case-detail .pd-sbtn-like.on .pd-sbtn-ico,
.case-detail .pd-sbtn-like.on .pd-sbtn-n { color: #C9930F; }

/* ---- 手机端（≤899px / ≤599px） ---- */
@media (max-width: 899px) {
  .sy-hero { padding: 28px 22px 25px; }
  .sy-hero .sy-lead { font-size: 14px; line-height: 2; text-align: left; }
  .sy-vrow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fr-case-ava { width: 64px; height: 64px; }
  .pd-case-card { width: 126px; margin-left: 14px; }
  .pd-case-ava { width: 62px; height: 62px; }
}
@media (max-width: 699px) {
  .sy-cul2-bs.n2 { grid-template-columns: 1fr; }
}
@media (max-width: 599px) {
  .csc { gap: 11px; padding: 13px 13px; }
  .csc-side { width: 62px; }
  .csc-ava { width: 48px; height: 48px; }
  .csc-nm { font-size: 12.5px; }
  .csc-dp { font-size: 10.5px; }
  .pd-case-band { font-size: 15.5px; padding: 10px 14px; }
  .pd-case-card { width: 108px; padding: 11px 9px 10px; }
  .pd-case-ava { width: 54px; height: 54px; }
  .pd-case-card b { font-size: 13.5px; }
  .post-detail.case-detail::before { inset: 4px; }
  .csl-head h2 { font-size: 16.5px; }
  .csm { padding: 17px 16px; }
}


/* ===========================================================================
   第 50 轮（2026-09-24 帆哥）云帆故事页精修 —— STORY-R50
   ---------------------------------------------------------------------------
   帆哥逐屏提了 8 条，按图对号：
   ① hero 蓝区：文字**两端对齐**、上下留白收窄（「蓝条高度小一些，显得秀气」）
   ② 使命/愿景/价值观：留白再收、图再放大；**价值观标题顶部与使命愿景对齐**；
      价值观右上角空位放「图形 + 无际云帆 + WUJIYUNFAN」组合标
   ③ 文化专题：去掉右上角「2026年」；整块重做（帆哥：「毫无美感和设计感」）
   ④ 案例卡：点赞/评论/浏览从左侧移到**右侧**（故事页模块 + 案例列表页共用）
   ⑤ 发展史 → **云帆发展史**，年份与圆点加特效（「太平面」）
   ⑥ 页脚「想了解更多…」整块去掉
   ⑦ 案例帖详情页：头像放大到贴住金色名片框，框内下方放名字（左）+ 部门/岗位（右两行）

   与第 49 轮同一手法：这段是**覆盖层**，全部写在文件最后。
   要回滚第 50 轮：删掉本段 + app.js 里带「第 50 轮」注释的几处即可。
   ⚠️ 本文件 1623 行处的 :root 覆盖才是**实际生效**的令牌（brand #4A5BF0 靛蓝），
      新样式一律走 var(--brand*)，不要凭 9 行的旧值（#0A5AA8）写死。
   =========================================================================== */

/* ---- ① hero：两端对齐 + 收窄上下留白 ------------------------------------
   原来 padding 42/38 + 15.5px/2.05 行高 + max-width 720 → 蓝条高 ~175px，
   三行且四周全是空。现在：留白 24/22，行宽放到 800（约 55 字/行，中文阅读舒适区），
   三行变两行、行高 1.95 → 实测高度约 100px，秀气且不挤。
   text-align: justify 让每行首尾都顶到边；最后一行仍左对齐（text-align-last 保持默认 auto）。 */
.sy-hero { padding: 24px 34px 22px; }
.sy-hero .sy-lead {
  max-width: 800px; margin: 0 auto;
  font-size: 14.5px; line-height: 1.95;
  text-align: justify; text-justify: inter-ideograph;
  color: rgba(255, 255, 255, .9);
}

/* ---- ② 三个图板块：统一内边距、图贴边、标题对齐 ---------------------------
   🚨 帆哥抓到的根因：第 49 轮只把 .sy-mv（使命/愿景）的 padding 收到 14px，
      价值观所在的 .sy-sec 还是旧的 26/28px —— 于是「价值观」离卡顶比「使命」远。
      现在两个值一起定，并让标题左边缘与图左边缘**对上**：
        价值观：卡 18 / 标题 18（对齐）
        使命愿景：卡 10 + 标题内缩 8 = 18  ← 同一个 18，肉眼看不出差
      图宽也因此各多出 16~8px（帆哥：「图片可以再放大一些」）。 */
.sy-sec { padding: 16px 18px 18px; }
.sy-sec-head { margin-bottom: 14px; }
.sy-mv { padding: 10px 10px 13px; }
.sy-mv .sy-sec-head { margin-bottom: 10px; padding: 4px 8px 0; }
.sy-pair { gap: 0 12px; }
.sy-vrow { gap: 10px; }

/* 价值观右上角的品牌组合标（透明 PNG，从官方品牌图裁出 —— 真实素材，不许 AI 重画）。
   高 32px：够看清「无际云帆 / WUJIYUNFAN」，又不至于抢标题的视觉重心。 */
.sy-brand-w { margin-left: auto; align-self: center; display: inline-flex; }
.sy-brand { display: block; height: 32px; width: auto; }

/* ---- ③ 文化专题：整块重做 ------------------------------------------------
   老版的问题（帆哥说「毫无美感和设计感」，看截图确实是）：
     · 引言 = 一块实心米色方框，和下面的蓝框、白框三层方块叠着，全是"框"；
     · 分组名只是 15px 加粗，子块是纯白方框，没有任何层级提示；
     · 右上角还挂着一个和内容无关的「2026年」（本轮已从数据与渲染两处去掉）。
   新版三层结构，从"堆方框"改成"有节奏的版式"：
     引言  = 金色左竖条 + 暖白渐变 + 大号装饰引号（去掉实心米底）
     分组头 = 靛蓝渐变序号徽章 + 分组名 + 右侧极浅英文标签（纯装饰）
     子块  = 白卡 + 顶部金色角标，正文两端对齐
   分组的"分界线"靠左侧渐变竖条 + 18px 的组间距，不再靠底色块。 */
.sy-cle {
  position: relative; margin: 0 0 18px; padding: 15px 20px 15px 44px;
  border: 1px solid rgba(200, 161, 90, .22); border-left: 3px solid var(--gold);
  border-radius: 4px var(--r-xs) var(--r-xs) 4px;
  background: linear-gradient(100deg, #FFFCF3, #FDFEFF 72%);
  font-size: 13.5px; line-height: 1.95; color: var(--ink-2);
  text-align: justify; text-justify: inter-ideograph;
}
.sy-cle::before {
  content: '\201C'; position: absolute; left: 13px; top: 7px;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 38px; line-height: 1; color: rgba(200, 161, 90, .42);
}
.sy-cgs { display: flex; flex-direction: column; gap: 18px; }
.sy-cg { position: relative; padding-left: 18px; }
.sy-cg::before {
  content: ''; position: absolute; left: 0; top: 3px; bottom: 3px; width: 3px;
  border-radius: 3px;
  background: linear-gradient(180deg, var(--brand), rgba(74, 91, 240, .06));
}
.sy-cg-h { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
.sy-cg-no {
  flex: none; width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--brand), var(--violet, #7C5CFF));
  color: #fff; font-size: 11.5px; font-weight: 800; letter-spacing: .02em;
  box-shadow: 0 3px 8px rgba(74, 91, 240, .26);
}
.sy-cg-h > b { font-size: 16.5px; font-weight: 800; color: var(--brand-ink); letter-spacing: .01em; }
.sy-cg-h > i {
  margin-left: auto; font-style: normal; font-size: 9.5px; font-weight: 800;
  letter-spacing: .18em; color: #C4CEE2; text-transform: uppercase;
}
.sy-cg-bs { display: grid; gap: 11px; }
.sy-cg-bs.n2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sy-cg-b {
  position: relative; padding: 13px 16px 14px;
  background: linear-gradient(180deg, #FFFFFF, #FCFDFF);
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(19, 26, 46, .035);
}
.sy-cg-b::before {
  content: ''; position: absolute; left: 16px; top: -1px; width: 22px; height: 3px;
  border-radius: 0 0 3px 3px;
  background: linear-gradient(90deg, var(--gold), var(--gold-300));
}
.sy-cg-b > b {
  display: block; margin: 3px 0 7px;
  font-size: 14px; font-weight: 800; color: var(--brand-ink); letter-spacing: .01em;
}
.sy-cg-b > p {
  margin: 0; font-size: 13px; line-height: 1.9; color: var(--ink-2);
  text-align: justify; text-justify: inter-ideograph;
}

/* ---- ④ 案例卡：三个数据靠右 ----------------------------------------------
   帆哥：「点赞评论和浏览放在右侧」——故事页模块与列表页共用 .csc-acts，
   一条 justify-content 两处同时生效。 */
.csc-acts { justify-content: flex-end; }
/* feed 卡头像框：--pic-edge 只在 .post-card 作用域里定义过，这里给回退值，
   拿不到就是 currentColor（深色边），很丑也可能被判成"设计变了"。 */
.fr-case-ava { border-color: var(--pic-edge, var(--hair)); }

/* ---- ⑤ 云帆发展史：年份与圆点加特效 --------------------------------------
   帆哥：「太平面」——原来年份是一行普通蓝字、圆点是死板的蓝圈。
   现在年轮式处理：年份渐变描色 + 圆点光环 + hover 时整条亮起、圆点变金发光，
   进场时每条依次上浮（纯 CSS，无 JS 依赖）。
   ⚠️ 圆点的 left/尺寸一个字都没动 —— 那一组值是第 49 轮前用几何推导校准过的
      （见本文件 4827 行处的推导注释），只加 box-shadow/transition（不参与布局）。 */
.sy-hiss { padding-left: 18px; }
.sy-hiss::before {
  background: linear-gradient(180deg, rgba(74, 91, 240, .5), rgba(74, 91, 240, .05) 94%);
}
.sy-his { padding: 12px 0 14px; border-radius: 10px; transition: background .18s; }
.sy-his:hover { background: linear-gradient(90deg, rgba(74, 91, 240, .05), rgba(74, 91, 240, 0) 78%); }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .sy-his-y {
    font-size: 17px; font-weight: 900; letter-spacing: .01em;
    background-image: linear-gradient(180deg, #4A5BF0 0%, #8FA6FF 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
  .sy-his:hover .sy-his-y { filter: saturate(1.3) brightness(1.06); }
}
.sy-his-b::before { transition: box-shadow .2s, border-color .2s, background .2s, transform .2s; }
.sy-his:hover .sy-his-b::before {
  border-color: var(--gold); background: #FFF6E2;
  box-shadow: 0 0 0 5px rgba(200, 161, 90, .16), 0 0 14px rgba(200, 161, 90, .38);
  transform: scale(1.14);
}
@keyframes sy-his-up {
  from { opacity: 0; transform: translateY(9px); }
  to { opacity: 1; transform: none; }
}
/* 编辑态条目带 .sy-ew（工具按钮锚点），编辑时不要重播动画 —— 每次改字都闪一下很晕 */
.sy-hiss .sy-his:not(.sy-ew) { animation: sy-his-up .48s cubic-bezier(.22, .85, .32, 1) both; }
.sy-hiss .sy-his:nth-child(1) { animation-delay: .02s; }
.sy-hiss .sy-his:nth-child(2) { animation-delay: .07s; }
.sy-hiss .sy-his:nth-child(3) { animation-delay: .12s; }
.sy-hiss .sy-his:nth-child(4) { animation-delay: .17s; }
.sy-hiss .sy-his:nth-child(5) { animation-delay: .22s; }
.sy-hiss .sy-his:nth-child(6) { animation-delay: .27s; }
.sy-hiss .sy-his:nth-child(7) { animation-delay: .32s; }
.sy-hiss .sy-his:nth-child(n+8) { animation-delay: .36s; }

/* ---- ⑦ 案例帖详情的名片：头像贴框、信息横排 -------------------------------
   帆哥：「头像显示太小，头像直接贴着外面那个黄色边框显示，图片下面…放名字和
   部门、岗位。名字在左侧，右侧分两行，上面部门，下面岗位。」
   → 卡片 padding 归零、头像通栏贴住金色边框（76px → 178×168），
     下方一条暖白信息带：左名字、右两行（部门 / 岗位）。 */
.pd-case-card {
  float: right; width: 178px; margin: 2px 0 16px 20px; padding: 0;
  display: block; text-align: left; overflow: hidden;
  border: 1px solid rgba(200, 161, 90, .62); border-radius: 14px;
  background: #fff;
  box-shadow: 0 6px 20px rgba(150, 118, 40, .13);
}
.pd-case-ava {
  width: 100%; height: 168px; border-radius: 0; border: 0;
  display: grid; place-items: center; overflow: hidden;
  background: var(--brand-050);
}
.pd-case-ava img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 0; }
.pd-case-ava .csc-ava-t { font-size: 34px; }
.pd-case-info {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 11px 11px;
  border-top: 1px solid rgba(200, 161, 90, .3);
  background: linear-gradient(180deg, #FFFDF7, #FFF8E8);
}
.pd-case-info > b { flex: none; font-size: 14.5px; font-weight: 800; color: var(--ink); letter-spacing: .01em; }
.pd-case-meta {
  margin-left: auto; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  text-align: right;
}
.pd-case-meta span { font-size: 10.5px; line-height: 1.35; color: var(--ink-3); }
.pd-case-meta span + span { color: var(--faint); }

/* ---- 手机端 ------------------------------------------------------------- */
@media (max-width: 899px) {
  .sy-hero { padding: 20px 20px 19px; }
  .sy-hero .sy-lead { max-width: none; font-size: 14px; line-height: 1.9; }
  .sy-sec { padding: 14px 14px 16px; }
  .sy-brand { height: 26px; }
  .sy-hiss { padding-left: 12px; }
  .pd-case-card { width: 152px; margin-left: 14px; }
  .pd-case-ava { height: 142px; }
}
@media (max-width: 699px) {
  .sy-cg-bs.n2 { grid-template-columns: 1fr; }
  .sy-cg-h > i { display: none; }        /* 手机端去掉装饰英文，省横向空间 */
}
@media (max-width: 599px) {
  .sy-mv { padding: 8px 8px 11px; }
  .sy-mv .sy-sec-head { padding: 3px 6px 0; }
  .sy-cle { padding: 13px 15px 13px 38px; }
  .sy-cle::before { left: 10px; top: 6px; font-size: 32px; }
  .sy-cg { padding-left: 14px; }
  .sy-cg-b { padding: 12px 13px 13px; }
  .pd-case-card { width: 132px; }
  .pd-case-ava { height: 124px; }
  .pd-case-info { padding: 8px 9px 9px; gap: 6px; }
  .pd-case-info > b { font-size: 13px; }
  .pd-case-meta span { font-size: 9.5px; }
  .sy-his { padding: 10px 0 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .sy-hiss .sy-his { animation: none; }
  .sy-his:hover .sy-his-b::before { transform: none; }
}

/* ---- ⑧ 故事页版心放宽（第 50 轮）------------------------------------------
   「留白太多、图片可以再放大一些」的根因：右栏 272px 白占。≥1100 才是三列，
   所以在同一断点里把 .shell-wide 收回两列 + 版心 1180 → 1280：
     · 内容列 648px → 1020px（+57%）
     · 价值观四图 152px → 240px 左右
   ⚠️ 900~1099 本来就是两列（右栏 CSS 隐藏），无需处理；<900 是 .shell display:block。 */
@media (min-width: 1100px) {
  .shell.shell-wide { grid-template-columns: 216px minmax(0, 1fr); max-width: 1280px; }
}

/* ---- 第 50 轮补充（截图复核后的小修） ------------------------------------- */
/* 案例卡左侧「事业部」原来 76px + 11px 字，7 个字的部门名（文创百货研发部）必折行 */
.csc-side { width: 84px; }
.csc-dp { font-size: 10.5px; line-height: 1.4; }
/* 文化专题子卡：一眼「能点/有反馈」的轻微上浮，别做成按钮那种重效果 */
.sy-cg-b { transition: border-color .18s, box-shadow .18s, transform .18s; }
.sy-cg-b:hover {
  border-color: rgba(74, 91, 240, .28);
  box-shadow: 0 6px 18px rgba(74, 91, 240, .10);
  transform: translateY(-1px);
}
@media (max-width: 599px) {
  .csc-side { width: 68px; }
}

/* ============================================================================
   第 51 轮 · 帖子卡片发帖时间：手机端从「题行右上角」挪到「卡片底部」
   （帆哥 2026-09-24 原话：「把每个帖子右上角的时间放在下边儿那个板块儿名字那里，
     每个帖子下边儿的那个板块儿名字不要，那儿放右上角那个时间」）
   ---------------------------------------------------------------------------
   手机端（≤899px，与本文件其它手机断点一致）：
     · 题行右上角的时间  → 隐藏
     · 底部「板块名」    → 隐藏（圈子页已按板块筛选，重复信息）
     · 底部时间节点      → 显示（占原板块名的位置，即统计图标左侧）
   PC / 平板（≥900px）：三处全部保持改动前形态，零变化。

   ⚠️ 两个时间节点（题行的 .pc-when 与底部的 .pc-when-ft）是**故意各自渲染一份**：
      CSS 无法把元素跨父容器搬运，用绝对定位去对齐 flex 底行既脆弱又会被后续
      改动碰坏。改动前题行那份是唯一的，现在仍是 PC 端显示的那一份；手机端显示底部那份。
   ⚠️ 隐藏用 display:none（不生成盒子）→ flex 的 gap 不会留下空档。
   回滚：整段删掉即可（app.js 那一个 <span> 一并删）。
   ============================================================================ */
.pc-when-ft { display: none; }          /* PC：底部时间不显示 */

@media (max-width: 899px) {
  .pc-trow .pc-when { display: none; }  /* 手机：题行右上角的时间收起来 */
  .pc-foot .pc-board { display: none; } /* 手机：底部板块名收起来 */
  .pc-foot .pc-when-ft {
    display: inline-flex; align-items: center;
    /* .pc-when 基础规则带 margin-left:auto（题行里用于贴最右）；
       搬进 .pc-sp 这个「宽度恰好等于内容宽」的容器后没有自由空间可吸收，
       但仍显式复位，避免以后 .pc-sp 改成弹性宽度时行为漂移。 */
    margin-left: 0;
  }
}

/* ============================================================================
   第 52 轮（2026-09-24）—— 公告落款 + 践行案例头像「出血」到卡片左上角
   ----------------------------------------------------------------------------
   帆哥两条需求（原话）：
     ① 「头像可以放大，头像上边和左边可以放大到外面的灰色边框的位置」
        （践行案例卡 .csc）
     ② 「公司公告，不显示顶部的发帖人头像和名字，部门，保留发布时间和
        全站公告，放在整个页面右下角」（公告详情）
   ============================================================================ */

/* ① 公告详情落款：题目 + 正文之外只剩这一行，灰色小字、贴内容右下角，
      日期只到年月日（由 app.js 的 fmtDate(x, false) 保证）。 */
.notice-detail .nd-foot {
  margin-top: 20px; text-align: right;
  font-size: 12px; line-height: 1.6; color: var(--faint);
}

/* ② 践行案例卡：头像放大，并让它的上边、左边一直顶到卡片边框。
      做法 —— 卡片上/左内边距归零（右/下不变），头像宽度 = 左侧列宽，
      于是头像左边缘正好压在卡片左边框内侧、上边缘贴在卡片顶边；
      右侧正文用 .csc-main 的 padding-top 保住原来的 15px 呼吸感。
      头像左上圆角对齐卡片圆角（--r-sm 12px 的内侧 ≈ 11px），
      其余三角保持 10px，这样贴边处不会露出方角。
      ⚠️ 只在 .csc 作用域内改，案例列表页复用同一个卡片 → 两处一致。 */
.csc { padding: 0 16px 15px 0; }
.csc-side { width: 88px; }
.csc .csc-ava {
  width: 88px; height: 88px;
  border-radius: 11px 0 10px 0;
  border: 0;                       /* 贴边后不需要描边，免得和卡片边框重影 */
}
.csc-main { padding-top: 15px; }
@media (max-width: 599px) {
  .csc { padding: 0 13px 13px 0; }
  .csc-side { width: 72px; }
  .csc .csc-ava { width: 72px; height: 72px; }
  .csc-main { padding-top: 13px; }
}

/* ============================================================================
   第 53 轮（2026-09-24）案例详情页返回 + 三处年月时间 —— CASEBACK-R53
   ----------------------------------------------------------------------------
   帆哥三条需求（原话）：
     ① 「这个页面加个返回上一页，否则看完了没有办法返回到践行案例这一页」
     ② 「'最新添加的排在最前' 改为 '按案例添加时间排序'」（文案在 app.js）
     ③ 详情页 / 列表页 / 故事页三处案例都加年月（如 2026年9月）：
        详情页放浏览头像前，另两处放点赞 ❤️ 前。

   ① 的根因（值得记一笔）：
     手机端 `.topbar` 早被整体撤掉（本文件 @media(max-width:899px){.topbar{display:none}}），
     当初的兜底是「钉钉工作台自带返回 + 底栏能回上级」——
     但**案例详情页两条路都不通**：底栏 5 个 tab 里没有「案例」（案例挂在云帆故事下），
     左栏导航也没有入口。PC 端 topbar 同样是 display:none。所以进去就真出不来了。
     → 补一个**页面级**返回按钮，落在案例帖卡片顶部（红色案例横幅上方）。
   ============================================================================ */

/* ① 案例详情页顶部「‹ 返回上一页」 */
.pd-case-back { margin: 0 0 14px; }
.pd-case-back .act {
  font-size: 12.5px; font-weight: 600; color: var(--ink-3);
  cursor: pointer; user-select: none;
}
.pd-case-back .act:hover { color: var(--brand); }

/* ③ 年月时间：比旁边的计数淡一档，只当时间锚点，不跟图标抢视觉 */
.csc-acts .csc-ym,
.pd-flags .pd-case-ym { color: var(--faint); }
.csc-acts .csc-ym { margin-right: 2px; }
.pd-flags .pd-case-ym { margin-right: 2px; }

/* ============================================================================
   第 54 轮（2026-09-24）案例详情「返回上一页」改为仅 PC 端 —— CASEBACK-PCONLY-R54
   ----------------------------------------------------------------------------
   帆哥原话：「刚刚在手机端加的返回上一页去掉，就是撤销这个任务，只保留 pc 端。」
   → 手机端（≤899px，与全站「手机端撤顶栏」同一断点）隐藏 .pd-case-back；
     PC 端（≥900px）原样保留第 53 轮加的那条返回条。

   做法：纯覆盖层，只加这一条媒体查询。
     · app.js 一行未动 —— 按钮结构两端都渲染，手机端只是不显示。
     · 第 53 轮的 .pd-case-back 规则（上方 130 行处）一行未动。
   要回滚（恢复手机端也显示）：删掉下面这一段即可。
   ============================================================================ */
@media (max-width: 899px) {
  .pd-case-back { display: none; }
}


/* ===========================================================================
   第 55 轮 CULTURE-R55 · 文化专题改版（方案 C「文化铭牌」，帆哥 2026-09-24 确认）
   深靛蓝底 + 描金 = 一块挂在墙上的企业文化铜牌。

   与第 50 轮那套（.sy-cg*）的关系：**不是覆盖，是替换** —— 新版式用的是全新的
   .sy-cul-* / .sy-wc-* 类名，老 .sy-cg* 规则原封不动留在文件里，继续给
   「themes 为空时退回旧版式」那条退路兜着。要整体回滚：删本段 + 删 app.js 里
   带「第 55 轮」注释的三处（STORY_DEFAULT.culture / 文化块渲染 / syKwtip），
   再把 settings.story_doc 里 culture.themes 删掉 —— 页面上立刻回到第 50 轮的样子。

   🚨 帆哥本轮的三条要求，逐条落在下面：
     ① 序号 01/02/03 不要了 —— 原来它占着左边 46px 栏位、标题和注释都要往右让，
        去掉后标题与注释直接顶到列内边距，每列多出约 46px 文字宽度 = 注释少折一行，
        整块高度随之压下来；
     ② 三大文化的名称用**原来序号那个金色渐变**（不是另配一个金色）；
     ③ 注释句换行从「每一位云帆人」的「每」字起 —— 换行位置在数据里（lead 的 \n），
        不靠宽度硬凑，任何屏宽下都断在同一处。
   =========================================================================== */

/* ---- ① 深色铭牌卡 ---- */
.sy-cul-dark {
  background: linear-gradient(152deg, #131A38, #1C2650 50%, #212D62);
  border-color: rgba(200, 161, 90, .30);
  box-shadow: 0 14px 40px rgba(14, 20, 44, .28);
}
.sy-cul-dark .sy-sec-head h2 { color: #fff; }
/* 板块名后面那行小英文是**装饰**（::after 而不是 DOM）：不进 DOM 就不会被
   编辑态读走、也不会占数据字段，改文案直接改这一行。 */
.sy-cul-dark .sy-sec-head h2::after {
  content: 'YUNFAN CULTURE'; margin-left: 14px; font-size: 9.5px; font-weight: 800;
  letter-spacing: .22em; color: rgba(227, 198, 133, .55); vertical-align: middle;
}
.sy-cul-tip {
  margin-left: auto; white-space: nowrap;
  padding: 4px 11px; border-radius: 999px;
  font-size: 11.5px; color: rgba(255, 255, 255, .62);
  background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .16);
}
/* 帆哥：「不加边框，就直接放在文化专题下方，字小一些」——
   所以这里**不用** .sy-cle（那条有金边框 + 引号 + 金底），另起一个素面类。
   text-align 用 left 不用 justify：justify 会把「每」字前那一行拉到满宽，
   行尾被拉开一截，正是帆哥要避免的观感。 */
.sy-cul-note {
  margin: 11px 0 20px; max-width: 790px;
  font-size: 12.5px; line-height: 1.95; color: rgba(255, 255, 255, .66);
  text-align: left;
}

/* ---- ② 一个网格装六块：上排三块铭牌、下排三块行为列 ----
   🚨 DOM 顺序是「铭牌1/列1/铭牌2/列2/铭牌3/列3」（交替），桌面端用 grid-row +
   grid-column 摆回上下两排 —— 视觉与「两个各三块的网格」一模一样，手机端一列流下来
   却自动成了「主题1 → 它自己的三层行为 → 主题2 → …」。
   这是**不拆成两个网格**的唯一原因：拆了就没法交错，手机端会先读完三个主题名、
   再连着看到九组行为，读者认不出哪组属于哪个主题。 */
/* 🚨 overflow 必须是 visible：悬停气泡虽然走 fixed，但祖先链上只要有
   overflow:hidden 又碰巧带 transform/filter，气泡就会被切。这里索性不裁 ——
   原来裁是为了让 glow 的圆角不下标题，改成给 glow 自己加 border-radius 即可。 */
.sy-wc {
  position: relative; border-radius: 14px; overflow: visible;
  background: linear-gradient(160deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .018));
  border: 1px solid rgba(255, 255, 255, .10);
}
.sy-wc-glow {
  position: absolute; inset: 0; pointer-events: none; border-radius: 14px;
  background: radial-gradient(560px 220px at 12% -10%, rgba(227, 198, 133, .16), transparent 68%),
              radial-gradient(500px 200px at 92% 106%, rgba(74, 91, 240, .30), transparent 70%);
}
.sy-wc-grid { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.sy-wc-grid > .sy-wc-pq { grid-row: 1; }
.sy-wc-grid > .sy-wc-col { grid-row: 2; }
.sy-wc-grid > [data-col="1"] { grid-column: 1; }
.sy-wc-grid > [data-col="2"] { grid-column: 2; }
.sy-wc-grid > [data-col="3"] { grid-column: 3; }
.sy-wc-pq { min-width: 0; padding: 19px 20px 18px; border-bottom: 1px solid rgba(255, 255, 255, .10); }
/* 竖分隔线只画在第 2、3 列（第 1 列左侧就是卡片边） */
.sy-wc-grid > [data-col="2"], .sy-wc-grid > [data-col="3"] { border-left: 1px solid rgba(255, 255, 255, .09); }
.sy-wc-pt { min-width: 0; }
/* 文化名 = 原序号的金色渐变（#F2DCAC → #C8A15A），与左导航/金色强调同一族。
   ⚠️ -webkit-text-fill-color:transparent 必须与 background-clip:text 成对出现；
      只写前者字就整个没了。老 WebView（钉钉 Mac）从 Safari 4 起就支持这一对。 */
.sy-wc-pt > b {
  display: block; font-size: 21px; font-weight: 800; letter-spacing: .02em; margin-bottom: 6px;
  background: linear-gradient(160deg, #F2DCAC, #C8A15A);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.sy-wc-pt > p {
  margin: 0; font-size: 11.5px; line-height: 1.8; color: rgba(255, 255, 255, .62);
  text-align: justify; text-justify: inter-ideograph;
}
.sy-wc-col { min-width: 0; padding: 17px 20px 20px; }

/* ---- ③ 三层行为：信号灯谱系（青绿 → 琥珀 → 中国红），底色由浅入深 ---- */
.sy-wc-lv {
  display: flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .05em; margin: 0 0 9px;
}
.sy-wc-lv > span { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.sy-wc-lv.yes { color: #5BE0B0; }
.sy-wc-lv.yes > span { background: #5BE0B0; box-shadow: 0 0 8px rgba(91, 224, 176, .65); }
.sy-wc-lv.no { color: #F5C065; }
.sy-wc-lv.no > span { background: #F5C065; box-shadow: 0 0 8px rgba(245, 192, 101, .6); }
.sy-wc-lv.zero { color: #FF8A8A; }
.sy-wc-lv.zero > span { background: #FF8A8A; box-shadow: 0 0 8px rgba(255, 138, 138, .6); }
/* :not(:first-child) 里第一颗是列的标题行，不画上线 */
.sy-wc-lv:not(:first-child) {
  margin-top: 15px; padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, .09);
}
.sy-wc-kws { display: flex; flex-wrap: wrap; gap: 7px; }
.sy-wc-kw {
  display: inline-flex; align-items: center;
  font-size: 12.5px; line-height: 1.2; white-space: nowrap;
  padding: 6px 11px; border-radius: 9px; cursor: help;
  color: rgba(255, 255, 255, .92);
  background: rgba(255, 255, 255, .065); border: 1px solid rgba(255, 255, 255, .14);
  transition: background .16s, border-color .16s, color .16s, transform .16s, box-shadow .16s;
}
.sy-wc-kw:hover, .sy-wc-kw:focus-visible {
  background: rgba(227, 198, 133, .18); border-color: rgba(227, 198, 133, .6);
  color: #FFE9A8; transform: translateY(-1px);
  box-shadow: 0 5px 14px rgba(200, 161, 90, .24); outline: none;
}

/* ---- ④ 悬停 / 点按气泡（DOM 由 syKwtip() 懒建在 body 上）----
   z-index 90：要在卡片之上、又必须在底部编辑工具条（91/92）与弹窗（9000+）之下。 */
#sy-kwtip {
  position: fixed; z-index: 90; left: 0; top: 0; width: 330px;
  padding: 13px 15px 14px; border-radius: 12px; background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 16px 40px rgba(16, 22, 46, .28), 0 0 0 4px rgba(74, 91, 240, .06);
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .14s, visibility .14s, transform .14s;
  pointer-events: none;
}
#sy-kwtip.on { opacity: 1; visibility: visible; transform: none; }
#sy-kwtip::after {
  content: ''; position: absolute; left: var(--ax, 50%); bottom: -6px;
  width: 12px; height: 12px; margin-left: -6px; background: #fff;
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  transform: rotate(45deg);
}
#sy-kwtip.below::after {
  bottom: auto; top: -6px; border: 0;
  border-left: 1px solid var(--line); border-top: 1px solid var(--line);
}
#sy-kwtip b {
  display: block; font-size: 13.5px; font-weight: 800; color: var(--brand-ink);
  margin-bottom: 7px; padding-bottom: 7px; border-bottom: 1px solid var(--hair);
}
#sy-kwtip b::before {
  content: ''; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: var(--brand); margin-right: 7px; vertical-align: middle;
}
#sy-kwtip p { margin: 0; font-size: 12.5px; line-height: 1.9; color: var(--ink-2); text-align: justify; }

/* ---- ⑤ 编辑态：三层行为全部铺开成可编辑行（深底上要重新配对比度）---- */
/* 编辑态：主题是竖着排的（没有「列」的概念），一个网格一列到底 */
.sy-wc-edit { grid-template-columns: minmax(0, 1fr); }
.sy-wc-ew { padding: 19px 20px 20px; }
.sy-wc-eh { position: relative; }
.sy-wc-eh > b {
  display: block; font-size: 21px; font-weight: 800; letter-spacing: .02em; margin-bottom: 6px;
  color: #F2DCAC;
  /* 编辑态的 contenteditable 元素不能走 background-clip:text ——
     光标与选区在透明填充的文字里看不见（实测：选区像没选中）。用实色金。 */
  -webkit-text-fill-color: currentColor;
}
.sy-wc-eh > p { margin: 0 0 4px; font-size: 11.5px; line-height: 1.8; color: rgba(255, 255, 255, .70); }
.sy-wc-el { margin-top: 14px; }
.sy-wc-eb {
  padding: 9px 11px 10px; border-radius: 9px;
  background: rgba(255, 255, 255, .045); border: 1px solid rgba(255, 255, 255, .12);
  margin-bottom: 7px;
}
.sy-wc-eb > b {
  display: block; font-size: 12.5px; font-weight: 800; color: #FFE9A8; margin-bottom: 5px;
}
.sy-wc-eb > p { margin: 0; font-size: 12px; line-height: 1.85; color: rgba(255, 255, 255, .74); }
/* 深底上的编辑态控件：直接套浅色版会「白底白边」，这里统一翻成半透明浅色 */
.sy-cul-dark .sy-edit { box-shadow: 0 0 0 1.5px rgba(230, 201, 140, .5); background: rgba(255, 255, 255, .07); }
.sy-cul-dark .sy-edit:hover { box-shadow: 0 0 0 1.5px rgba(230, 201, 140, .8); background: rgba(255, 255, 255, .12); }
.sy-cul-dark .sy-edit:focus { box-shadow: 0 0 0 2px var(--gold-300); background: rgba(255, 255, 255, .16); }
.sy-cul-dark .sy-tb {
  color: rgba(255, 255, 255, .82); background: rgba(255, 255, 255, .10);
  border-color: rgba(255, 255, 255, .22);
}
.sy-cul-dark .sy-tb:hover:not(:disabled) { border-color: var(--gold-300); color: #FFE9A8; }
.sy-cul-dark .sy-add, .sy-cul-dark .sy-add-mini {
  color: #E6C98C; background: transparent; border-color: rgba(230, 201, 140, .45);
}
.sy-cul-dark .sy-add:hover, .sy-cul-dark .sy-add-mini:hover { background: rgba(230, 201, 140, .12); }

/* ---- ⑥ 窄屏：一列到底，顺序就是「主题 → 它的三层行为」 ---- */
@media (max-width: 899px) {
  .sy-wc-grid { grid-template-columns: minmax(0, 1fr); }
  .sy-wc-grid > .sy-wc-pq, .sy-wc-grid > .sy-wc-col { grid-row: auto; grid-column: 1; }
  /* 竖分隔线全部收掉，改由每块的下沿分隔 */
  .sy-wc-grid > [data-col="2"], .sy-wc-grid > [data-col="3"] { border-left: 0; }
  .sy-wc-grid > *:not(:last-child) { border-bottom: 1px solid rgba(255, 255, 255, .09); }
  .sy-wc-pq { padding: 15px 16px 14px; }
  .sy-wc-col { padding: 14px 16px 16px; }
  .sy-wc-pt > b { font-size: 19px; }
}
@media (max-width: 699px) {
  .sy-cul-tip { display: none; }        /* 手机端横向本来就紧，提示胶囊让位 */
  #sy-kwtip { width: min(330px, calc(100vw - 24px)); padding: 11px 13px 12px; }
  #sy-kwtip p { font-size: 12px; }
}
@media (max-width: 599px) {
  .sy-cul-note { font-size: 12px; line-height: 1.9; }
  .sy-wc-kw { font-size: 12px; padding: 5px 10px; }
}

/* ============================================================================
   CASENAME-R55（2026-09-24）案例名片：职务长时让它「独占一行」
   🚨 轮次号撞车提示：本轮主题标签 = CASENAME-R55；同时另一个窗口在推
      「第 55 轮 CULTURE-R55 文化专题」，两者按**主题标签**区分，别按数字认。
   ----------------------------------------------------------------------------
   帆哥原话：「右侧这个人照片下面，职务比较长，直接换行了，第二行就一个字，很难看。
   其实你可以这么做，当案例人的职务比较长的时候，左侧的名字可以放在和岗位平齐的一行，
   那么职务就可以在不影响其他内容的情况下，在一行显示完整了。当案例人职务不长，
   不用换行的时候，那就按原有方案。」

   🔍 实测（手机端卡片 132px，信息带内宽 112px）——帆哥设想的排法差 7px：
     名字「沐光」27px + 列间距 6px = 占 33px；职务「高级新媒体运营专员」单行需 86px。
     → 「名字与职务同行」后职务只剩 112−33 = 79px < 86px，**还是放不下**。
     → 「职务独占一行」可获满宽 112px ≥ 86px，**放得下** ✅ → 采用后者。
     结论：真正腾出宽度的是「把名字从职务那一行挪走」、让职务独占一行。

   做法（只改排布，尺寸/字号/颜色一律不动）：
     信息带由 flex 两栏改为 2×2 栅格 ——
       第 1 行 = 名字（左） + 部门（右）   ← 名字与部门同行，与改前视觉一致
       第 2 行 = 职务（横跨两列，右对齐） ← 独占满宽，一行放得下

   · `.pd-case-meta { display: contents }` 拆掉它自己的盒子 → 里面两个 span 直接
     成为栅格的项，**app.js 一行都不用改**（纯 CSS 重排），风险最低。
   · 职务不长时（如「高级市场营销专员」76px、「市场营销专员」57px）：
     两个 span 仍各占一格、都右对齐，名字垂直居中 → 与改前**逐像素一致**（QA 已验）。
   · 手机端 599 档的 padding / 字号沿用原值；列间距 8px（手机 599 档 6px）与原值一致。
   · 若案例人没有职务（部门独占）→ 第 2 行空高为 0，不产生多余空档。
   要回滚：删掉本段即可（`display:contents` 一删即回到 flex 两栏）。
   ============================================================================ */
.pd-case-info {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: 8px; row-gap: 2px;
}
.pd-case-info > b { grid-column: 1; grid-row: 1 / span 2; }
.pd-case-meta { display: contents; }
.pd-case-meta > span:first-child { grid-column: 2; grid-row: 1; }
.pd-case-meta > span:nth-child(2) { grid-column: 1 / span 2; grid-row: 2; }
.pd-case-meta > span { justify-self: end; max-width: 100%; text-align: right; }
@media (max-width: 599px) { .pd-case-info { column-gap: 6px; } }


/* ===========================================================================
   第 56 轮（2026-09-24）· CASEPUSH-R56
   添加/编辑案例弹窗里新增两块：「案例照片」与「全员推送」。
   -------------------------------------------------------------------------
   案例照片占的是**方形头像位**（.csc-ava / .pd-case-ava / .fr-case-ava / .csm-pava），
   那四处本来就有 object-fit:cover + 圆角 + 描边，所以正方形照片放进去不用改一行；
   这也正是帆哥要「正方形」的原因 —— 与系统默认的钉钉头像同一个形状。
   开关本体直接复用发帖页「同步到群」那套 .sw-row / .sw，这里只补弹窗里的收边。
   =========================================================================== */

/* ---- ① 照片：方形预览框 + 右侧两行说明 ---- */
.csm-fl-o { font-weight: 500; font-size: 11.5px; color: var(--ink-3); }
.csm-photo { position: relative; display: flex; align-items: flex-start; gap: 13px; }
.csm-ph {
  flex: none; position: relative;
  width: 96px; height: 96px; padding: 0;
  display: grid; place-items: center; gap: 3px;
  border: 1.5px dashed var(--hair); border-radius: 12px;
  background: var(--surface-2); color: var(--ink-3);
  cursor: pointer; overflow: hidden;
  transition: border-color .15s, color .15s;
}
.csm-ph:hover { border-color: var(--brand); color: var(--brand); }
.csm-ph svg { width: 24px; height: 24px; }
.csm-ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.csm-ph.has { border-style: solid; border-color: var(--line); background: var(--surface); }
.csm-ph-t { font-size: 11.5px; line-height: 1; }
/* 上传中：蒙一层白纱 + 文案。上传成功后整窗重渲，这个类自然消失 */
.csm-ph.busy { opacity: .8; pointer-events: none; }
.csm-ph.busy::after {
  content: '上传中…'; position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .76); color: var(--ink-2); font-size: 12px;
}
/* 移除按钮。🚨 必须挂在 .csm-ph **外面**（那是个 overflow:hidden 的圆角框，
   放里面会被自己裁掉一半），但位置要落在框的**右上角内侧** ——
   第一版把它压到了框的右边缘上（left:85），圆心出框 10px、紧贴右侧那句提示文案，
   放大看就是「× 压在『只能上传…』上」。现在收进框内：69+22=91 < 96。 */
.csm-ph-del {
  position: absolute; left: 69px; top: 4px; z-index: 3;
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(16, 24, 40, .62); color: #fff; cursor: pointer;
  box-shadow: 0 1px 4px rgba(16, 24, 40, .3);
  transition: background .15s;
}
.csm-ph-del:hover { background: rgba(16, 24, 40, .9); }
.csm-ph-del svg { width: 11px; height: 11px; }
.csm-ph-tip { flex: 1 1 auto; min-width: 0; padding-top: 3px; }
.csm-ph-t1 { font-size: 12.5px; line-height: 1.65; color: var(--ink-2); }
.csm-ph-t1 b { font-weight: 700; color: var(--ink); }
.csm-ph-t2 { margin-top: 4px; font-size: 11.5px; line-height: 1.7; color: var(--ink-3); }
.csm-ph-warn { margin-top: 10px; }

/* ---- ② 全员推送：复用 .sw-row / .sw（见上面「需求 1 发布页」那段）----
   .sw-row 自带 var(--surface-2) 底 + 12/14 内边距；弹窗本身也是浅底，
   所以补一圈描边把它框出来，否则「这一块是个开关」在弹窗里看不出边界。 */
.csm .sw-row { padding: 11px 13px; border: 1px solid var(--line); gap: 12px; }
.csm .sw-d { line-height: 1.55; }

/* ---- ③ 案例详情页的方形位改成**严格正方形** ----
   第 50 轮为「头像放大贴金框」把它做成了通栏（桌面 178×168、手机 150×142 / 130×124）——
   那时里面放的是钉钉头像，6~8px 的横竖差看不出来；但第 56 轮起这个位置放的是
   **正方形照片**，非方容器会把它上下裁掉一截（.pd-case-ava img 是 object-fit:cover）。
   这里改成跟着宽度走的正方形：桌面高 168 → 176（只高 8px），三个断点一并生效。
   🚨 只动 .pd-case-ava 一处；.csc-ava（56）/ .fr-case-ava（78）/ .csm-pava（42）本来就是正方形。
   🚨 可撤：删掉这一条即回到第 50 轮的通栏版式（照片会被裁 4~5%，但不至于变形）。 */
.post-detail .pd-case-ava { height: auto; aspect-ratio: 1 / 1; }

/* ---- ④ 手机端（断点 899 与全站「手机端」口径同档）---- */
@media (max-width: 899px) {
  .csm-photo { gap: 11px; }
  .csm-ph { width: 84px; height: 84px; border-radius: 11px; }
  .csm-ph-del { left: 58px; top: 3px; width: 21px; height: 21px; }
  .csm-ph-tip { padding-top: 1px; }
  .csm-ph-t1 { font-size: 12px; }
  .csm-ph-t2 { font-size: 11px; }
  .csm .sw-row { padding: 10px 12px; gap: 10px; }
  .csm .sw-n { font-size: 13.5px; }
  .csm .sw-d { font-size: 11.5px; }
}

/* ==================================================================
   第 58 轮（2026-09-24）· 正文里的站外超链接 —— RTE-LINK-R58
   ------------------------------------------------------------------
   ⚠️ 为什么必须补这一段：文件顶部有 `a { color: inherit; text-decoration: none }`，
      也就是说正文里的超链接**长得和普通文字一模一样**。而编辑器内反而有样式
      （`.rte-area a`，见上方），于是出现「编辑时看得见是链接、发出去就看不见」的错位 ——
      用户以为链接没插上，其实是插上了但认不出来。
   只认 http / mailto 开头的站外地址，两条排除都很关键：
     · `.rte-file`（站内附件 /uploads/…）与 `.rte-video`（视频卡片）已有各自的卡片样式，
       不排除的话下面这几条会把卡片的白字深底覆盖成蓝字，卡片直接花掉；
       （:not() 串联写法 = Selectors 3，老 WebKit 也认；不要写成 :not(a, b) 那种多参数形式）
     · `#/` 开头的站内 hash 跳转（@提及、云帆故事锚点）刻意不动 —— 它是同页跳转，
       跟「外链」不是一回事，改了还会波及历史帖的观感。
   word-break：留一个 overflow-wrap，避免没选中文字时插入的长域名把版心撑出横向滚动条。
   ================================================================== */
.rt-body a[href^="http"]:not(.rte-file):not(.rte-video),
.rt-body a[href^="mailto:"] {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: break-word;
}
.rt-body a[href^="http"]:not(.rte-file):not(.rte-video):hover,
.rt-body a[href^="mailto:"]:hover { color: var(--brand-ink); }

/* 编辑器内补一条同款换行策略（原本只有 color/underline） */
.rte-area a { overflow-wrap: break-word; }

/* 超链接弹层里的「移除链接」次级按钮 */
.rte-lk-row { margin-top: 9px; }
.rte-lk-del {
  height: 30px; padding: 0 12px;
  border: 1px solid var(--hair); border-radius: 8px;
  background: var(--surface); color: var(--ink-2);
  font-family: inherit; font-size: 12.5px; line-height: 1;
  cursor: pointer; transition: .16s;
}
.rte-lk-del:hover { border-color: #E5484D; color: #E5484D; background: #FFF5F5; }
/* ===========================================================================
   第 59 轮（2026-09-24）· 首页「相册」→「积分商城」 —— 方案 A（帆哥选定）
   ---------------------------------------------------------------------------
   由 app.js 的 viewPortal() 输出：.section-head（「积分商城」+ 右侧「全部 N 件 ›」）
   + .mall-strip（一行 5 格）；每格上半是 1:1 产品图、底部是所需积分条。

   量（手机内容列 362px）：5 格 + 4×8px 间距 → 每格 66px；图 66 + 积分条 26 = 92px，
   与原相册几乎同高，页面不会因为这次改版变长。

   🚨 格子宽度一律 flex:1 1 0 均分，**绝不写死 px** ——
      写死 66px 就得同时写死一套左右内边距，容器宽度一变（手机 362 / 桌面 736）
      立刻左右错位。第 58 轮设计稿踩过这个坑（整行左移 14px），两端对齐是均分的副产品。
   🚨 图用 object-fit:cover（不是 contain）：方块位要「填满不露底」；
      被裁掉的两侧在详情页能看全（详情页首图用的是完整原图，不裁）。
   =========================================================================== */
.mall-strip { display: flex; gap: 8px; }

.mall-cell {
  flex: 1 1 0; min-width: 0; cursor: pointer;
  border-radius: 10px; overflow: hidden;
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--hair);
  transition: transform .14s, box-shadow .14s;
}
.mall-cell:hover { transform: translateY(-1px); box-shadow: 0 0 0 1px var(--brand), var(--sh-1); }
.mall-cell:active { transform: none; }

/* 图位：严格 1:1。底色兜住「还没加载完 / 加载失败 / 没配图」时的空档，
   不至于在页面上留一个没有边界的白块。 */
.mc-img {
  position: relative; aspect-ratio: 1 / 1;
  background: linear-gradient(180deg, #F4F6FB, #EDF0F8);
  display: flex; align-items: center; justify-content: center;
}
.mc-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mc-ph { color: #C7CCDA; display: flex; }
.mc-ph svg { width: 20px; height: 20px; }

/* 积分条：浅灰底 + 深金数字。金色与商城列表页同一个 #9C6F12（不另立一套）。 */
.mc-p {
  height: 26px; display: flex; align-items: center; justify-content: center;
  gap: 2px; white-space: nowrap;
  background: #F7F8FB; border-top: 1px solid var(--hair);
  font-size: 11px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.mc-p b { font-size: 13px; font-weight: 800; color: #9C6F12; letter-spacing: -.01em; }

/* 桌面端（≥900px —— 与全站「手机端 = ≤899px」同一档，别再另起 768/599）：
   内容列 736px，5 格均分到约 137px，比手机上大一倍；积分条跟着加厚，
   否则 137px 的图上压一条 26px 的细条会头重脚轻。 */
@media (min-width: 900px) {
  .mall-strip { gap: 12px; }
  .mall-cell { border-radius: 12px; }
  .mc-p { height: 34px; font-size: 12.5px; gap: 3px; }
  .mc-p b { font-size: 19px; }
  .mc-ph svg { width: 26px; height: 26px; }
}

/* ===========================================================================
   第 59 轮（2026-09-24）· 上架时的 1:1 封面裁剪器
   ---------------------------------------------------------------------------
   由 app.js 的 shopCrop 那段动态创建（只在管理员点「上传图片」时才出现在
   body 上，用完就 hidden，不占首页/圈子的 DOM）。
   取景框就是 canvas 本身，所以没有额外的遮罩层 —— 图片超出方框的部分
   被 canvas 边界自然裁掉，所见即所得。
   =========================================================================== */
.cc-mask {
  /* z-index 压过 9100（全站最高的浮动层）—— 裁剪器是独占式操作，
     弹着它的时候不该有别的浮层骑在上面。 */
  position: fixed; inset: 0; z-index: 9300;
  display: flex; align-items: center; justify-content: center;
  padding: 16px; background: rgba(10, 16, 32, .62);
}
.cc-mask[hidden] { display: none; }

.cc-panel {
  width: 100%; max-width: 420px;
  background: var(--surface); border-radius: 18px;
  box-shadow: var(--sh-3); padding: 16px 16px 14px;
  display: flex; flex-direction: column; gap: 12px;
}
.cc-hd { display: flex; align-items: baseline; gap: 8px; }
.cc-hd b { font-size: 15.5px; font-weight: 700; color: var(--ink); }
.cc-n { font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.cc-stage { display: flex; align-items: center; justify-content: center; }
.cc-stage canvas {
  display: block; border-radius: 12px; background: #0E1220;
  box-shadow: 0 0 0 1px var(--hair);
  cursor: grab;
  /* 🚨 少了 touch-action:none，手机上拖图会变成滚页面（指针事件被浏览器
     当成滚动手势接管），裁剪器直接变成不可用。 */
  touch-action: none;
}
.cc-stage canvas:active { cursor: grabbing; }

.cc-ctl { display: flex; align-items: center; gap: 10px; }
.cc-ctl span { font-size: 12px; color: var(--ink-3); white-space: nowrap; }
.cc-ctl input[type=range] {
  flex: 1; -webkit-appearance: none; appearance: none;
  height: 4px; border-radius: 999px; background: var(--surface-2);
  outline: none; margin: 0;
}
.cc-ctl input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 20px; height: 20px; border-radius: 50%;
  background: var(--brand); box-shadow: 0 1px 4px rgba(74, 91, 240, .4); cursor: pointer;
}

.cc-ft { display: flex; gap: 8px; }
.cc-ft .btn { flex: 1; padding: 0 10px; }
.cc-ft .btn-primary { flex: 1.25; }
.cc-tip { font-size: 11.5px; color: var(--faint); text-align: center; line-height: 1.5; }

/* ===========================================================================
   软键盘适配（2026-09-24 · 第 52 轮）
   ---------------------------------------------------------------------------
   症状：手机上点评论框，底部导航栏被顶到键盘上方，屏幕上叠成
        「输入框 + 导航栏 + 键盘」三层，评论内容被整片挤掉。

   成因：评论输入条 .composer-fixed 与底部导航 .tabbar 都是 position:fixed。
        钉钉 / 微信的安卓 WebView 键盘弹出走 adjustResize —— 可视区被压矮
        一个键盘的高度，两个 fixed 元素就各自上浮同样多。
        此前代码里没有任何键盘态，所以这不是偶发，是必然。

   处理：键盘弹出时 body 挂 .kb-open —— 导航栏收起、输入条落到最底，
        键盘上方只剩输入框（与帆哥的预期一致）。判定逻辑在 app.js 的
        initKeyboardAdapt()，它维护 --kb：
          · 安卓 adjustResize：可视区已缩到键盘上沿，贴底即可，--kb 为 0
          · iOS：可视区不变，靠 --kb（真实键盘高）把输入条抬到键盘上面

   范围：整块只在手机端（≤899px）生效 —— PC 端一个像素都不动。
   =========================================================================== */
@media (max-width: 899px) {
  body.kb-open .tabbar {
    transform: translateY(calc(100% + 26px));
    opacity: 0;
    pointer-events: none;
  }
  body.kb-open .composer-fixed { bottom: var(--kb, 0px); }
  /* 同一批写死 76px（悬浮导航占位）的贴底元素一起归位，
     否则修好一个又会在另一个页面露出同样的毛病。 */
  body.kb-open .sd-bar { bottom: var(--kb, 0px); }
  body.kb-open .sy-ebar { bottom: calc(var(--kb, 0px) + 8px); }
  /* 返回顶部：输入时它只会压住输入框，直接让开 */
  body.kb-open .back-top {
    opacity: 0 !important; visibility: hidden !important; pointer-events: none;
  }
  /* 键盘态下占位高度不用再给导航栏留那 76px，滚到底更紧凑 */
  body.kb-open .cf-spacer { height: 24px; }
  body.kb-open .sd-bar-gap { height: 26px; }
}

/* ===========================================================================
   每日签到（第 63 轮 · 2026-09-28 · 帆哥）
   ---------------------------------------------------------------------------
   ① .me-signin —— 个人页「名字那一行」最右侧的签到按钮
   ② .sc-pop    —— 点击后**向左下**弹出的小月历浮层
   ③ .sc-*      —— 浮层内部（顶部文案 / 月历 / 底部两行灰字）

   🚨 浮层必须挂在 document.body 上，不能塞进 .me-card 里 ——
      .me-card 有 overflow:hidden，塞进去会被裁成一个方块（技能日志有同类记录）。
   🚨 定位走 JS 的 placeSigninPop()（fixed + getBoundingClientRect 现算），
      这里只给尺寸和外观，**不写 left/top** —— .me-top 是 flex 且有媒体查询，
      CSS 算不准它。
   =========================================================================== */

/* ---------- ① 签到按钮 ---------- */
/* 落在 .me-top 这一行里：头像 → 姓名块 → 按钮。
   align-self:flex-end 让它底边与「姓名块」底边齐平 —— 就是帆哥说的
   「名字那一行的右侧」。flex:none 很关键：不给它伸缩，
   否则窄屏上它会和姓名块抢宽度，把「部门 · 职务」挤没。 */
.me-signin {
  flex: none; align-self: flex-end; margin-bottom: 2px;
  display: inline-flex; align-items: center; gap: 5px;
  height: 32px; padding: 0 13px; border-radius: 999px;
  border: 1px solid transparent;
  background: linear-gradient(135deg, var(--brand), var(--violet));
  color: #fff; font-size: 12.5px; font-weight: 700; letter-spacing: .02em;
  box-shadow: 0 6px 16px rgba(74, 91, 240, .32);
  white-space: nowrap;
  transition: transform .16s ease, box-shadow .16s ease, background .16s ease;
}
.me-signin .ms-ico { display: flex; }
.me-signin .ms-ico svg { width: 15px; height: 15px; }
.me-signin:active { transform: scale(.93); }
.me-signin:disabled { opacity: .6; }
/* 已签到：换成金边浅底。
   为什么不继续用蓝色实心 —— 实心蓝是「快点点我」的语气，签过之后还闪着，
   用户会以为没生效、反复点。改成「已完成的标记」才读得懂。 */
.me-signin.done {
  background: var(--gold-050);
  color: #7A5310;
  border-color: rgba(200, 161, 90, .55);
  box-shadow: none;
}

/* ---------- ② 浮层外壳 ---------- */
.sc-pop {
  position: fixed; z-index: 105; width: 274px;
  padding: 13px 13px 11px; border-radius: var(--r-md);
  background: #fff;
  border: 1px solid rgba(19, 26, 46, .08);
  box-shadow: 0 18px 44px rgba(8, 21, 44, .22), 0 2px 8px rgba(8, 21, 44, .07);
  /* 🚨 「向左下弹出」的支点 = 按钮那一角（右上角）。
     改成 center/bottom 就会变成「原地放大」或「向右下」，不是帆哥要的方向。 */
  transform-origin: top right;
  will-change: transform, opacity;
}
/* 指向按钮的小尖角。x 由 placeSigninPop() 写进 --arw（浮层左边被夹紧时会跟着偏） */
.sc-arrow {
  position: absolute; top: -5px; left: var(--arw, 34px);
  width: 10px; height: 10px; margin-left: -5px;
  background: #fff; transform: rotate(45deg);
  border-left: 1px solid rgba(19, 26, 46, .08);
  border-top: 1px solid rgba(19, 26, 46, .08);
  border-radius: 2px 0 0 0;
}

/* ---------- ③ 浮层内容 ---------- */
.sc-head { display: flex; align-items: center; gap: 6px; min-width: 0; }
.sc-head .sc-coin { display: flex; flex: none; color: var(--gold); }
.sc-head .sc-coin svg { width: 16px; height: 16px; }
.sc-ht {
  font-size: 13.5px; font-weight: 750; color: var(--ink); letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 「连签 N 天」小胶囊。帆哥没点名要，是我加的 —— 它直接解释了「为什么今天是 2 分」，
   不要的话删掉这一条 + signinPopHtml 里那个 span 即可。 */
.sc-streak {
  flex: none; margin-left: auto; padding: 1px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; white-space: nowrap;
  color: #7A5310; background: var(--gold-050);
  border: 1px solid rgba(200, 161, 90, .45);
}

.sc-cal { margin-top: 10px; }
.sc-week, .sc-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.sc-week { margin-bottom: 2px; }
.sc-week span {
  text-align: center; font-size: 10.5px; font-weight: 650; color: var(--faint);
}
.sc-grid { row-gap: 1px; }
.sc-cell {
  position: relative; height: 32px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 9px;
  font-size: 12.5px; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.sc-cell b { font-weight: 600; line-height: 1; }
.sc-cell.blank { visibility: hidden; }
/* 今天：淡蓝底圈出来。用 --brand-050 而不是写死色值 ——
   主题段重定义过这个变量（真实值是 #EFF1FF），跟着走才和全站选中态一致。 */
.sc-cell.today { background: var(--brand-050); color: var(--brand-600); }
.sc-cell.today b { font-weight: 800; }
/* 签到日的小绿点。帆哥要求「日期上面签到的日期就标注一个小绿点」——即数字下方。
   🚨 用绝对定位钉在格子底部，**不用 flex 占位**：占位会让「有圆点」和
      「没圆点」的数字一高一低，整排日期就对不齐了。 */
.sc-dot {
  position: absolute; left: 50%; bottom: 4px; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 2px rgba(31, 138, 91, .14);
}

/* 底部灰色小字：帆哥给的两句原文，一字未改 */
.sc-foot { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line); }
.sc-foot p { margin: 0; font-size: 11.5px; line-height: 1.7; color: var(--ink-3); }

/* ---------- 手机端 ---------- */
@media (max-width: 899px) {
  /* ⚠️ 手机端 .me-top 行内空间最紧（头像 77px + 姓名块 + 按钮 + 间距），
     按钮同步收一档：字号 12.5→11.5、内边距 13→10、图标 15→13。
     margin-left:-3px 吃掉一点 flex 间隙 —— 这几 px 都是还给「部门 · 职务」那行的，
     手机端 12% 成员的职务较长，按钮每省 1px 他们就少截一个字。 */
  .me-signin { height: 28px; padding: 0 10px; font-size: 11.5px; gap: 4px; margin-left: -3px; }
  .me-signin .ms-ico svg { width: 13px; height: 13px; }
  /* 浮层：390px 窄屏下 274px 仍能完整放下（夹紧逻辑见 placeSigninPop） */
  .sc-pop { width: 268px; }
  .sc-cell { height: 30px; font-size: 12px; }
}
@media (max-width: 380px) {
  .me-signin { height: 26px; padding: 0 9px; font-size: 11px; }
  .sc-pop { width: 258px; }
  .sc-cell { height: 28px; }
}
