@charset "UTF-8";
/* ============================================================================
   theme.css —— 全站配色唯一权威层（override layer）
   ----------------------------------------------------------------------------
   加载位置：templates/base.html 中 `{% block page_css %}` **之后**。
   因此本文件的 `:root` 与同特异性选择器都晚于页面样式生效，可覆盖全站。

   唯一标准：static/css/pages/index.css 的 :root
            （= cankao/index.html 原版 :root，27 个 token，逐字一致）

   设计原则：
     1. 原版 7 个 CSS 文件（industry / guanwang / pages/*）**保持逐字节不变**，
        差异全部收敛到本文件 —— 便于审计与回滚。
     2. `:root` 只覆盖「颜色类」token。布局类 token（--maxw / --radius* 等）
        不做改动，避免把配色统一扩大成改版。
     3. 页面里用字面色值（硬编码）写的**跨页共享组件**（顶栏/页脚/底栏/横幅/
        弹层/闸门）无法被 token 覆盖，在本文件底部逐条纠正为 index 的取值。
     4. 语义色（涨跌红绿）显式保留，见「第 4 节」。

   维护者注意：新增页面若自带 :root，不需要改；本文件会覆盖它。
   若某个 token 需回退到页面原值，把对应行注释掉即可，不必动原版 CSS。
   ============================================================================ */

/* ============================================================================
   第 1 节 · 权威配色 token
   取值来源：static/css/pages/index.css :root（逐字复制，勿手改）
   ============================================================================ */
:root {
  /* —— 背景层级：画布 / 卡片 / 浮起 / 内凹 / 侧栏 —— */
  --bg: #100F0E;
  --card: #161513;
  --tint: #1E1C18;
  --soft: #1E1C18;
  --bg-card: #161513;
  --bg-soft: #121110;
  --bg-side: #1A1816;

  /* —— 描边 / 分隔线（米白半透明三档）—— */
  --line: rgba(252,251,248,.10);
  --line-2: rgba(252,251,248,.20);
  --line-strong: rgba(252,251,248,.28);

  /* —— 印章红（主强调色）—— */
  --red: #D9503A;
  --red-d: #C2442C;
  --red-soft: rgba(217,80,58,.16);
  --seal: #D9503A;
  --seal-2: #E8705A;

  /* —— 金铜（辅助强调色）—— */
  --gold: #C97B2A;
  --gold-soft: #E0C083;

  /* —— 文字四档 —— */
  --ink: #FCFBF8;
  --ink-2: rgba(252,251,248,.74);
  --ink-3: rgba(252,251,248,.55);
  --ink-4: rgba(252,251,248,.38);

  /* —— 等宽字体与顶栏高度（各页取值本已一致，此处硬化）—— */
  --mono: ui-monospace,SFMono-Regular,Menlo,Consolas,"Courier New",monospace;
  --topbar-h: 56px;
  --app-nav-h: 0px;
}

/* ⚠ 有意不覆盖的 token：
     --maxw —— index 为 1180px，radar/trend/rank/pay 为 1240px。
               这是**版心宽度**（布局量），不是配色，统一它会改变 4 个
               内容密集型页面的排版宽度。任务边界是「配色」，故保留差异。
   如需一并统一，取消下面一行的注释即可（会收窄 4 个页面 60px）：
*/
/* :root { --maxw: 1180px; } */

/* ============================================================================
   第 2 节 · 设计系统其余 token（字体族 / 圆角 / 深色阴影）
   ----------------------------------------------------------------------------
   --radius* 与 --serif/--sans 仅由 industry.css 定义且无页面覆写，取值统一。
   --shadow-sm/md/lg 是 industry.css 的**浅色**阴影（rgba(20,19,17,·)），
   在深色画布上等于不存在。这里别名到 index 的深色阴影 --sh-sm / --sh-md。
   ============================================================================ */
:root {
  --serif: "Source Han Serif SC", "Noto Serif SC", "Songti SC", "STSong", serif;
  --sans: "PingFang SC", "Hiragino Sans GB", "Microsoft Yahei", sans-serif;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;

  --shadow-sm: var(--sh-sm);
  --shadow-md: var(--sh-md);
  --shadow-lg: var(--sh-md);
}

/* 深色阴影两档（index 取值）——上面 --shadow-* 的别名目标 */
:root {
  --sh-sm: 0 1px 2px rgba(0,0,0,.35);
  --sh-md: 0 6px 18px rgba(0,0,0,.45),0 18px 48px rgba(0,0,0,.4);
}

/* ============================================================================
   第 3 节 · 遗留 token 别名
   ----------------------------------------------------------------------------
   历史上一批页面各自起了前缀（--tr- / --club- / --deep …）。它们指向的
   仍然是「背景 / 卡片 / 文字 / 描边」这几类角色，只是换了名字。
   把这些名字统一指到第 1 节的权威 token，页面里已有的 var() 引用就自动统一，
   不必逐条改页面 CSS。

   --tr-* 中性族：trend / rank / radar / pay（行情终端口径）
   ============================================================================ */
:root {
  --tr-bg: var(--bg);              /* 画布 */
  --tr-panel: var(--card);         /* 面板 / 卡片 */
  --tr-panel-2: var(--bg-soft);    /* 面板内凹层 */
  --tr-bg-3: var(--tint);          /* 面板浮起层 */
  --tr-line: var(--line);
  --tr-line-2: var(--line-2);
  --tr-txt: var(--ink);
  --tr-txt-2: var(--ink-2);
  --tr-txt-3: var(--ink-4);
  --tr-gold: var(--gold-soft);
}

/* 其余遗留中性名 —— 一律指向权威 token */
:root {
  --deep: var(--bg);               /* talent-detail：页脚更深一档 */
  --bg-deep: var(--bg);            /* industry：浅色页上的深色按钮底 */
  --code-bg: var(--bg-soft);
  --club-bg: var(--tint);
  --club-text: var(--ink);
  --club-card: var(--card);
  --club-card-2: var(--bg-side);
  --ink-soft: var(--ink-3);
  --ink-subtle: var(--ink-4);
  --industry-ink: var(--ink);
  --paper: var(--tint);            /* guanwang 卡片底 → 与 --tint 同值 */

  /* 印章红系列的历史别名 */
  --cinnabar: var(--gold-soft);
  --cinnabar-2: var(--gold);
  --td-red: var(--red);
  --broker: var(--red);
  --broker-deep: var(--red-d);
  --broker-soft: var(--red-soft);
  --broker-line: rgba(217,80,58,.34);
}

/* ⚠ 一处「补定义」而非「改色」—— 但必须做：
   `--hairline` 被 guanwang.css（60+ 处）与 index/talent-detail 的
   `.industry-strip` 引用，可**全站只有 talent-detail.css 定义过它**
   （值 rgba(252,251,248,.10)，恰好等于 --line）。
   后果：横幅 `.industry-strip` 的下边框在 talent-detail 上有、在其余 6 页
   因 var() 计算期失效而**没有** —— 这是本次发现的真实跨页渲染差异。
   这里把它补成 --line，使「有/无这条 hairline」在全部页面一致（都有），
   同时也让 guanwang.css 那 60+ 条边框声明恢复生效（仅 talent-detail
   与未迁移页会渲染到这些类，该页原值本就相同，因此视觉无变化）。 */
:root {
  --hairline: var(--line);
}

/* ============================================================================
   第 4 节 · 语义色保留区（**禁止按主题色改动**）
   ----------------------------------------------------------------------------
   行情口径：涨 = 红、跌 = 绿（国内市场惯例，勿改成欧美配色）。
   这几个 token 表达的是**数据方向**，不是品牌色，因此不参与「向 index 统一」。
   trend / rank / radar / pay 四页的 :root 里本来就有同名定义，取值一致，
   这里显式重申一遍，避免日后被误合并进主题色。
   ============================================================================ */
:root {
  --tr-up: #F04E3E;                /* 涨 / 信号增强 */
  --tr-up-soft: rgba(240,78,62,.14);
  --tr-down: #17B978;              /* 跌 / 信号减弱 */
  --tr-down-soft: rgba(23,185,120,.14);
  --tr-flat: #8B94A0;              /* 持平 */

  --tr-gold-soft: rgba(224,192,131,.14);  /* 金色「中性提示」底，与品牌金同源 */
}

/* ⚠ 同样有意保留、未纳入统一的语义/类目色（index 中无对应角色）：
     --success #5BD49A · --warning #E7C68C     状态语义（talent-detail）
     --industry / --industry-soft / --industry-line  产业端蓝色类目色
     --olive / --olive-soft / --lv-s/-a/-b     绿色与等级渐变（未迁移页用）
   它们不是「站点主题色」，属于内容语义，改它们会丢失信息。
*/

/* ============================================================================
   第 5 节 · 跨页共享组件：字面色值纠正
   ----------------------------------------------------------------------------
   下面这些规则在原版里是用**硬编码色值**写在每个页面的 CSS 中的，
   token 覆盖不到。取值一律取「index 在真实加载顺序下的有效值」，
   即 index 现在渲染出来的样子 —— 也就是本次统一的唯一标准。

   纳入范围：在 ≥2 个页面渲染的共享组件。
   未纳入：仅单页出现的类（如 index 的 .zo-car-*、talent-detail 的 .bk-side-*）
          以及未在模板中引用的类（.btn-gold / .badge-* / .status-* 等）。
   ============================================================================ */

/* —— 顶栏 —— */
.topbar {
  background: rgba(16,15,14,.84);
  border-bottom: 1px solid var(--line);
  border-bottom-color: var(--line);
}

/* 顶栏右栏导航项 */
.bar-link { color: var(--ink-2); }
.bar-link:hover { background: rgba(252,251,248,.08); color: var(--ink); }
/* hover 文字/图标色：原版被 industry.css 的全局 `a:hover{color:var(--seal)}`
   （#9A2415 印章红）接管——各页 .dvn-i:hover 只补了 background 没管 color。
   现统一改为主题金 --gold-soft，与移动端 .app-tab-i.on 同源；
   .dvn-i 是 <a>，图标 svg 走 stroke="currentColor"，会随文字一起变金。
   特异性 (0,2,0) 稳压全局 a:hover (0,1,1)，且本文件全站最后加载，
   全部页面一处生效，pages/*.css 一行不动。 */
.dvn-i:hover { background: rgba(255,255,255,.07); color: var(--gold-soft); }
.dvn-i.on::before { background: rgba(255,255,255,.45); }
/* 品牌名悬浮色：与 .dvn-i 同一事故——`.brand` 是 <a>，industry.css 全局
   `a:hover{color:var(--seal)}` 把「ORecord」悬浮染成印章红（.brand-name
   自身无 color，整条继承链只有这一个声明在管它；.brand-slogan 有显式
   --ink-3，所以只有品牌名变红）。现统一为主题金，与导航项同源。
   特异性 (0,3,0) 稳压全局 a:hover (0,1,1)，theme.css 全站最后加载，
   全部页面一处生效，pages/*.css 一行不动。
   ⚠ 只做 PC 端（≥901px，与顶栏/移动底栏分界同值）：触屏端 :hover 由点击
   残留触发，属误触语义，不在本次需求内。 */
@media (min-width:901px) {
  .brand:hover .brand-name { color: var(--gold-soft); }
}

/* —— 横幅（industry-strip）——
   `.industry-strip` 的下边框写法 `1px solid var(--hairline)` 原样保留；
   `--hairline` 已在第 3 节补成 var(--line)，故这条边框现在在全部页面
   都生效、且颜色一致。 */
.industry-strip {
  background: linear-gradient(90deg,rgba(252,251,248,.03) 0%,rgba(252,251,248,.06) 50%,rgba(252,251,248,.03) 100%);
  color: var(--ink-2);
  border-bottom: 1px solid var(--hairline);
  border-bottom-color: var(--line);
}
.industry-strip a { color: var(--red); }
.industry-strip .right { color: var(--ink-3); }
.industry-strip .lock {
  background: transparent;
  border: 1px solid var(--hairline);
  color: var(--gold-soft);
  border-color: rgba(224,192,131,.4);
  width: fit-content;
  white-space: nowrap;
}
.industry-strip .broker-tag { background: rgba(224,192,131,.1); }

/* —— 页脚 ——
   同时给出 border-top 简写与 border-top-color 长写：原版各页写法不一
   （有的只写简写、有的只写长写），两种都声明才能保证计算值一致。 */
.site-foot {
  border-top: 1px solid var(--line);
  border-top-color: var(--line);
  background: #0E0D0C;
}
.site-foot-links a:hover { color: var(--red); }

/* —— 底部四栏固定导航（仅 ≤900px 显示）——
   ⚠ 四份定义原本不一致：index 用 --ink-2/--gold-soft，radar/trend/rank
      用 --tr-txt-2/--tr-gold。现统一为 index 口径（--tr-* 已在第 3 节
      指向同一批 token，两层一致，后续不再分叉）。
   完整规则（含定位、栅格、PC 退场）见第 6 节，此处不重复声明。 */

/* —— 咨询弹层（im_modal）——
   每个「边线」都同时给简写与长写：原版各页有的写 `border`、有的写
   `border-color`，只声明一种会让计算值在其他页面上对不齐。 */
.im-mask { background: rgba(8,7,6,.66); }
.im-box {
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-color: var(--line);
}
.im-body { background: var(--bg-soft); }
.im-head {
  border-bottom: 1px solid var(--line);
  border-color: var(--line);
}
.im-foot {
  border-top: 1px solid var(--line);
  border-color: var(--line);
}
.im-foot input {
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink);
  border-color: var(--line-2);
}
.im-msg .ava { background: var(--bg-soft); color: var(--seal); }
.im-msg .bbl {
  background: var(--tint);
  border: 1px solid var(--line);
  border-color: var(--line);
  color: var(--ink);
}
.im-msg.me .ava { background: var(--seal); color: #fff; }
.im-msg.me .bbl {
  background: var(--seal);
  color: #fff;
  border-color: var(--seal);
}
.im-warn {
  background: rgba(217,80,58,.13);
  border: 1px solid #f3cdd5;
  color: #F3A48E;
  border-color: rgba(217,80,58,.35);
}

/* —— NDA 弹层（nda_modal）—— */
.nda-mask { background: rgba(8,7,6,.66); }
.nda-box {
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-color: var(--line);
}
.nda-box .body { background: var(--bg-soft); color: var(--ink-2); }

/* —— 弹层主按钮 —— */
.btn-primary {
  background: var(--seal);
  color: #fff;
  border-color: var(--seal);
}

/* —— 管家码闸门（gate）——
   全站都会加载，各页原本各写一套，取值不同（index 暖黑 / 行情页冷黑）。 */
html.zo-locked .zo-gate { background: rgba(8,7,6,.75); }
.zo-gate-panel {
  background: linear-gradient(180deg,#1B1917 0%,#141312 100%);
  border: 1px solid rgba(252,251,248,.14);
  box-shadow: 0 30px 80px rgba(0,0,0,.62),0 0 0 1px rgba(224,192,131,.05);
}
.zo-gate-ic {
  background: rgba(201,123,42,.14);
  border: 1px solid rgba(224,192,131,.36);
  color: var(--gold-soft);
}
.zo-gate-form input:focus {
  border-color: rgba(224,192,131,.6);
  box-shadow: 0 0 0 4px rgba(224,192,131,.1);
}
.zo-gate-form button {
  border: 0;
  color: #16130E;
  background: linear-gradient(135deg,var(--gold-soft),var(--gold));
  box-shadow: 0 8px 22px rgba(201,123,42,.3);
}
.zo-gate-form button:hover { box-shadow: 0 12px 28px rgba(201,123,42,.42); }
.zo-gate-err { color: #E5836F; }
.zo-gate-note a { color: var(--gold-soft); border-bottom: 1px solid rgba(224,192,131,.42); }

/* ============================================================================
   第 6 节 · 补上底部四栏导航的**结构**（新增页需要）
   ----------------------------------------------------------------------------
   背景：`.app-tab` 的规则原先只写在 index / radar / trend / rank 四个页面的
   CSS 里，而 base.html 是按 `nav_enabled` 无条件渲染这段 DOM 的。
   于是 404 / 服务错误 / 未迁移三张新增页（没有自己的页面 CSS）会渲染出
   「有 DOM、没样式」的一排裸链接 —— 之前只能靠模板里 `{% block app_tab %}`
   置空来回避，代价是这三页成为全站唯一没有底部导航的页面。

   这里把结构补齐（取值与 index.css 逐字一致，故对已有四页零影响），
   新增页就能按站内一致的方式拿到底栏：≤900px 固定展示、PC 上退场，
   并同步处理 .app-tab-pad 的占位高度（「耦合三件套」：栏体 / 占位 / toast）。
   ============================================================================ */
.app-tab {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  background: rgba(16,15,14,.92);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  box-shadow: 0 -10px 26px rgba(0,0,0,.42), inset 0 1px 0 var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.app-tab-in {
  max-width: var(--maxw); margin: 0 auto; height: 56px;
  display: grid; grid-template-columns: repeat(4,1fr);
}
.app-tab-i {
  position: relative; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  text-decoration: none; color: var(--ink-4);
  font-size: 10.5px; line-height: 1; letter-spacing: .02em; transition: color .18s;
}
.app-tab-i svg { width: 21px; height: 21px; display: block; }
.app-tab-i:hover { color: var(--ink-2); }
.app-tab-i.on { color: var(--gold-soft); }
.app-tab-i.on::before {
  content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 28px; height: 2px; border-radius: 0 0 2px 2px;
  background: linear-gradient(90deg, var(--gold), var(--gold-soft));
}
/* 固定栏会盖住页脚末行 → 在页脚之后放一个等高占位块（静态 HTML，替换不到它） */
.app-tab-pad { height: calc(56px + env(safe-area-inset-bottom)); }

@media (min-width: 901px) {
  /* PC 形态：顶栏（.dvn-rail）承载导航，底栏退场；
     ⚠ 占位高度必须一起归零，否则页脚上方会留一条 56px 空档。 */
  .app-tab { display: none; }
  .app-tab-pad { height: 0; }
}

/* ============================================================================
   第 7 节 · 顶栏用户胶囊下拉（退出登录）
   ----------------------------------------------------------------------------
   结构见 templates/partials/topbar.html：`.user-menu-wrap` 是 `.dvn-acts` 的一个
   flex item，内部放 `.user-chip`（按钮）与 `.user-menu`（绝对定位面板）。
   之所以要包这一层：面板必须以**胶囊**为定位基准，而面板不能放进 button 里面
   （button 内不允许再嵌交互元素，「退出登录」会点不动）。

   本节只做两件事：把胶囊「从 <span> 变成 <button> 后必须补的属性」补上，
   以及给出面板的样式。**胶囊原有的配色一律不动** —— 它仍由 industry.css
   与各页 pages/*.css 决定（含 talent-detail 那条 `display:none !important`）。

   三个具体的坑：
     1. UA 给 <button> 的 `color` 是 `buttontext` —— 页面没声明 color-scheme，
        深色底上就是一行黑字。必须显式 `color: inherit`。
     2. `.user-chip` 只补 `position: relative` 供面板定位，**这里不碰 display** ——
        恢复学者详情页的胶囊另有一条**带作用域**的规则（见本节末「4.」），
        两条刻意不合并：无作用域的 `display:inline-flex` 会顶掉 talent-detail 的
        `display:none !important`，并顺带作用到全站每一页（今天看不出差别，
        因为只有这一页会隐藏胶囊 —— 属于本文件最忌讳的「静默生效」）。
     3. 面板收起时用 `pointer-events: none` 而不是只降 opacity ——
        否则那层看不见的面板仍会吃掉胶囊下方的点击。
   ============================================================================ */
.user-menu-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
/* ⚠ `hidden` 属性必须显式接管：UA 的 `[hidden]{display:none}` 与上面这条
   `.user-menu-wrap{display:inline-flex}` 特异性相同（都是 0,1,0），作者样式胜出
   —— 不写这一行，JS 里 `wrap.hidden = true` 会静默无效（外壳照样占位、
   照样吃那一次 gap）。 */
.user-menu-wrap[hidden] { display: none; }

/* —— 胶囊：只补「换成按钮后必须补的」+ caret —— */
button.user-chip {
  position: relative;
  color: inherit;                 /* 坑 1：UA 的 buttontext 在深色底上是黑字 */
  text-align: left;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: border-color .18s, background .18s;
}
button.user-chip:hover { border-color: var(--line-strong); }
button.user-chip:focus-visible {
  outline: none;
  border-color: var(--gold-soft);
  box-shadow: 0 0 0 3px rgba(224,192,131,.18);
}
/* caret：靠 ::after 充当第三个 flex item（自动带上 .user-chip 的 gap 6px），
   不额外加 DOM 节点，也就不动任何既有选择器 */
button.user-chip::after {
  content: "";
  width: 0; height: 0;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  opacity: .55;
  transition: transform .18s, opacity .18s;
}
button.user-chip[aria-expanded="true"]::after {
  transform: rotate(180deg);
  opacity: .9;
}

/* —— 下拉面板 ——
   right:0 对齐胶囊右沿：胶囊右沿距视口右边就是顶栏内边距（12~24px），
   面板 196px 向左展开，320px 宽的手机上也放得下，不需要做溢出夹紧。 */
.user-menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 60;
  min-width: 196px;
  display: flex;
  flex-direction: column;
  padding: 8px;
  border-radius: 14px;
  border: 1px solid var(--line-2);
  background: var(--bg-side);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;           /* 坑 3 */
  transition: opacity .16s ease, transform .16s ease;
}
.user-menu.on {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.user-menu-hd {
  margin: 2px 6px 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink-2);
  border-bottom: 1px solid var(--line);
  padding-bottom: 7px;
}
.user-menu-sub {
  margin: 0 6px 6px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink-4);
}

/* —— VIP 行（管家码核验后**替换** job_title 那一行，两者互斥）——
   徽标的配色规则是「`.vip-badge` 给中性底，两档等级只调前景与底色」：
   这样运营在库里写了未登记的等级时，徽标仍是个有底色的空壳，而不是
   「看着什么都没有」—— 至少能看出这一行有内容，再去查为什么文案不对。

   金铜色取自第 1 节的 --gold / --gold-soft，与原版
   `.user-chip.role-signed` 的「尊贵身份」用色同源，不是新引入的颜色。 */
.user-menu-vip {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 6px 6px;
  line-height: 1.4;
}
.vip-badge {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: rgba(252,251,248,.06);
  color: var(--ink-2);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
}
/* 尊享：金铜（本文件第 1 节的 --gold-soft） */
.vip-badge.vip-premium {
  border-color: rgba(224,192,131,.42);
  background: rgba(201,123,42,.18);
  color: var(--gold-soft);
}
/* 试用：中性偏弱，与尊享刻意拉开档次差（不是配色差异，是层级差异） */
.vip-badge.vip-trial {
  border-color: var(--line);
  background: rgba(252,251,248,.05);
  color: var(--ink-3);
}
/* 到期时间与徽标同一行：nowrap 保证「2027-06-30」不会在中间断开 */
.vip-exp {
  font-size: 11px;
  color: var(--ink-4);
  white-space: nowrap;
}

/* VIP 持卡态下的胶囊：沿用原版 `.user-chip.role-signed` 的既有表达
   （industry.css 与 7 个 pages/*.css 都写了这条规则，是本项目现成的
   「尊贵身份」语言），但更克制 —— 只调边框与头像，不动胶囊底色。
   ⚠ 与 role-signed 同时命中时（签约科学家又核验了 VIP 卡）两者特异性同为
   0,2,0 / 0,2,1，靠 theme.css 最后加载取胜，结果可预期。 */
.user-chip.role-vip { border-color: rgba(224,192,131,.45); }
.user-chip.role-vip .avatar { background: linear-gradient(135deg, var(--gold-soft), var(--gold)); }

/* 退出登录：≥40px 触控高度，键盘可达（原生 button） */
.user-menu-i {
  display: block;
  width: 100%;
  min-height: 40px;
  margin-top: 6px;
  padding: 10px 10px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--ink-2);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: background .16s, color .16s;
}
.user-menu-i:hover { background: rgba(252,251,248,.06); color: var(--ink); }
.user-menu-i:focus-visible {
  outline: none;
  background: rgba(252,251,248,.06);
  color: var(--ink);
  box-shadow: 0 0 0 3px rgba(224,192,131,.18);
}
.user-menu-i[disabled] { opacity: .5; cursor: default; }

/* —— 窄屏：顶栏要同时塞下「品牌 + 发布需求 + 附加导航 + 胶囊」，空间很紧。
   胶囊收起姓名、只留头像与 caret（实测省下约 37px）——
   收之前 375px 上「发布需求 / 经纪人后台」会被挤成两行，胶囊里的姓名也跟着竖排，
   把胶囊从 32px 撑到 42px 高（`.user-chip` 是 flex 容器，裸文本会换行）。
   头像本身就是身份标识（李 / 陈 / 张），caret 继续提示「可点开看完整身份」，
   完整身份仍在 title 属性与下拉抬头里，信息没有丢。
   断点取 600px，与 industry.css 里顶栏转入紧凑形态的那一档对齐。 */
@media (max-width: 600px) {
  .user-chip-t { }
  /* 姓名收起后，右侧那 10px 内边距也一并收掉，胶囊紧贴头像尺寸 */
  button.user-chip { padding: 4px; }
}

/* 超窄屏：面板与字号各收一档（320px 下仍不溢出、不换行） */
@media (max-width: 400px) {
  .user-menu { min-width: 172px; padding: 7px; }
  .user-menu-i { font-size: 12.5px; }
}

/* —— 4. 学者详情页（/talent/{id}）恢复顶栏胶囊 ——
   产品决策：原版 industry-talent-detail.html 刻意把胶囊整块拿掉
   （页面 CSS 里 `.user-chip{display:none !important}`，且 html 上挂了
   data-user-chip="removed" 当回归钩子），本站在该页把登录头像模块补回来。

   ⚠ 原版 CSS 一字不改是硬基线（theme_consistency.py A 组 sha256），
     所以恢复动作只能落在 theme.css —— 靠「同为 !important + 更高特异性」
     取胜，不依赖加载顺序（theme.css 本就最后一张样式表，双保险）。

     特异性 (0,3,1) > `html[data-user-chip="removed"] .user-chip` 的 (0,2,1)，
     也 > `.user-chip` 的 (0,1,0)。!important 是**必须**的：同源下
     带 !important 的声明一律压过不带 !important 的，单堆特异性没用。

   ⚠ 作用域 `body.talent-detail` 不能省。省掉就是一条全局规则，今天全站
     只有这一页隐藏胶囊、看起来「也对」，但只要以后再有页面沿用同样手法
     隐藏它，就会被这条规则静默顶掉 —— 无报错、无 404，正是本项目最忌的
     那类失败。作用域挂钩来自 templates/talent_detail.html 的 body_class 块。

   ⚠ 只恢复 display，不重写配色：暗底描边等仍由 talent-detail.css
     （`.topbar` / `.bar-link` 那几条）与本文件第 1 节的 token 决定。

   ⚠ 胶囊重新可见后，orecord-common.js 的 bindUserMenu() 不再走
     「`!chip.getClientRects().length` → `wrap.hidden = true`」那条分支
     （那是为「0 宽外壳白吃一次 .dvn-acts 的 gap、把发布需求挤偏 4px」写的）。
     逻辑无需改动：判据是布局结果，CSS 一变它自己就换分支。 */
body.talent-detail .topbar .user-chip { display: inline-flex !important; }

/* ============================================================================
   第 8 节 · 顶栏主导航（aria-label="主导航" 的 PC 形态 .dvn-rail）轴线居中
   ----------------------------------------------------------------------------
   背景：第 97 轮把导航列改成「靠 auto 左边距吃富余 → 操作区钉最右」，
   于是导航列停在操作区左边、**不在顶栏轴线上**。真机实测（1440×900，
   _recon/nav_center_measure.mjs）：index 偏 +57.4px、trend/rank/radar 偏
   +87.4px；而 1024 / 901 富余被吃光后反而"碰巧"贴近轴线
   （−17.6px / +5.9px）—— 同一站内、换个窗口宽度就忽中忽偏。

   本节把它统一成**轴线居中**（导航列中心 == 顶栏内容盒中心），
   并把结论建立在一条算得清的预算上：

     品牌 238.6 + 导航 426.2 + 操作区 263.5 + 两侧各留 16px = 960.3px
     内容盒 = 视口 − 15(滚动条) − 48(顶栏左右内边距) = 视口 − 63
     ⇒ 三栏并排、且导航列居中，至少需要视口 1024px。

   所以分两段，而不是一条规则打天下（实测数据与上面这条预算逐项吻合）：

     ① 901–1079 —— **预算不够**。回到「左右 auto 外边距」的老形态：
        导航列居中于**品牌与操作区之间的空档**。因两侧槽宽不等
        （238.6 vs 263.5），中心会落在轴线左侧恒定 12.45px ——
        一个不随窗口宽度漂移的小偏差。
        这一区间**绝不能**用绝对定位：实测 1000px 下压住操作区 8px、
        901px 下压住品牌 33px 且压住操作区 57px（浏览器不报错，
        页面只是"看着有导航"，正是本项目最容易被静默放过的类型）。

     ② ≥1080 —— **预算富余 ≥32px**，才用绝对定位做**真轴线居中**。
        它把导航列移出文档流，两个邻居的宽度就与它无关：
        实测 Δ=0.00px，且不会把品牌/操作区挤变形。
        为什么不改用「左右两栏等权 flex」：`.brand` / `.dvn-acts`
        的 flex 基数都是 auto（缩不下去），`flex:1 1 0` 只能让
        **富余**均分，结果仍是「轴线 + (品牌宽 − 操作宽)/2」= 偏 12.45px；
        要彻底相等就得 `min-width:0` 硬压，而 901px 下品牌只剩
        232px、窄于它 238.6px 的自然宽，标语会被挤成两行。

   ⚠ 四个必须写死的点：
     ① `.bar-spacer-w`（让位件）在 ≥901 必须退场。它在 PC 上是 0 宽 +
        `flex:0 0 auto`，本身不吃富余，却会**多贡献一个 16px 的 gap**，
        把导航列中心额外推离轴线 8px。它唯一的用途是 601–900 那段
        把操作区顶回右沿，与本区间无关。
     ② 绝对定位时 `position: relative` 挂在 `.topbar-in` 上：它是导航列
        唯一的定位祖先。不写的话百分比会落回 `.topbar`（sticky，
        已是包含块），基准从内容盒变成整条顶栏，内边距不对称时就会偏。
     ③ 绝对定位时 `top:50%` + `translate(-50%,-50%)`，而不是只写
        `left:50%`：只给 left 时纵向位置走「静态位置」——那是 flex
        容器对绝对定位子项的隐式对齐，各内核实现细节不同，别赌。
     ④ 绝对定位时导航列移出流，富余空间没人吃，操作区会紧贴品牌。
        必须由 `.dvn-acts` 自己吃（`margin-left:auto`）—— 此时全行
        只剩这一个 auto，不存在历史注释里那个「auto 对 auto 平分富余」
        把导航列拽走的问题。
   ============================================================================ */
@media (min-width: 901px) {
  /* 让位件退场：PC 上它只剩一个多余的 gap（见上面 ⚠①） */
  .topbar-in > .bar-spacer-w { display: none; }

  /* 覆盖 pages/*.css 的 `margin-left:auto; margin-right:0`（第 97 轮那条），
     恢复两侧等权 —— 特异性 (0,2,0) > (0,1,0)，不依赖加载顺序；
     theme.css 本身又最后加载，两条保险都在。 */
  .topbar-in > .dvn-rail {
    margin-left: auto;
    margin-right: auto;
  }
}

@media (min-width: 1080px) {
  .topbar-in { position: relative; }

  .topbar-in > .dvn-rail {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    margin-left: 0;
    margin-right: 0;
  }

  /* 操作区改为自己贴右（原来靠导航列的 auto 左边距把它顶过去） */
  .topbar-in > .dvn-acts {
    margin-left: auto;
    margin-right: 0;
  }
}

/* ============================================================================
   第 9 节 · 行业趋势页：领域切换标签条 + 行情带去交互化
   ----------------------------------------------------------------------------
   2026-09-22 liam 拍板：行情带（跑马灯）改**纯展示**，切换数据的入口移到
   tr-body 上方的领域标签条（templates/partials/trend_fields.html）。
   pages/trend.css 是 A 组 sha256 钉死基线，一行不改；本节做两件事：

     ① 新增 .tr-fields / .tr-field-tab 的椭圆标签样式（页面 CSS 里没有这两类）；
     ② 撤掉 .tr-tape-i 的「可点击视觉语言」——trend.css 里它写着
        cursor:pointer + hover 变金，现在节点已是 <span> 且无监听，
        这两条留着就是在骗用户点。用 --maxw 同源的取值习惯覆盖为 default 光标、
        hover 不再变色。**悬浮暂停滚动**不在此列：那条
        `.tr-tape:hover .tr-tape-track{animation-play-state:paused}`
        是 trend.css 既有规则，正是需求要的，保留原样。
   ============================================================================ */

/* —— ① 领域标签条：椭圆边框，点击切换 ——
   排布：一行放不下就换行（9 个领域名长短不一，不做横向滚动——
   滚动条会把「点哪个」变成「先找哪个」）。 */
.tr-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 14px 0 0;
}
.tr-field-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border-radius: 999px;                 /* 椭圆（胶囊）边框 */
  border: 1px solid var(--tr-line-2);
  background: transparent;
  color: var(--tr-txt-2);
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.5;
  white-space: nowrap;
  cursor: pointer;
  transition: color .16s, border-color .16s, background .16s;
}
.tr-field-tab i {
  width: 7px; height: 7px; border-radius: 50%;
  display: inline-block; flex: 0 0 7px;  /* 领域色点，与 hero 标签同源色 */
}
.tr-field-tab:hover {
  color: var(--tr-txt);
  border-color: var(--tr-gold);
}
.tr-field-tab:focus-visible {
  outline: none;
  border-color: var(--gold-soft);
  box-shadow: 0 0 0 3px rgba(224,192,131,.18);
}
.tr-field-tab.on {
  color: var(--gold-soft);
  border-color: var(--gold-soft);
  background: var(--tr-gold-soft);
  font-weight: 600;
}
/* 窄屏收紧一档，避免 9 个标签挤成三四行 */
@media (max-width: 620px) {
  .tr-fields { gap: 6px; padding-top: 10px; }
  .tr-field-tab { padding: 4px 10px; font-size: 11.5px; }
}

/* —— ② 行情带去交互化 ——
   特异性与 trend.css 原规则同为 (0,1,0)/(0,2,0)，theme.css 最后加载取胜；
   节点已是 <span>，此处只清理视觉暗示。 */
.tr-tape-i { cursor: default; }
.tr-tape-i:hover .nm { color: var(--tr-txt-2); }

/* ============================================================================
   第 10 节 · 榜单页概况区：4 格纯数字 → 「资金全景」卡（donut + 图例 + 成交动态）
   ----------------------------------------------------------------------------
   2026-09-22 liam 拍板：热点榜单页头原 4 格 KPI（上榜企业数/榜首/覆盖领域/已认证）
   对企业主没有吸引力，整块换成资金全景 —— 领域成交金额 donut、图例、
   金融统计四格、最新成交动态。
   pages/rank.css 是 A 组 sha256 钉死基线，一行不改；本节：
     ① 新增 .rk-cap 系列的版式（卡体、donut、图例、成交动态）；
     ② 在 .rk-cap-side 作用域内把 .rk-kpis 从 4 列覆成 2×2 ——
        选择器 .rk-cap-side .rk-kpis 特异性 (0,2,0) > 原 (0,1,0)，且 theme.css
        最后加载，双保险；≤400px 的 1 列覆写同理（.rk-cap-side .rk-kpis）。
   donut 是 SVG circle + pathLength=100，dash 值即百分点，纯静态无 JS。
   ============================================================================ */

/* —— ① 卡体骨架：左图右数据，窄屏回落上下 —— */
.rk-cap {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(300px, 1fr);
  gap: 12px;
  margin-top: 18px;
}
.rk-cap-card,
.rk-deals {
  background: var(--tr-panel);
  border: 1px solid var(--tr-line);
  border-radius: 12px;
  min-width: 0;
}
.rk-cap-h {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--tr-line);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--tr-txt);
  flex-wrap: wrap;
}
.rk-cap-h .d { width: 6px; height: 6px; border-radius: 50%; background: var(--tr-up); flex: 0 0 6px; }
.rk-cap-h em {
  font-style: normal;
  font-weight: 400;
  font-size: 11px;
  color: var(--tr-txt-3);
  margin-left: auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* —— donut 图 + 图例 —— */
.rk-cap-body { display: grid; grid-template-columns: 158px minmax(0, 1fr); gap: 16px; padding: 14px 14px 13px; align-items: center; }
.rk-donut-fig { position: relative; width: 158px; height: 158px; }
.rk-donut { width: 100%; height: 100%; display: block; }
.rk-donut circle { fill: none; stroke-width: 5.6; }
.rk-donut circle.trk { stroke: rgba(255, 255, 255, 0.055); }
.rk-donut-c {
  position: absolute; inset: 0;
  display: grid; place-content: center; text-align: center; gap: 3px;
  pointer-events: none;
}
.rk-donut-c b {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 19px; font-weight: 700;
  color: var(--tr-gold);
  letter-spacing: -0.02em;
}
.rk-donut-c s { text-decoration: none; font-size: 10.5px; color: var(--tr-txt-3); }

.rk-donut-legend { min-width: 0; display: grid; gap: 2px; }
.rk-lg-hd, .rk-lg-row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) 76px 46px;
  gap: 8px;
  align-items: center;
}
.rk-lg-hd { font-size: 10.5px; color: var(--tr-txt-3); padding: 0 3px 4px; border-bottom: 1px solid var(--tr-line); margin-bottom: 2px; }
.rk-lg-hd span:nth-child(3), .rk-lg-hd span:nth-child(4),
.rk-lg-row .amt, .rk-lg-row .pc { text-align: right; }
.rk-lg-row { padding: 3px 3px; border-radius: 6px; font-size: 11.5px; color: var(--tr-txt-2); transition: background 0.14s; }
.rk-lg-row:hover { background: rgba(255, 255, 255, 0.045); }
.rk-lg-row i { width: 8px; height: 8px; border-radius: 2px; }
.rk-lg-row .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rk-lg-row .amt { color: var(--tr-txt); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.rk-lg-row .pc { color: var(--tr-gold); font-size: 11px; font-variant-numeric: tabular-nums; }
.rk-lg-empty { font-size: 11.5px; line-height: 1.8; color: var(--tr-txt-3); padding: 6px 3px; }
.rk-lg-empty b { color: var(--tr-txt); }
.rk-lg-ft { font-size: 10.5px; color: var(--tr-txt-3); padding: 5px 3px 0; border-top: 1px dashed rgba(255, 255, 255, 0.07); margin-top: 3px; }
.rk-lg-ft b { color: var(--tr-gold); font-weight: 600; }

/* —— 右侧栏：统计四格 2×2 + 最新成交动态 —— */
.rk-cap-side { display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 12px; min-width: 0; }
.rk-cap-side .rk-kpis { grid-template-columns: repeat(2, 1fr); margin-top: 0; }
.rk-cap-side .rk-kpi .v { font-size: 19px; }
.rk-cap-side .rk-kpi .v s { font-size: 11px; margin-left: 4px; }

.rk-deals { display: flex; flex-direction: column; overflow: hidden; }
.rk-deal {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 58px 64px;
  gap: 8px;
  align-items: center;
  padding: 6px 13px;
  font-size: 11.5px;
  color: var(--tr-txt-2);
}
.rk-deal + .rk-deal { border-top: 1px solid rgba(255, 255, 255, 0.045); }
.rk-deal .dt { font-size: 10.5px; color: var(--tr-txt-3); }
.rk-deal .ent { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--tr-txt); }
.rk-deal .sv { font-size: 10.5px; color: var(--tr-txt-3); white-space: nowrap; }
.rk-deal .am { text-align: right; color: var(--tr-gold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rk-deal-empty { display: block; text-align: center; color: var(--tr-txt-3); padding: 12px 13px; }

/* —— ② 响应式：卡体回落 —— */
@media (max-width: 1000px) {
  .rk-cap { grid-template-columns: 1fr; }
  /* 基础 .rk-kpis 在 1000 断点已被 pages/rank.css 覆成 2 列 ——
     本节本就是 2×2，无需额外动作；620 以下再收 */
}
@media (max-width: 620px) {
  .rk-cap { gap: 9px; margin-top: 13px; }
  .rk-cap-body { grid-template-columns: 128px minmax(0, 1fr); gap: 12px; padding: 11px 11px 10px; }
  .rk-donut-fig { width: 128px; height: 128px; }
  .rk-donut-c b { font-size: 16px; }
  .rk-lg-hd, .rk-lg-row { grid-template-columns: 10px minmax(0, 1fr) 64px 42px; gap: 6px; }
  .rk-deal { grid-template-columns: 36px minmax(0, 1fr) 50px 58px; gap: 6px; padding: 6px 11px; }
}
@media (max-width: 400px) {
  /* 覆盖 pages/rank.css 的 .rk-kpis{grid-template-columns:1fr}（特异性同、
     本文件后加载取胜）与 .rk-kpi 横排规则 —— 金额格横排会把「亿」单位挤远，
     这里保持竖排 2×2 更稳 */
  .rk-cap-side .rk-kpis { grid-template-columns: repeat(2, 1fr); }
  .rk-cap-side .rk-kpi { display: block; }
  .rk-cap-side .rk-kpi .l { margin-bottom: 5px; }
  .rk-cap-side .rk-kpi .v { font-size: 17px; }
}

/* ============================================================================
   第 11 节 · 人才雷达：领域筛选条（#rdFields）可拖拽横滚
   ----------------------------------------------------------------------------
   pages/radar.css 是 A 组 sha256 基线，一行不改。那里的 `.rd-fields` 已经有
   `overflow-x:auto` + `-webkit-overflow-scrolling:touch` + 隐藏滚动条，
   拖拽所需的**行为**在 radar.js（bindFieldsDrag），这里只补两处表现层：

     · 光标：只有真能拖时才把 grab 抬出来 —— 由 JS 在溢出时给容器加
       `.rd-can-drag`（scrollWidth > clientWidth）。不溢出就别摆拖拽手势，
       把 chip 自己的 `cursor:pointer` 留着（它才是「可点」的暗示）。
       特异性 (0,3,0) > pages/radar.css `.rd-f{cursor:pointer}` 的 (0,1,0)，
       且本文件最后加载，双保险。
     · user-select:none：拖拽途中指针掠过 chip 文字不再拉起选区，
       否则甩完松手会留下一片反白（PC 端用鼠标才看得到，触屏无此问题）。
   ============================================================================ */
.rd-fields{user-select:none;-webkit-user-select:none}
.rd-fields.rd-can-drag{cursor:grab}
.rd-fields.rd-can-drag .rd-f{cursor:inherit}
.rd-fields.rd-dragging{cursor:grabbing}
.rd-fields.rd-dragging .rd-f{cursor:inherit}

/* ============================================================================
   第 12 节 · 学者详情页：学生 / 生源模块下线后的 KPI 栅格补偿（2026-09-29）
   ----------------------------------------------------------------------------
   背景：库内无任何学生实体表、`scientists.students_count` 407 行全 0
   （scripts/import_orecord_data.py 按「真实包零供给落中性值」写死 0），
   原「可推荐生源」卡列表是服务层 DEMO_STUDENT 占位 —— 故学生相关内容整页下线，
   KPI 由 4 项变 2 项（仅留 h-index / 经纪人响应时效）。

   问题：pages/talent-detail.css 是 A 组 sha256 基线、一行不改，那里把 `.td-kpis`
   写死 `grid-template-columns: repeat(4,1fr)`；删两卡后剩余两卡只占左半边，
   右半留白（不是渲染报错，是静默的版式缺陷）。这里按「新增样式层」约定覆盖：

     · 特异性 body.talent-detail .td-kpis = (0,2,1)，压制原 `.td-kpis` (0,1,0)；
     · 且本文件在 pages/*.css 之后加载 —— 双保险，不依赖加载顺序。
     · ≤900px 断点原本就另有 repeat(2,1fr)，故本规则全宽度统一为 2 列，
       与既有断点行为一致，不产生新的断点冲突。

   注：`.td-kpi.hl`（高亮卡）随学生两卡一并消失，`.td-kpi-bar-h .src` 文案已改
   为「影响力 / 响应时效」—— 二者都在模板侧，无需额外样式。
   ============================================================================ */
body.talent-detail .td-kpis{grid-template-columns:repeat(2,1fr)}

/* ============================================================================
   第 13 节 · 学者详情页：合作方式列表下线后的 CTA 间距补偿（2026-10-08）
   ----------------------------------------------------------------------------
   背景：`templates/talent_detail.html` 的 `#cooperation` 区块按产品决策移除
   「企业合作方式 · 按你的目标选择」标题与 4 条方式说明（`.sc-profile`），
   只留下方的 CTA 卡片（`.td-cta`）。区块 id 与页签锚点保留，导航照常可达。

   问题：pages/talent-detail.css 是 A 组 sha256 基线、一行不改，那里写着
   `.sc-section .td-cta { margin-top: var(--td-sp-3) }`（16px）—— 它原本是
   CTA 与**上方列表**之间的间距。列表删掉后 CTA 成了区块内唯一元素，这段
   margin 失去对象却仍生效：卡片内容距区块顶由 22px 变成 38px，比其余区块
   多 16px。不报错、静态断言也抓不到，纯版式不一致。

   覆盖：把 `#cooperation` 的直属 CTA 的 margin-top 归零。
     · 特异性 `#cooperation > .td-cta` = (1,1,0)，压制原 `.sc-section .td-cta` (0,2,0)；
     · theme.css 在 pages/*.css 之后加载 —— 双保险，不依赖加载顺序；
     · 用直属子选择器限定，全站仅此一处 `.sc-section > .td-cta`，不波及别处。
   ============================================================================ */
.sc-section#cooperation > .td-cta{margin-top:0}

/* ============================================================================
   第 14 节 · 闸门壳：未核验访客的落位块（2026-10-08）
   ----------------------------------------------------------------------------
   背景：闸门改由**服务端**执行（`app/core/gate.py`）。未核验访客不再拿到整页
   真实内容，只拿到 `templates/gate_shell.html` —— 全站骨架 + `.zo-gate` 遮罩。
   壳里刻意**没有**内容，若不撑高度，`html.zo-locked{overflow:hidden}` 下页面只有
   顶栏 + 页脚两条，全屏遮罩会浮在一片空白上，看起来像「页面坏了」。

   覆盖：给壳的占位块一个视口高度。
     · `pages/*.css` 是冻结文件（A 组 sha256），`.zo-hold` 是**新增**选择器，
       与任何既有规则都不冲突 —— 不需要压制谁的优先级。
     · 只在 `body.gate-shell` 下生效，别的页面即使误挂 `.zo-hold` 也不受影响。
     · 遮罩本身是 `position:fixed; inset:0`，高度只作背景，故取 70vh 即可
       （顶栏 58px + 70vh + 页脚 ≈ 满屏，不产生额外滚动条）。
   ============================================================================ */
body.gate-shell .zo-hold{min-height:70vh}

/* ============================================================================
   第 15 节 · 人才雷达：移动端单栏栅格被 nowrap 文本顶宽（横向溢出 + 底栏错误）
   ----------------------------------------------------------------------------
   症状（390×844 真机实测，改前）：
     `documentElement.scrollWidth` 734 > `clientWidth` 390 ⇒ **整页横向溢出 344px**；
     `position:fixed` 的底部 tabbar（`.app-tab`）随之被拉伸到 734px 宽，四个 tab
     各 184px ⇒ 「行业趋势 / 热点榜单」两项跑出视口，页面还能左右拖动。

   根因（逐层隐藏法定位到叶子）：
     `pages/radar.css` 在 `@media (max-width:1240px)` 把 `.rd-body` 从桌面的
     `300px minmax(0,1fr)` 覆盖成**裸 `1fr`**。`1fr` 的自动下限是 `auto`
     ⇒ 轨道最小宽度 = 网格项的 min-content。左栏列表项的姓名 / 机构两行是
     `white-space:nowrap` + ellipsis（`.rd-it .tx b` / `.rd-it .tx span`，冻结区），
     长机构名（实测「中国医学科学院与北京协和医学院 · …」单项宽 617px）把
     `aside.rd-side` 的 min-content 顶到 723px，轨道跟着变成 723px。
     ⇒ 溢出链条（隐藏哪一个都能让溢出归零）：
        `.rd-body` → `aside.rd-side` → `.rd-panel` → `#rdPick` → `.rd-it` → `.tx` → nowrap span

   覆盖（`pages/*.css` 是 A 组 sha256 冻结区，只能新增样式层）：
     · `minmax(0,1fr)` —— 轨道下限钉成 0，与桌面第二列 `minmax(0,1fr)` 同源；
     · `.rd-side` / `.rd-col` 补 `min-width:0` —— 网格项自身默认 `min-width:auto`
       同样等于 min-content，**只改轨道不改项，项仍会溢出轨道**（两处缺一不可）。
     · 同媒体条件 + theme.css 后加载 ⇒ 压制冻结文件里的裸 `1fr`，双保险。
     · `#rdMain` 不在本文件重复声明别的属性，只补收缩下限，排版观感与冻结区一致。
   ============================================================================ */
@media (max-width:1240px){
  .rd-body{grid-template-columns:minmax(0,1fr)}
  .rd-side,.rd-col{min-width:0}
}
