/* Hallmark · v2.0.0 · redesign: restyle · theme: Console (graphite, dealt 2/3) · genre: modern-minimal · scope: app · built: 2026-10-30 */
/* Critique: 蓝紫底(var(--bg-dark))+Tailwind 默认色(var(--cyan)/var(--up)/var(--text-muted))+品牌蓝紫渐变 = 一眼生成物；改为中性石墨三层明度、琥珀/冷蓝双信号、全站数字定宽。 */
/* waive 34: body overflow:hidden —— 全屏看盘应用刻意锁死页面滚动，各面板内部各自滚，不是漏写 clip。 */
/* 30a emoji 图标：已修（2026-10-30）—— 全站 emoji 换成 index.html 顶部 sprite 的 #ic-* 线性 SVG，stroke=currentColor。 */
/* waive 33/63/67: canvas aria、中间点文案、大写标签在 HTML/文案层，用户要求「仅改变设计，其他不要动」。 */
/* ===== Reset & Base ===== */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* ===== SVG 图标系统（2026-10-30，替换 emoji）=====
   取代原来当图标用的 emoji（📊 📈 ⭐ 💰 🧠 📰 🌍 🔥 ⚙ …）。
   emoji 的两个硬伤：颜色由系统字体决定、跟深色主题对不上，且各平台长得不一样。
   这套图标 stroke=currentColor，所以选中/hover/禁用态自动继承文字色，不用再造一套。
   尺寸用 em，跟随字级；-0.14em 是为了让图形与中文基线视觉居中。 */
.ic {
  width: 1em; height: 1em;
  display: inline-block;
  vertical-align: -0.14em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}
.ic-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* 导航：图标略大于字，撑住左侧栏的视觉重量 */
.nt-ico .ic { width: 15px; height: 15px; vertical-align: -0.2em; }
/* 面板/卡片标题：比标题字小一档，不抢标题 */
.panel-header .ic, .card-header .ic, h3 .ic, .hot-rank-title .ic { width: 13px; height: 13px; vertical-align: -0.16em; }
/* 按钮里的图标：跟按钮字同高 */
button .ic, .filter-btn .ic, .auto-run-btn .ic { width: 12px; height: 12px; vertical-align: -0.16em; }

:root {
  /* ===== Hallmark · redesign restyle · theme: Console（graphite）=====
     只换视觉系统（colour / type / radius / motion），布局、间距、面板结构与 DOM 一律不动。
     原值备份：style.css.bak-hallmark-*。
     三个取舍，写在这里免得以后被当成随手改的：
       ① 背景原来是蓝紫（Tailwind slate 家族），五个层级差别很小 → 拉回中性石墨，
          hue 固定 250、彩度压到 0.008 左右，只留一丝冷调，层级才分得开。
       ② 强调色原是 Tailwind blue-500（var(--accent)） → 换成 Console 的双信号：
          琥珀 = 人/主动作，冷蓝 = 仪器/读数。蓝紫渐变那套 AI 感就在这里。
       ③ 涨跌语义不变（A 股惯例：涨红跌绿），只把色值换成 Console 的 bad/ok，
          原来的 var(--up) / var(--down) 是两个最标准的 Tailwind 默认色。 */

  /* ===== Apple 深色设计系统（2026-10-30 第三版：用户要求"仿照苹果公司的设计美学"）=====
     参照 macOS / iOS 深色模式的系统色板来做，几个决定性的取舍：

       ① **背景靠明度递进分层，不靠边框**。苹果的暗色界面几乎看不到硬边线：
          窗口底 #121214 → 面板 #1c1c1e → 卡片 #242426 → hover #343437，每级只差 3~4%，
          视线是"浮起来"的，不是"被框住"的。
       ② **边框一律改成白色半透明**（0.08 / 0.14）。暗底上的实色灰线会显脏，
          半透明白线才会像玻璃边缘那样融进背景。
       ③ **强调色统一为系统蓝 #0A84FF**。苹果只在"能点/能选"的地方用蓝，
          其余全部交给灰阶 —— 这是它看起来安静的根本原因。
          原来那版是琥珀金，颜色本身没问题，但金色在暗底上更像"警告"而不是"交互"。
       ④ **红绿换成 iOS 语义色** #FF453A / var(--down)：屏幕上的红绿更纯、更亮，
          像苹果表盘的涨跌，而不是网页安全色。A 股涨红跌绿的语义不变。
       ⑤ **圆角放大到 10 / 14 / 18**（苹果卡片与弹层的实际尺寸），小控件 8。
       ⑥ **字体走系统栈**：-apple-system / SF Pro 优先，中文 PingFang SC，
          没有外链（内网服务，外链字体会白等一次握手）。 */
  --bg-darkest: #121214;
  --bg-dark: #1c1c1e;
  --bg-panel: #242426;
  --bg-card: #2c2c2e;
  --bg-hover: #343437;
  --border: rgba(255, 255, 255, 0.08);
  --border-light: rgba(255, 255, 255, 0.14);

  /* 文字三档对应 iOS 的 label / secondaryLabel / tertiaryLabel */
  --text-primary: #f5f5f7;
  --text-secondary: #a1a1a6;
  --text-muted: #6e6e73;

  --up: #ff453a;
  --up-bg: rgba(255, 69, 58, 0.12);
  --down: #30d158;
  --down-bg: rgba(48, 209, 88, 0.12);
  --flat: #8e8e93;
  --accent: #0a84ff;
  /* 实心强调底上的字色：系统蓝够深，白字 4.6:1 达标（苹果的填充按钮就是白字蓝底）。
     ⚠️ 唯一例外是绿色 --down（var(--down) 太亮），凡 down 实心底的地方单独用深墨字。 */
  --on-accent: #ffffff;
  /* 只作为半透明底色用（active 标签、选中行）。名字保留是因为全站 20 处在引用 */
  --accent-glow: rgba(10, 132, 255, 0.14);
  --gold: #ff9f0a;
  --purple: #bf5af2;
  --cyan: #64d2ff;

  /* 字体：这是内网单机服务，外链 Google Fonts 会白等一次握手才回落到系统字体，
     所以直接以系统字为准；SF Pro 在 macOS 上就是苹方/系统黑体的拉丁伴侣。 */
  --font-body: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC', 'Segoe UI', 'Microsoft YaHei', system-ui, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* 圆角：苹果的控件 10 / 卡片 14 / 弹层 18。原来是 3/4/5/6/7/8/9/10/12 七档并存，等于没有系统 */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 14px;

  --ticker-h: 30px;          /* 桌面端底部指数条高度(手机端未使用) */

  /* ===== 比例式布局基准 (2026-10-02 v3) =====
     全站"宽度/间距/高度"的比例关系只在这里定义一处, 任何页面尺寸都按同一套比例推导,
     不再让每个面板各自写 clamp() 各算各的(那正是"同一个页面里对不齐"的根源)。
     规则: 轨道用 Nfr 按比例分配 → 容器变宽/变窄时所有轨道等比缩放;
           每个轨道配一个由"内容实测最小宽"得出的 minmax 兜底 → 缩到内容放不下时不再缩,
           多余/不足的份额由其余轨道按比例吸收。
     实测依据(2026-10-02, 三视口):
       · 列表栏 190px 时自选股名称仍完整 → 最小 176px
       · F10 栏 230px(旧 clamp 下限)时 股东名 111px 装 134px 文字、公司全名 150 装 160 → 截断;
         F10 栏 268px 时 股东名 148px / 字段值 166px → 全部完整 → 最小 268px
       · 底部面板 174px 时 核心指标网格内容 201px(4 行) → 被切 66px; 190px 时行高 36.6px 正好装下 */
  --gutter: clamp(8px, 0.72vw, 13px);         /* 页面内边距 = 面板间距, 同一口径 */
  --rail-w: clamp(168px, 11.8vw, 236px);      /* 左侧导航栏 */
  --min-list: 176px;                          /* 中栏左(自选股/列表) 最小宽 */
  --min-f10: 268px;                           /* 中栏右(F10) 最小宽 */
  --h-bottom: clamp(176px, 24vh, 252px);      /* 底部"盘口 + 核心指标"面板高度 */

  /* 三栏比例 (fr): 列表 15 : 详情 66.5 : F10 18.5 —— 想调整栏宽只改这三个数 */
  --fr-list: 15fr;
  --fr-main: 66.5fr;
  --fr-f10: 18.5fr;
}

body {
  font-family: var(--font-body);
  background: var(--bg-darkest);
  color: var(--text-primary);
  font-size: 13px;
  /* 全站数字定宽：价格、涨跌幅、成交量、时间全部纵向对齐。
     这是看盘界面可读性最大的一处提升 —— 一列数字不对齐，扫视成本高一个数量级。 */
  font-variant-numeric: tabular-nums;
  /* 全屏应用刻意锁死页面滚动（各面板内部各自滚），保留 hidden；
     sloplint 34 报的 overflow-x 在此为设计选择，已在交付说明里注明。 */
  overflow: hidden;
}

/* ===== Proportional layout: fills any viewport, no scaling transform =====
   All module sizes are relative (vw/vh/fr with clamp guards), so the UI
   adapts to any screen size and aspect ratio natively. */
.app-scale {
  /* 100vw 会把垂直滚动条的宽度也算进来（横向溢出 1 条滚动条宽），
     改 100% 只吃可用宽度；高度仍用 vh，全屏应用的壳。 */
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ===== Scrollbar ===== */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--bg-darkest); }
::-webkit-scrollbar-thumb { background: var(--border-light); border-radius: var(--r-xs); }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* ===== Top Bar ===== */
.top-bar {
  height: 44px;
  background: var(--bg-dark);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 16px;
  gap: 24px;
  flex-shrink: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 6px;
}

.logo-icon {
  color: var(--accent);
  font-size: 20px;
}

.brand-text {
  font-size: 18px;
  font-weight: 600;
  /* 原来是 accent→cyan 的 135° 渐变裁字（蓝紫渐变是「AI 生成感」的头号标志），
     换成实色 + 收紧字距 + 字重撑住。品牌靠克制立住，不靠发光。 */
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

.brand-sub {
  font-size: 12px;
  color: var(--text-muted);
  padding-left: 4px;
  border-left: 1px solid var(--border);
  margin-left: 4px;
}

.market-ticker {
  flex: 1;
  display: flex;
  gap: 20px;
  overflow: hidden;
  align-items: center;
}

.ticker-item {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  cursor: pointer;
  transition: opacity 0.2s;
}

.ticker-item:hover { opacity: 0.8; }

.ticker-name {
  color: var(--text-secondary);
  font-size: 12px;
}

.ticker-price {
  font-weight: 600;
  font-size: 13px;
}

.ticker-change {
  font-size: 11px;
  padding: 1px 5px;
  border-radius: var(--r-xs);
}

.top-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-shrink: 0;
}

.market-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--down);
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.clock {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--accent);
  font-weight: 600;
  letter-spacing: 1px;
}

/* ===== 自动刷新心跳指示 =====
   刻意不用涨跌红绿(那个语义被行情占用), 改用 青=正常 / 琥珀=降频或停滞 / 红=卡住。 */
.poll-hb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: border-color .2s, color .2s;
}
.poll-hb:hover { border-color: var(--border-light); color: var(--text-primary); }
.poll-hb .hb-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cyan);
  flex-shrink: 0;
}
.poll-hb.ok .hb-dot { animation: pulse 2s infinite; }
.poll-hb.warn { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 45%, transparent); }
.poll-hb.warn .hb-dot { background: var(--gold); animation: pulse 1.2s infinite; }
.poll-hb.bad { color: var(--up); border-color: color-mix(in srgb, var(--up) 50%, transparent); }
.poll-hb.bad .hb-dot { background: var(--up); animation: pulse .8s infinite; }
.poll-hb.paused { color: var(--text-muted); }
.poll-hb.paused .hb-dot { background: var(--text-muted); box-shadow: none; animation: none; }

/* ===== Main Layout ===== */
.main-layout {
  display: flex;
  flex: 1;
  min-height: 0; /* fills remaining viewport height below the top bar */
  overflow: hidden;
}

/* ===== Left Sidebar ===== */
.sidebar-left {
  width: var(--rail-w);
  background: var(--bg-dark);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}

.panel-header {
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border);
  background: var(--bg-panel);
}

/* 面板标题 = 全站最高一级的"这是哪块"，必须明显大于它下面的内容。
   2026-11-02：13 → 14px。原来面板标题、排行里的股票名、自选行数据**全是 13px**，
   四个不同层级同一个字号，只靠字重和颜色区分 —— 这是"没有层级体系"最典型的症状。
   负字距用来抵消中文在 14px 下的松散感（苹果标题的常规做法）。 */
.panel-header h3 {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

.panel-count {
  font-size: 11px;
  color: var(--text-muted);
  background: var(--bg-card);
  padding: 2px 8px;
  border-radius: var(--r-md);
}

.watchlist {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0;
}

.watchlist-item {
  padding: 8px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  transition: background 0.15s;
  border-left: 3px solid transparent;
}

.watchlist-item:hover {
  background: var(--bg-hover);
}

.watchlist-item.active {
  background: var(--bg-hover);
  border-left-color: var(--accent);
}

.wl-name {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.wl-stock-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
}

.wl-stock-code {
  font-size: 10px;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.wl-price {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.wl-current {
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-mono);
}

.wl-change {
  font-size: 11px;
  font-family: var(--font-mono);
}

.sidebar-footer {
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  background: var(--bg-panel);
}

.quick-stats {
  display: flex;
  justify-content: space-around;
}

.stat-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.stat-label {
  font-size: 11px;
  color: var(--text-muted);
}

.stat-val {
  font-size: 14px;
  font-weight: 700;
  font-family: var(--font-mono);
}

/* ===== Center Area ===== */
.center-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg-darkest);
}

/* Stock Header */
.stock-header {
  padding: 10px 16px;
  background: var(--bg-panel);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 20px;
  flex-shrink: 0;
}

.sh-left {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.sh-back {
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px 10px;
  background: color-mix(in srgb, var(--cyan) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--cyan) 40%, transparent);
  border-radius: var(--r-sm);
  color: var(--accent);
  font-family: inherit;
  font-size: 12px;
  line-height: 1.4;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s;
}
.sh-back:hover {
  background: color-mix(in srgb, var(--cyan) 24%, transparent);
  border-color: var(--accent);
}

.sh-name {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
}

.sh-code {
  font-size: 13px;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

.sh-industry {
  font-size: 11px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  padding: 2px 8px;
  border-radius: var(--r-xs);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
}

/* 实时刷新时间戳：让用户看到数据是"活的" */
.sh-updated {
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sh-updated:empty { display: none; }

.sh-price-block {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.sh-price {
  font-size: 28px;
  font-weight: 700;
  font-family: var(--font-mono);
}

.sh-change {
  font-size: 15px;
  font-weight: 600;
  font-family: var(--font-mono);
}

.sh-change-percent {
  font-size: 15px;
  font-weight: 600;
  font-family: var(--font-mono);
  padding: 2px 8px;
  border-radius: var(--r-xs);
}

.sh-stats {
  display: flex;
  gap: 16px;
  margin-left: auto;
}

.sh-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.sh-stat-label {
  font-size: 11px;
  color: var(--text-muted);
}

.sh-stat-val {
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--text-primary);
}

/* ===== 页面播报按钮 + 右键选项小框 (个股页头部 / 全景图资讯共用) ===== */
.sh-bc-wrap { display: flex; align-items: center; flex: none; }
.sh-bc-btn, .pn-bc-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  background: color-mix(in srgb, var(--cyan) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--cyan) 35%, transparent);
  border-radius: var(--r-sm);
  color: var(--accent);
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;   /* iOS 长按不弹系统菜单 */
  transition: background 0.15s, border-color 0.15s;
}
.sh-bc-btn:hover, .pn-bc-btn:hover { background: color-mix(in srgb, var(--cyan) 22%, transparent); border-color: var(--accent); }
.sh-bc-btn.playing, .pn-bc-btn.playing {
  background: color-mix(in srgb, var(--gold) 14%, transparent);
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  color: var(--gold);
}
.sh-bc-btn.loading, .pn-bc-btn.loading { opacity: 0.6; cursor: wait; }

/* 全景图「市场资讯」头部右侧(时间戳 + 播报按钮) */
.pn-news-right { display: flex; align-items: center; gap: 10px; min-width: 0; }

.sh-bc-menu {
  position: fixed;
  z-index: 9500;
  width: 320px;
  max-width: 92vw;
  max-height: min(72vh, 560px);
  overflow-y: auto;
  display: none;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  padding: 8px;
}
.sh-bc-menu.open { display: block; }
.sh-bc-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 2px 4px 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-primary);
}
.sh-bc-menu-head small { display: block; font-size: 10.5px; font-weight: 400; color: var(--text-muted); margin-top: 1px; }
.sh-bc-menu-reset {
  flex: none;
  padding: 3px 10px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 11px;
  cursor: pointer;
}
.sh-bc-menu-reset:hover { border-color: var(--accent); color: var(--accent); }
.sh-bc-menu-tree .bc-node-kids { margin-left: 14px; padding-left: 6px; border-left: 1px solid var(--border); }

/* 资讯播报选项(单选组) */
.pn-bc-sec { padding: 2px 4px 6px; }
.pn-bc-sec + .pn-bc-sec { border-top: 1px solid var(--border); padding-top: 6px; }
.pn-bc-sec-title { font-size: 11px; font-weight: 600; color: var(--text-muted); margin: 2px 0 3px; }
.pn-bc-opt { cursor: pointer; }
.pn-bc-opt input { border-radius: 50%; }   /* 视觉上暗示单选 */
.pn-bc-foot {
  margin-top: 6px;
  padding: 6px 4px 2px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  color: var(--text-muted);
}

.bc-toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  transform: translateX(-50%) translateY(8px);
  z-index: 9600;
  max-width: 78vw;
  padding: 8px 16px;
  background: color-mix(in srgb, var(--bg-panel) 92%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-size: 12.5px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s, transform 0.2s;
}
.bc-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Abnormal Analysis Row */
.abnormal-analysis-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 16px;
  background: var(--bg-dark);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  transition: background 0.15s;
  flex-shrink: 0;
  min-height: 32px;
  outline: none;
}
.abnormal-analysis-row:hover,
.abnormal-analysis-row:focus {
  background: var(--bg-hover);
}
.aa-label {
  font-size: 11px;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--up) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--up) 30%, transparent);
  padding: 1px 6px;
  border-radius: var(--r-xs);
  white-space: nowrap;
  flex-shrink: 0;
}
.aa-summary {
  flex: 1;
  font-size: 12px;
  /* 行内 .aa-tag 是 inline-block(11px + 2px 内边距 + 1px 边框 = 19px), 而 12px 的
     normal 行高只有 16px → 标签下沿每次都被 overflow:hidden 切掉 3px。
     把行高对齐到标签高度, 让它"正好落在范围内"。 */
  line-height: 19px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.aa-summary .aa-tag {
  margin-right: 8px;
}
.aa-divider {
  color: var(--text-muted);
  margin: 0 8px;
}
.aa-more {
  font-size: 11px;
  color: var(--accent);
  white-space: nowrap;
  flex-shrink: 0;
}

/* Chart Toolbar */
.chart-toolbar {
  padding: 6px 16px;
  background: var(--bg-dark);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 4px;
}

.period-btn, .indicator-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-secondary);
  padding: 4px 12px;
  font-size: 12px;
  cursor: pointer;
  border-radius: var(--r-xs);
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}

.period-btn:hover, .indicator-btn:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.period-btn.active, .indicator-btn.active {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}

.divider {
  width: 1px;
  height: 16px;
  background: var(--border);
  margin: 0 6px;
}

.chart-info {
  font-size: 11px;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

/* Chart */
.chart-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
}

/* 分时/其他单图布局：K线占满，volume固定120px */
.chart-wrapper:not(.chart-wrapper-3) > #klineChart {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.chart-wrapper:not(.chart-wrapper-3) > #volumeChart {
  height: clamp(90px, 15vh, 130px);
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  overflow: hidden;
}

/* Bottom Panels */
.bottom-panels {
  display: flex;
  gap: 1px;
  background: var(--border);
  border-top: 1px solid var(--border);
  height: clamp(160px, 20vh, 230px);
  flex-shrink: 0;
}

.panel {
  background: var(--bg-dark);
  display: flex;
  flex-direction: column;
}

.order-book-panel {
  width: clamp(280px, 26vw, 380px);
  flex-shrink: 0;
}

.trade-info-panel {
  flex: 1;
}

/* ===== F10 Panel (right sidebar) ===== */
.f10-panel {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.f10-sub {
  font-size: 11px;
  color: var(--text-muted);
  margin-left: 8px;
}
.f10-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px 12px;
  min-height: 0;
}
.f10-loading {
  padding: 16px;
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
}
.f10-sec { margin-bottom: 10px; }
.f10-sec-title {
  font-size: 11px;
  color: var(--accent);
  font-weight: 600;
  margin-bottom: 5px;
  border-left: 2px solid var(--accent);
  padding-left: 6px;
}
.f10-kv {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  font-size: 11px;
  line-height: 1.9;
}
.f10-k { color: var(--text-muted); flex-shrink: 0; }
/* 值不再 nowrap+省略号(1440 视口下 150px 装 160px 的"TCL中环新能源科技股份有限公司"被截断),
   放不下就换到第二行右对齐 —— 宁可占一行也不能显示半个公司名 */
.f10-v {
  color: var(--text-primary);
  text-align: right;
  overflow-wrap: anywhere;
  min-width: 0;
}
.f10-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.f10-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  color: var(--text-secondary);
  background: var(--bg-hover, rgba(255,255,255,0.05));
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  padding: 1px 6px;
  cursor: default;
}
.f10-tag[onclick] { cursor: pointer; }
/* 同花顺板块标签（2026-10-22）：
   · 行业用青色描边与概念区分 —— 用户看「所属板块」时要能一眼分出哪些是行业、哪些是概念；
   · 所属行业那一格是**纯文本**（不关联板块），所以显式去掉 hover/pointer 暗示。 */
.f10-tag-ind {
  color: var(--cyan);
  border-color: color-mix(in srgb, var(--cyan) 38%, transparent);
  background: color-mix(in srgb, var(--cyan) 8%, transparent);
}
/* 所属行业 = 纯文本：连边框/底色一起去掉。
   只改 cursor 不够 —— 带边框的圆角小方块在视觉上就是"可点的标签"（铁律 107）。 */
.f10-tag-plain {
  cursor: default;
  border-color: transparent;
  background: transparent;
  padding: 1px 0;
  font-size: 11px;
  color: var(--text-primary);
}
.f10-tag[onclick]:hover { border-color: var(--accent); color: var(--accent); }
.f10-tag-ind[onclick]:hover { border-color: var(--cyan); color: var(--cyan); }
.f10-sec-note { font-size: 9px; color: var(--text-muted); font-weight: 400; margin-left: 4px; }
.f10-muted { color: var(--text-muted); }
.ts-noquote { font-size: 12px; opacity: .55; }
.ts-desc-muted { opacity: .7; }
.tag-pct { font-size: 9px; font-weight: 500; }
.neutral { color: var(--text-secondary) !important; }
.f10-text {
  font-size: 11px;
  line-height: 1.7;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.f10-news { display: flex; flex-direction: column; gap: 2px; }
/* 资讯行: 窄侧栏里单行塞 4 件套(时间 78px + 标题 188px + 来源 36px + 分类 46px = 348px)
   而 F10 内容宽只有 218~292px → 标题被压到 4~81px(2 个字), 1440 视口下甚至整行溢出 11px。
   改为"比例自适应换行": 标题独占一行拿满宽, 元信息落到第二行; 两行都不需要压窄任何文字。 */
.f10-news-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 1px 6px;
  padding: 4px;
  border-radius: var(--r-xs);
  cursor: pointer;
  font-size: 11px;
}
.f10-news-item > .f10-news-title { order: 1; flex: 1 1 100%; }   /* 独占一行 */
.f10-news-item > .f10-news-time { order: 2; }
.f10-news-item > .f10-news-source { order: 3; }
.f10-news-item > .f10-news-cat { order: 4; margin-left: auto; }  /* 分类靠右 */
.f10-news-item:hover { background: var(--bg-hover, rgba(255,255,255,0.05)); }
.f10-news-time { color: var(--text-muted); font-size: 10px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.f10-news-title {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1;
}
.f10-news-item:hover .f10-news-title { color: var(--text-primary); }
.f10-news-cat {
  flex-shrink: 0;
  font-size: 9px;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  padding: 0 4px;
}
.f10-news-empty { font-size: 11px; color: var(--text-muted); padding: 4px 0; }
.f10-news-tabs { display: flex; gap: 2px; margin-bottom: 6px; }
.f10-news-tab {
  font-size: 11px;
  color: var(--text-muted);
  padding: 2px 8px;
  border-radius: var(--r-xs);
  cursor: pointer;
  border: 1px solid transparent;
}
.f10-news-tab:hover { color: var(--text-primary); background: var(--bg-hover, rgba(255,255,255,0.05)); }
.f10-news-tab.active { color: var(--text-primary); background: var(--bg-card, rgba(255,255,255,0.08)); border-color: var(--border); }
.f10-news-content { min-height: 40px; }
.f10-news-loading { font-size: 11px; color: var(--text-muted); padding: 8px 0; }
.f10-news-source {
  flex-shrink: 0;
  font-size: 9px;
  color: var(--text-muted);
  max-width: 70px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.f10-sec-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 5px;
}
.f10-view-all {
  background: transparent;
  border: none;
  color: var(--accent);
  font-size: 11px;
  cursor: pointer;
  padding: 0;
}
.f10-view-all:hover { text-decoration: underline; }

/* ===== F10「核心竞争力」 =====
   F10 侧栏很窄(218~292px), 而单条正文实测最长 1060 字 → 默认折叠到 3 行, 点"展开"看全文。
   折叠用 line-clamp 而不是截断字符串: 数据始终是完整的, 只是展示收敛
   (不然"复制/搜索全文"就废了, 也会让验收的"内容非空"变成看运气)。
   展开态用 [data-expanded="1"] 把 -webkit-line-clamp 置 unset —— 可被断言直接读到。 */
.f10-cmp-count {
  font-size: 10px;
  color: var(--text-muted);
  flex-shrink: 0;
}
.f10-cmp-list { display: flex; flex-direction: column; gap: 7px; }
.f10-cmp-item {
  border-left: 2px solid var(--border);
  padding-left: 7px;
}
.f10-cmp-head {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-bottom: 2px;
  min-width: 0;
}
.f10-cmp-idx {
  flex-shrink: 0;
  font-size: 9px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-glow);
  border-radius: 2px;
  min-width: 13px;
  text-align: center;
  line-height: 14px;
}
.f10-cmp-title {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-primary);
  overflow-wrap: anywhere;
  min-width: 0;
}
.f10-cmp-body {
  font-size: 11px;
  line-height: 1.7;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.f10-cmp-body[data-expanded="1"] {
  -webkit-line-clamp: unset;
  overflow: visible;
}
.f10-cmp-toggle {
  margin-top: 3px;
  background: transparent;
  border: none;
  padding: 0;
  color: var(--accent);
  font-size: 10px;
  cursor: pointer;
}
.f10-cmp-toggle:hover { text-decoration: underline; }

/* ===== F10 查看全部弹窗 ===== */
.f10-all-news-box {
  width: min(760px, 92vw);
  max-height: 78vh;
  padding: 20px 22px 18px;
}
.f10-all-news-tabs {
  display: flex;
  gap: 6px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.f10-all-news-tab {
  font-size: 13px;
  color: var(--text-muted);
  padding: 5px 12px;
  border-radius: var(--r-xs);
  cursor: pointer;
  border: 1px solid transparent;
}
.f10-all-news-tab:hover { color: var(--text-primary); background: var(--bg-hover, rgba(255,255,255,0.05)); }
.f10-all-news-tab.active { color: var(--text-primary); background: var(--bg-card, rgba(255,255,255,0.08)); border-color: var(--border); }
.f10-all-news-content { padding-right: 4px; }
.f10-all-news-list { display: flex; flex-direction: column; gap: 3px; }
.f10-all-news-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--r-xs);
  cursor: pointer;
  font-size: 12px;
}
.f10-all-news-item:hover { background: var(--bg-hover, rgba(255,255,255,0.05)); }
.f10-all-news-time { color: var(--text-muted); font-size: 11px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.f10-all-news-title {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1;
}
.f10-all-news-item:hover .f10-all-news-title { color: var(--text-primary); }
.f10-all-news-source {
  flex-shrink: 0;
  font-size: 10px;
  color: var(--text-muted);
  max-width: 90px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.f10-all-news-cat {
  flex-shrink: 0;
  font-size: 10px;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  padding: 1px 5px;
}
.f10-holder {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  line-height: 1.9;
}
.f10-holder-idx {
  width: 14px;
  color: var(--text-muted);
  text-align: right;
  flex-shrink: 0;
}
.f10-holder-name {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-primary);
}
.f10-holder-num {
  color: var(--text-muted);
  flex-shrink: 0;
  font-size: 10px;
}

/* Order Book - 买卖五档左右对照（L1 数据源最多五档） */
.order-book {
  flex: 1;
  overflow: hidden;
  padding: 4px 10px;
}
.order-book.empty {
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); font-size: 12px;
}
.ob-wrap {
  display: flex; flex-direction: column;
  height: 100%; gap: 2px;
}
.ob-columns {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 10px;
  min-height: 0;
}
.ob-col {
  display: flex; flex-direction: column;
  justify-content: flex-start;
  gap: 0;
  min-height: 0;
}
.ob-side-label {
  text-align: center; font-size: 10px;
  padding: 1px 0; border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.ob-side-label.ask { color: var(--up); }
.ob-side-label.bid { color: var(--down); }
.ob-row {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-family: var(--font-mono);
  position: relative; padding: 2px 0;
  flex-shrink: 1;
}
/* 桌面/平板: 5 档高度按列内可用空间等分 —— 面板变矮时 5 档一起等比压缩,
   不会让最后一档(卖1/买1)溢出到面板底边之外被切掉(旧版实测溢出 3px)。
   手机端不参与(那里底部面板高度自适应)。 */
@media (min-width: 769px) {
  .stock-panel .ob-row { flex: 1 1 0; min-height: 0; }
}
.ob-label { width: 26px; color: var(--text-muted); font-size: 10px; }
.ob-price { flex: 1; font-weight: 600; text-align: right; }
.ob-volume { width: 54px; color: var(--text-secondary); text-align: right; }
.ob-bar {
  position: absolute; right: 0; top: 0; bottom: 0;
  opacity: 0.12; border-radius: 2px 0 0 2px; pointer-events: none;
}
.ob-ask .ob-bar { background: var(--up); }
.ob-bid .ob-bar { background: var(--down); }
.ob-ask .ob-price { color: var(--up); }
.ob-bid .ob-price { color: var(--down); }
.ob-last-price {
  display: flex; align-items: center; justify-content: center;
  padding: 3px 0; font-size: 15px; font-weight: 700;
  font-family: var(--font-mono);
  border-bottom: 1px dashed var(--border);
  flex-shrink: 0;
}
.ob-l2-hint {
  text-align: center; font-size: 9px; color: var(--text-muted);
  padding-top: 1px; flex-shrink: 0;
}

/* Trade Detail */
.trade-detail {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0;
}

.td-row {
  display: flex;
  align-items: center;
  padding: 2px 14px;
  font-size: 11px;
  font-family: var(--font-mono);
  gap: 12px;
}

.td-time { color: var(--text-muted); width: 70px; }
.td-price { width: 70px; font-weight: 600; }
.td-volume { width: 60px; color: var(--text-secondary); text-align: right; }
.td-flag {
  font-size: 10px;
  padding: 1px 5px;
  border-radius: 2px;
}

.td-flag.buy { color: var(--up); background: var(--up-bg); }
.td-flag.sell { color: var(--down); background: var(--down-bg); }

/* ===== Right Sidebar ===== */
.sidebar-right {
  width: clamp(220px, 17vw, 320px);
  background: var(--bg-dark);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  overflow-y: auto;
}

.sidebar-right .panel {
  border-bottom: 1px solid var(--border);
}

/* Indicator Grid */
.indicator-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--border);
}

.indicator-cell {
  background: var(--bg-dark);
  padding: 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ic-label {
  font-size: 10px;
  color: var(--text-muted);
}

.ic-value {
  font-size: 14px;
  font-weight: 600;
  font-family: var(--font-mono);
}

/* News Panel */
.news-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.news-feed {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0;
}

.news-item {
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background 0.15s;
}

.news-item:hover {
  background: var(--bg-hover);
}

.news-title {
  font-size: 12px;
  color: var(--text-primary);
  line-height: 1.5;
  margin-bottom: 4px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.news-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  color: var(--text-muted);
}

.news-tag {
  padding: 1px 6px;
  border-radius: 2px;
  background: var(--bg-card);
  color: var(--text-secondary);
  font-size: 10px;
}

.news-tag.macro { color: var(--gold); background: color-mix(in srgb, var(--gold) 10%, transparent); }
.news-tag.company { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.news-tag.report { color: var(--purple); background: color-mix(in srgb, var(--purple) 10%, transparent); }
.news-tag.market { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 10%, transparent); }

/* ===== 资讯多源状态条 (2026-10-22) =====
   多源之后"资讯变少了"有两种完全不同的原因: 某家挂了, 或某家本来就慢。
   状态条把每家的本次条数与状态摆在列表正上方, 降级一眼可见(kb铁律 10)。
   ⚠️ 状态色不能用 --up/--down —— 那是涨红跌绿, 拿来标"正常/异常"会被读反。 */
.news-srcbar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 2px 9px;
  padding: 3px 14px 5px;
  border-bottom: 1px solid var(--border);
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-muted);
  overflow: hidden;
}
.news-src { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; cursor: default; }
.news-src i { font-style: normal; font-size: 8px; line-height: 1; }
.news-src b { font-weight: 600; margin-left: 2px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.news-src.ok i { color: var(--down); }
.news-src.degraded i,
.news-src.degraded b { color: var(--gold); }
.news-src.skipped i { color: var(--text-secondary); }
.news-src.idle i { color: var(--text-muted); }

/* 来源标签: 与「分类标签」并列但更弱 —— 同一件事会来自不同源, 用户需要一眼分辨谁说的。
   刻意避开红/绿两色, 免得来源色被误读成涨跌。 */
.news-org { font-size: 10px; }
.news-org.cls { color: var(--purple); }
.news-org.jin10 { color: var(--gold); }
.news-org.wscn { color: var(--cyan); }
.news-org.ths { color: var(--purple); }
.news-org.sina { color: var(--text-secondary); }

/* ===== Color Utilities ===== */
.up { color: var(--up) !important; }
.down { color: var(--down) !important; }
.flat { color: var(--flat) !important; }

.up-bg { background: var(--up-bg); }
.down-bg { background: var(--down-bg); }

/* ===== Loading ===== */
.loading-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-darkest);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  transition: opacity 0.3s;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ===== V2: Panel Navigation ===== */
.nav-tabs {
  display: flex;
  gap: 4px;
  background: var(--bg-dark);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 3px;
  /* 2026-10-26: 新增「AI训练」后 13 个入口在 1440 宽下会挤到换行
     (每个 tab 被压成两行字)。这里改成不换行 + 不收缩,
     真的装不下时整条导航横向滚动, 而不是把字挤成两行。 */
  flex-wrap: nowrap;
  flex-shrink: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.nav-tabs::-webkit-scrollbar { display: none; }
.nav-tab {
  background: transparent;
  border: none;
  color: var(--text-secondary);
  font-size: 13px;
  padding: 5px 9px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: color .2s, background-color .2s, border-color .2s, opacity .2s, transform .2s;
  font-family: inherit;
  white-space: nowrap;
  flex: 0 0 auto;
}
@media (max-width: 1400px) and (min-width: 769px) {
  .nav-tab { padding: 5px 7px; font-size: 12px; }
}
.nav-tab:hover { color: var(--text-primary); background: var(--bg-hover); }
/* 选中态只上极淡底色 + 强调色文字，不用实心金底 —— 顶部导航是常驻元素，
   实心底块会一直抢视线（原来那版是 accent→cyan 渐变 + 白字，最跳的一块）。 */
.nav-tab.active {
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  color: var(--accent);
  font-weight: 600;
}

/* ===== Main Content Panels ===== */
.main-layout { display: flex; overflow: hidden; }
.main-content {
  flex: 1;
  overflow-y: auto;
  padding: var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
  min-width: 0;
}
.panel-scroll {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ===== Index Cards (全景) ===== */
.index-cards {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.index-card {
  flex: 1;
  min-width: 200px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 14px 16px;
  cursor: pointer;
  transition: color .25s, background-color .25s, border-color .25s, opacity .25s, transform .25s;
}
.index-card:hover {
  border-color: var(--border-light);
  background: var(--bg-card);
}
.ic-top { display: flex; justify-content: space-between; align-items: baseline; }
.ic-name { font-size: 14px; font-weight: 600; }
.ic-code { font-size: 11px; color: var(--text-muted); }
.ic-price { font-size: 26px; font-weight: 700; margin: 6px 0 2px; }
.ic-change { display: flex; gap: 10px; font-size: 13px; }
.ic-sub { font-size: 11px; color: var(--text-muted); margin-top: 6px; }

/* ===== Market Stats Strip ===== */
.market-stats-strip {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.ms-item {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 10px 18px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.ms-label { font-size: 12px; color: var(--text-muted); }
.ms-val { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.ms-val.up { color: var(--up); }
.ms-val.down { color: var(--down); }

/* ===== A股涨跌家数 (全景图) ===== */
/* ⚠️ 本段是桌面端基准样式, 必须留在**移动端媒体查询之前** —— 否则文件末尾的
   @media(max-width:768px) 覆盖会被这里的同名规则反吃掉(kb 铁律 24: 断点要放在能生效的位置)。 */
.breadth-panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 10px 14px 12px;
}
.bp-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 8px;
}
.bp-title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.bp-sub { font-size: 11px; color: var(--text-muted); margin-left: auto; }
/* 降级/陈旧必须比常态显眼 —— 否则用户会把几天前的分布当成今日实时(铁律 4/17) */
.bp-sub.is-stale { color: var(--gold); font-weight: 600; }
/* 副源(同花顺)模式: 数据是新的, 只是来源与口径变了 → 用青色区别于"陈旧"的金色,
   既不制造告警感, 又能让人一眼看出"这不是东财那份数"。 */
.bp-sub.is-fallback { color: var(--cyan); font-weight: 600; }
/* 口径说明: 副源覆盖沪深两市、不含北交所 —— 属于常态说明, 用虚下划线提示可 hover 看原因 */
.bp-src {
  border-bottom: 1px dashed var(--border-light);
  cursor: help;
  color: var(--cyan);
}
.bp-bar {
  display: flex;
  height: 14px;
  /* 全圆角：高度 14 的一半，苹果的比例条都是胶囊形 */
  border-radius: 7px;
  overflow: hidden;
  background: var(--bg-hover);
}
/* 宽度由内联 style 按家数占比给定, 这里只管颜色与不塌陷 */
.bp-seg { display: block; height: 100%; flex: 0 0 auto; }
/* 这条是全页面积最大的纯色块，直接用 --up/--down 会亮得压过所有数字。
   掺 22% 背景色压低一档，比例仍然一眼可读，但不再"发光"（苹果的表盘/进度条也是这个做法）。 */
.bp-seg.up { background: color-mix(in srgb, var(--up) 78%, var(--bg-panel)); }
.bp-seg.down { background: color-mix(in srgb, var(--down) 72%, var(--bg-panel)); }
.bp-seg.flat { background: var(--flat); }
.bp-legend {
  display: flex;
  align-items: center;
  gap: 6px 22px;
  flex-wrap: wrap;
  margin-top: 9px;
}
.bp-cell { display: flex; align-items: baseline; gap: 6px; }
.bp-cell-label { font-size: 12px; color: var(--text-muted); }
.bp-cell-num { font-size: 18px; font-weight: 700; line-height: 1.1; }
.bp-cell-pct { font-size: 11px; color: var(--text-muted); }
.bp-cell.up .bp-cell-num { color: var(--up); }
.bp-cell.down .bp-cell-num { color: var(--down); }
.bp-cell.flat .bp-cell-num { color: var(--text-secondary); }
.bp-foot {
  margin-left: auto;
  display: flex;
  gap: 12px;
  font-size: 11px;
  color: var(--text-muted);
  /* 脚注可能同时出现「有效 / 已剔除停牌 / 已剔除退市」三项, 窄容器允许换行,
     否则会横向溢出把最后一项裁掉(几何上"没报错", 实际看不见 —— kb铁律 20) */
  flex-wrap: wrap;
  justify-content: flex-end;
  row-gap: 2px;
}
/* 退市剔除量用中性色(dashed 下划线)而不是告警色: 这是**常态化的口径说明**,
   不是异常; 与"停牌"用同一视觉权重会让人误以为数据出了问题。 */
.bp-delisted {
  border-bottom: 1px dashed var(--border-light);
  cursor: help;
}
.bp-empty { font-size: 12px; color: var(--text-muted); padding: 8px 0; }

/* ===== Trend Rating Strip (全部股票面板) ===== */
.trend-rating-strip {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 10px 0 2px;
}
.tr-loading {
  font-size: 12px;
  color: var(--text-muted);
  padding: 10px 14px;
}
.tr-card {
  flex: 1 1 calc(20% - 8px);
  min-width: 130px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 10px 12px;
  cursor: pointer;
  transition: color .25s, background-color .25s, border-color .25s, opacity .25s, transform .25s;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tr-card:hover {
  border-color: var(--border-light);
  background: var(--bg-card);
}
.tr-card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.tr-card-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}
.tr-card-count {
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}
.tr-card-count.up { color: var(--up); }
.tr-card-count.down { color: var(--down); }
.tr-card-count.info { color: var(--text-secondary); }
.tr-card-top1 {
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tr-card-top1 .tr-pct {
  margin-left: 4px;
  font-weight: 600;
}
.tr-card-top1 .tr-pct.up { color: var(--up); }
.tr-card-top1 .tr-pct.down { color: var(--down); }

/* 走势评级弹窗列表 */
.tr-modal-meta {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.tr-modal-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: min(60vh, 520px);
  overflow-y: auto;
}
.tr-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background 0.15s;
  border: 1px solid transparent;
}
.tr-row:hover {
  background: var(--bg-hover);
  border-color: var(--border);
}
.tr-row-rank {
  width: 28px;
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  flex-shrink: 0;
}
.tr-row-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.tr-row-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}
.tr-row-code {
  font-size: 11px;
  color: var(--text-muted);
}
.tr-row-score {
  width: 46px;
  text-align: right;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  flex-shrink: 0;
}
.tr-row-pct {
  width: 64px;
  text-align: right;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}
.tr-row-price {
  width: 58px;
  text-align: right;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}

/* 走势评级弹窗排序栏 */
.tr-sort-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.tr-sort-label {
  font-size: 12px;
  color: var(--text-muted);
}
.tr-sort-btn {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 12px;
  padding: 4px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-family: inherit;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.tr-sort-btn:hover { border-color: var(--accent); color: var(--text-primary); }
.tr-sort-btn.active {
  background: var(--accent-glow);
  border-color: var(--accent);
  color: var(--accent);
}
.tr-sort-btn.active::after {
  content: '↓';
  margin-left: 3px;
  font-size: 11px;
}
.tr-sort-btn.active.asc::after { content: '↑'; }
.tr-sort-hint {
  margin-left: auto;
  font-size: 11px;
  color: var(--text-muted);
}

/* ===== Panorama Grid ===== */
.panorama-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.panorama-news { grid-column: span 2; }

/* ===== 全景图精选榜单 (同花顺 人气榜 / 板块热榜, 2026-10-22 取代涨幅/跌幅榜) =====
   两块面板结构完全一致: 头部(标题 + 分段 tab) → 口径行 → 表格体。
   分数式布局: 头部与口径行不参与伸缩, 表格体吃掉剩余高度并自己滚 —— 行高不随窗口抖动。 */
.pn-rank-panel { display: flex; flex-direction: column; min-width: 0; }
.pn-tabs { display: flex; gap: 4px; flex-shrink: 0; }
.pn-tab {
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-size: 11px;
  line-height: 1;
  padding: 4px 10px;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.pn-tab:hover { background: var(--bg-hover); color: var(--text-primary); }
.pn-tab.active {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  color: var(--cyan);
}
/* 「全部」是**范围开关**（热度榜 TOP10 ⇄ 全量板块），不是第三种分类 ——
   用青色与蓝色的分类 tab 区分开，否则会被读成"行业/概念/全部"三选一。 */
.pn-tab.pn-scope { margin-left: 6px; color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 45%, transparent); }
.pn-tab.pn-scope:hover { background: color-mix(in srgb, var(--cyan) 12%, transparent); color: var(--cyan); }
.pn-tab.pn-scope.active {
  background: color-mix(in srgb, var(--cyan) 18%, transparent);
  border-color: color-mix(in srgb, var(--cyan) 70%, transparent);
  color: var(--cyan);
}
.pn-rank-meta {
  font-size: 10px;
  color: var(--text-muted);
  padding: 5px 14px 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 副源异常: 必须比"加载中"显眼, 否则会一直盯着一个空白面板等它出来 */
.pn-rank-meta.is-err { color: var(--gold); }
.pn-rank-body { min-width: 0; overflow: auto; }
/* 「全部」视图最多 294 行 —— 必须自己封顶。
   不封顶时面板高度会被行数决定（实测 294 行 → 4174px），整页被撑长、
   下面的「市场资讯」被顶到看不见的位置，而且同排的人气榜会被拉出大片空白。 */
.pn-rank-panel.is-all .pn-rank-body { max-height: min(62vh, 620px); }
.pn-rank-table th, .pn-rank-table td { padding: 6px 10px; }
.pnr-no { width: 36px; }
/* 序号：纯数字 + 颜色分级（2026-11-02）
   与左侧 .hr-rank 同一套做法。原先是圆角方块，第 1 名红底深字、2/3 名半透明红底，
   一列下来「红块/浅红块/更浅红块/灰块」像是批量套的排行榜模板；
   而且实心红块的视觉重量盖过了它标注的股票名。
   序号是一个"位置标记"，不需要背景和边框，颜色分级已经足够区分前三。 */
.pnr-badge {
  display: inline-block;
  min-width: 18px;
  padding: 0 4px;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.pnr-badge.r1 { color: var(--up); font-weight: 800; }
.pnr-badge.r2, .pnr-badge.r3 { color: var(--gold); }
.pnr-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* 热度值 = "被关注程度"的绝对值，不是价格。
   原来是青色（--cyan #64d2ff）用来和涨跌的红绿区分 —— 方向对，但青色在深底上
   比红色还亮，一列「+9.89% / 75.5万」看过去，视线先被热度吸走，主次是反的。
   2026-11-02 改成浅灰：既不属于红绿语义，也不和涨跌争亮。靠列标题和位置就够识别。 */
.pnr-num.heat { color: var(--text-secondary); font-weight: 600; }
.pnr-tag, .pnr-misc {
  max-width: 104px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-muted);
  font-size: 11px;
}
.pn-empty { text-align: center; color: var(--text-muted); padding: 24px 0 !important; }
/* 板块行在东财板块列表里没有同名项时不挂 onclick → 也不该显示成可点 */
.pn-row-static { cursor: default; }

/* ===== Rank Table ===== */
.rank-table, .ts-table, .watchlist-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.rank-table th, .ts-table th, .watchlist-table th {
  text-align: left;
  padding: 8px 10px;
  color: var(--text-muted);
  font-weight: 500;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg-panel);
}
.rank-table td, .ts-table td, .watchlist-table td {
  padding: 7px 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
}
.clickable-row { cursor: pointer; transition: background 0.15s; }
.clickable-row:hover { background: var(--bg-hover); }
.rank-name { font-weight: 600; }
.rank-code { font-size: 10px; color: var(--text-muted); }
.muted { color: var(--text-muted); }

/* ===== Theme / Sector Cards ===== */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 12px;
}

/* ===== 热门板块排行 (板块页左侧小窗口) ===== */
.sectors-layout {
  display: flex;
  gap: 12px;
  min-width: 0;
  align-items: flex-start;
}
.sectors-main { flex: 1; min-width: 0; }
.hot-rank-panel {
  width: clamp(210px, 16vw, 280px);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  align-self: flex-start;
  position: sticky;
  top: 0;
  max-height: calc(100vh - 140px);
  overflow: hidden;
}
.hot-rank-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--border);
}
.hot-rank-title { font-size: 14px; font-weight: 700; }
.hot-rank-tabs { display: flex; gap: 6px; }
.hr-tab {
  flex: 1;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: 12px;
  padding: 4px 0;
  cursor: pointer;
  transition: color .2s, background-color .2s, border-color .2s, opacity .2s, transform .2s;
}
.hr-tab:hover { border-color: var(--border-light); color: var(--text-secondary); }
.hr-tab.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.hot-rank-meta {
  font-size: 11px;
  color: var(--text-muted);
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
}
.hot-rank-list {
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.hr-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
}
.hr-row:last-child { border-bottom: none; }
.hr-row:hover { background: var(--bg-card); }
/* 序号：纯数字，只用颜色区分前三（2026-11-02）
   原来是 20×20 圆角方块，第 1 名红底白字、2/3 名半透明红底 ——
   一列下来是「红圆点/浅红圆点/更浅红圆点/灰方块」，典型的排行榜模板长相，
   而且实心红块的视觉重量超过了它标注的股票本身。
   改成和右侧「同花顺话题榜」一致的纯数字 + 颜色分级：读者扫的是数字，不是徽章。 */
.hr-rank {
  width: 18px;
  display: flex;
  align-items: center;
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.hr-rank.r1 { color: var(--up); font-weight: 800; }
.hr-rank.r2, .hr-rank.r3 { color: var(--gold); }
.hr-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.hr-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hr-sub { font-size: 10px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hr-pct { font-size: 13px; font-weight: 700; flex-shrink: 0; }
/* ===== 板块卡片（2026-11-02 去装饰版）=====
   原来每张卡还有：顶部 2px 彩色边（theme=饱和紫 / sector=蓝）、板块名前的图标、
   一整行「查看成分股」按钮。12 张并排时这三样全是噪音 ——
   顶边是 12 条彩色横线、同一个靶心图标重复 12 次、按钮让每张卡都长成一张表单。
   现在：只有名字、说明、涨跌幅；整卡可点，hover 时右缘浮出 › 。
   卡高 100px → 62px，一屏多出两行板块。 */
.ts-card {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  cursor: pointer;
  transition: background-color .14s, border-color .14s;
}
/* hover 只做两件事：底色提一档、边框提亮。不做位移、不做彩色外发光。 */
.ts-card:hover { background: var(--bg-card); border-color: var(--border-light); }
.ts-card:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent); outline-offset: 1px; }

.ts-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 13px 15px;
}
/* min-width:0 让长板块名能省略而不是把涨跌幅挤出卡片 */
.ts-title { min-width: 0; }
.ts-title h3 {
  font-size: 14px;                 /* 15 → 14：名字不需要和数字争大小 */
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ts-desc {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 说明行里的涨跌数字降一档：它和主涨跌幅同色同重时会抢主角 */
.ts-desc .up, .ts-desc .down { font-weight: 500; opacity: .8; }
.ts-change {
  flex: 0 0 auto;
  font-size: 18px;                 /* 16 → 18：涨跌幅是这张卡的主角 */
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
/* 卡片右缘的 ›：默认不占视觉，hover/focus 时淡入，给"能点进去"一个不占位的提示 */
.ts-go {
  flex: 0 0 auto;
  font-size: 15px;
  line-height: 1;
  color: var(--text-muted);
  opacity: 0;
  transform: translateX(-3px);
  transition: opacity .14s, transform .14s, color .14s;
}
.ts-card:hover .ts-go,
.ts-card:focus-visible .ts-go { opacity: 1; transform: translateX(0); color: var(--accent); }

.ts-table { display: none; }
.ts-name { font-weight: 600; margin-right: 6px; }
.ts-code { font-size: 10px; color: var(--text-muted); }

/* ===== Board Detail Panel ===== */
.board-toolbar {
  display: flex; align-items: center; gap: 12px;
  padding: 6px 0 12px;
  flex-shrink: 0;
}
.back-btn {
  background: var(--bg-panel); border: 1px solid var(--border);
  color: var(--text-secondary); border-radius: var(--r-sm);
  padding: 6px 12px; font-size: 12px; cursor: pointer;
}
.back-btn:hover { border-color: var(--accent); color: var(--accent); }
.board-title-wrap { display: flex; align-items: baseline; gap: 10px; flex: 1; }
.board-title-wrap h2 { font-size: 16px; margin: 0; }
.board-change { font-size: 16px; font-weight: 700; }
.board-meta { font-size: 12px; color: var(--text-muted); }
.board-table-panel { flex: 1; min-height: 0; overflow-y: auto; }

/* ---- 板块走势图（2026-10-30）----
   固定在成分股表上方，高度写死不参与 flex 分配 —— 让它 flex:1 会把表格挤没，
   让表格 flex:1 才是对的（表格行数不定，图表高度固定 200 才好读）。 */
.board-chart-panel { flex: 0 0 auto; height: 200px; display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.bd-chart-head { display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.bd-tabs { display: flex; gap: 4px; }
.bd-tab { padding: 2px 10px; border-radius: var(--r-md); border: 1px solid var(--border-light); background: var(--bg-panel);
  color: var(--text-secondary); font-size: 11.5px; font-family: inherit; cursor: pointer; }
.bd-tab:hover { color: var(--accent); border-color: var(--accent); }
.bd-tab.active { color: var(--accent); border-color: var(--accent); background: var(--accent-glow); font-weight: 600; }
/* 口径说明：一定要能看见"历史是等权缩放、分时是合成" —— 否则用户会拿它跟同花顺 App 对点位 */
.bd-chart-note { font-size: 10.5px; color: var(--text-muted); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-chart { flex: 1; min-height: 0; position: relative; }
.bd-chart-empty { display: flex; align-items: center; justify-content: center; height: 100%; font-size: 12px; color: var(--text-muted); }
@media (max-width: 768px) {
  .board-chart-panel { height: 170px; }
  .bd-chart-note { display: none; }
}
.board-table { width: 100%; border-collapse: collapse; }
.board-table th, .board-table td { padding: 8px 12px; text-align: left; font-size: 12px; }
.board-table th { position: sticky; top: 0; background: var(--bg-panel); z-index: 2; }
.board-table tbody tr { cursor: pointer; }
.board-table tbody tr:hover { background: var(--bg-hover); }

/* ===== Watchlist Panel Table ===== */
.watchlist-table td { white-space: nowrap; }
.wt-name { font-weight: 600; }
.wt-code { color: var(--text-muted); font-size: 11px; }
.wt-price { font-weight: 700; }

/* ===== Chart Layout (3 panes) ===== */
.chart-wrapper-3 {
  display: flex;
  flex-direction: column;
  /* ⚠️ 这个下限是"图表区最少占多高"。它必须 ≥ 主图最小高 + 各副图最小高之和,
     否则容器比内容还矮 → 内容溢出压住下方 .ps-tabs(见 2026-10-04 bug)。
     现值验算: 主图 150 + 量 48 + MACD 56 = 254 < 340 ✅ 留足冗余;
     空间充裕时主图与副图会按 flex 长大到理想高(量 100 / MACD 120)。 */
  min-height: 340px;
  flex: 1 1 340px;
  position: relative;
}
.chart-wrapper-3 > div { position: relative; flex-shrink: 0; border-top: 1px solid var(--border); overflow: hidden; }
.chart-wrapper-3 > div:first-child { border-top: none; }
/* ⚠️ 主图/副图的高度必须"可收缩", 否则两图同开时会撑破容器并压住下方 .ps-tabs
   (2026-10-04 修的 bug: 成交量+MACD 同开 → 内容需 kline150+vol99+macd120=369px, 而
    .chart-wrapper-3 的 min-height 只有 300px → 溢出 69px 恰好盖住 subchart-tabs / ps-tabs)。
   做法: 主图 flex:1 1 auto 吃掉剩余空间; 副图 flex:0 1 <理想高> —— 空间充足时保持理想高,
   不足时按比例收缩(0 1 = 可缩不可长), 这样"开几个副图"都落在容器内。
   ⚠️ 不要用 flex:0 0(禁止收缩)+固定高, 那是本次 bug 的直接成因。 */
.chart-wrapper-3 > #klineChart { flex: 1 1 auto; min-height: 120px; background: var(--bg-dark); }
/* #volumeChart/#macdChart 已升级为 .sub-slot 内的 .sub-slot-chart(高度由槽位接管) */
.chart-wrapper-3 > #capitalChart { flex: 0 1 clamp(150px, 24vh, 220px); height: auto; min-height: 90px; background: var(--bg-dark); display: none; }

/* ===== 副图双槽位 (2026-11-03): 每槽一个指标, chip 条切换, ✕ 关闭 =====
   高度沿用旧铁律: 副图必须 flex:0 1 可收缩(2026-10-04 压住 .ps-tabs 的 bug 根因),
   两槽同开 = 220px 理想高, 与旧 vol100+macd120 持平, 不挤主图。 */
.chart-wrapper-3 > .sub-slot {
  display: flex;
  flex-direction: column;
  flex: 0 1 clamp(76px, 12vh, 112px);
  min-height: 72px; /* bar 24 + chart 净高 ≥48 */
  background: var(--bg-dark);
  border-top: 1px solid var(--border);
  overflow: hidden;
  position: relative;
}
.chart-wrapper-3 > .sub-slot.is-off { display: none; }
.sub-slot-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 4px 0 8px;
  flex-shrink: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.sub-slot-name {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
  letter-spacing: 0.2px;
}
.sub-slot-chips {
  display: flex;
  gap: 3px;
  overflow-x: auto;
  flex: 1;
  min-width: 0;
  scrollbar-width: none;
}
.sub-slot-chips::-webkit-scrollbar { display: none; }
.sub-chip {
  flex-shrink: 0;
  border: none;
  cursor: pointer;
  font-size: 10.5px;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  transition: background 0.12s, color 0.12s;
  font-family: inherit;
}
.sub-chip:hover:not(:disabled) { background: rgba(255, 255, 255, 0.08); color: var(--text-primary); }
.sub-chip.active {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-weight: 600;
}
/* 对侧槽位已激活: 点了会两槽交换 —— 用虚线底提示"可换槽"而不只是"已选中" */
.sub-chip.is-pair { color: var(--text-secondary); text-decoration: underline dotted; }
.sub-chip:disabled { opacity: 0.3; cursor: not-allowed; }
.sub-slot-close {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.sub-slot-close:hover { background: rgba(255, 69, 58, 0.18); color: var(--down); }
.sub-slot-chart { flex: 1; min-height: 0; position: relative; }

/* 指标浮层: 固定钉在各自图表容器左上角, 不随图表左右滚动移动, 也不遮挡最后一根K线
   ⚠️ .chart-wrapper-3 > div 会给所有 div 加 position:relative + border-top + overflow:hidden,
      浮层必须显式覆盖为 absolute 并去掉边框 */
.chart-wrapper-3 > .chart-legend,
.sub-slot > .chart-legend {
  position: absolute;
  left: 6px;
  z-index: 50;
  border-top: none;
  overflow: visible;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 6px;
  align-items: center;
  padding: 0;
  font-size: 11px;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  user-select: none;
  background: transparent;
}
.chart-legend .cl-item {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 1px 5px;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--bg-darkest) 75%, transparent);
  color: var(--text-secondary);
  white-space: nowrap;
}
.chart-legend .cl-item .cl-val { font-weight: 600; }

/* K线长按详情标签 (ID 选择器覆盖 .chart-wrapper-3 > div 的 position:relative) */
#klineTooltip {  position: absolute;
  z-index: 100;
  min-width: 150px;
  max-width: 210px;
  padding: 5px 9px;
  background: color-mix(in srgb, var(--bg-panel) 96%, transparent);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--r-sm);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-primary);
  pointer-events: none;
  user-select: none;
  backdrop-filter: blur(4px);
}
.kline-tooltip .kt-title {
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 3px;
  padding-bottom: 3px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 12px;
}
.kline-tooltip .kt-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 0;
}
.kline-tooltip .kt-label {
  color: var(--text-muted);
  font-size: 11px;
}
.kline-tooltip .kt-val {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12px;
  font-weight: 500;
}
.kline-tooltip .kt-val.up { color: var(--up); }
.kline-tooltip .kt-val.down { color: var(--down); }
.kline-tooltip .kt-hint {
  color: var(--text-muted);
  font-size: 10px;
  margin-left: 2px;
}

.subchart-tabs {
  display: flex;
  gap: 8px;
  padding: 8px 16px;
  background: var(--bg-dark);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.subchart-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 16px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
  font-family: inherit;
}
.subchart-tab .tab-icon { font-size: 14px; filter: grayscale(0.3); }
.subchart-tab:hover { background: rgba(255, 255, 255, 0.08); color: var(--text-primary); border-color: rgba(255, 255, 255, 0.15); }
.subchart-tab.active {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
}

.chart-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--text-muted);
  font-size: 14px;
}

/* ===== Stock Panel Layout ===== */
/* ⚠️ 2026-10-03 v4: .bottom-panels / .rating-panel 已不再作为 stock-detail 的顶层块 ——
   两者都收进 .panel-stack 的 .ps-body, 高度由 flex 分配(见文件尾部 "个股信息面板栈")。
   这里保留 .bottom-panels 的规则仅为兼容: 旧版它是 grid(盘口 | 核心指标)双列固定高,
   现在两块的宽度都交给 .ps-pane, 不再各自 clamp。 */
.stock-panel { padding: 12px; display: flex; flex-direction: column; min-height: 0; }
.stock-panel .bottom-panels {
  display: grid;
  grid-template-columns: clamp(268px, 24vw, 372px) minmax(0, 1fr);
  grid-template-rows: 100%;
  gap: var(--gutter);
  height: var(--h-bottom);
  flex-shrink: 0;
  overflow: hidden;
}
.stock-panel .bottom-panels > .panel {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
.indicator-grid.compact {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--border);
  padding: 1px;
  border-radius: var(--r-sm);
  overflow: hidden;
}
/* 桌面/平板: 行高按面板可用高度等分 —— 13 个指标 → 4 行恒等分,
   不再出现"内容 201px 塞进 135px, 最后一行(历史最低)被面板底边整行切掉 66px"。
   格子内部同时收紧到"最小可读"(实测单行需 28.8px, 1699 视口下每行可分到 36.6px)。
   手机端保持原样(横向 2 列 + 高度自适应, 不存在纵向放不下的问题)。 */
@media (min-width: 769px) {
  .indicator-grid.compact {
    grid-auto-rows: minmax(0, 1fr);
    flex: 1;
    min-height: 0;
  }
  .indicator-grid.compact .indicator-cell {
    padding: clamp(0px, 0.25vh, 3px) 10px;
    justify-content: center;
    gap: clamp(0px, 0.3vh, 3px);
    min-height: 0; min-width: 0;
    overflow: hidden;
  }
  /* 单格最小内容高 = 标签 12 + 值 15.6 + 上下内边距 ≈ 31px;
     1280×800 这类"矮视口"下面板只有 192px → 每行 37px, 仍留 6px 余量。 */
  .indicator-grid.compact .ic-label { font-size: 10px; line-height: 1.2; flex: 0 1 auto; min-height: 0; }
  .indicator-grid.compact .ic-value { font-size: 13px; line-height: 1.2; flex: 0 1 auto; min-height: 0; }
}

/* ===== 个股信息面板栈 (2026-10-03 v4) =====
   问题(用户 2026-10-03 反馈): 旧版把「盘口+核心指标」写死为 --h-bottom clamp(176px,24vh,252px),
   机构评级又当第 5 块往下堆(clamp(220px,52vh,560px)), 两者相加在 1699×828 这类视口下
   必然超过剩余高度 → 整页要向下滚一点才能看全评级面板。
   v4 方案: 4 个面板(盘口/核心指标/机构研报/F10)共用「一条 tab 栏 + 一块剩余高度」,
   同一时刻只显示 1 块, 高度由 flex 分配。这样:
     · 纵向: 面板栈拿走 stock-detail 的全部剩余高度, 内容永远在视口内 → 整页零滚动;
     · 横向: 盘口/指标/评级/ F10 宽度完全一致(同一块地方), 不再有"框宽窄不一"的别扭;
     · 点 tab 即切换, 不改变页面高度, 也不销毁图表(flex 重分配 → resizeCharts 即可)。 */
.panel-stack {
  /* ⚠️ 必须是**固定份额**(0 1 ...) 而不是 flex:1 1 auto ——
     用 1 1 auto 时, 这块的高度会被当前 tab 的内容撑/缩, 于是切 tab 时间上方的
     K 线跟着跳(实测同一视口下 340 / 342 / 353 三种高度, 1920 下评级面板更把
     图表压到 340 而盘口是 451)。用户要求"四块显示高度一致"。
     改成 0 1 clamp(...) 后: 高度只由视口决定, 与内容无关; 多出来的空间全部
     归 K 线区(flex:1 1 340px) → K 线/量/MACD 始终是版面主体。
     内容超出这块固定高度时由各 pane 自己内部滚动。 */
  flex: 0 1 clamp(180px, 24vh, 300px);
  min-height: 176px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: hidden;
}
.ps-tabs {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  /* 分段控件: 4 等分, 宽度按容器比例分配(不写死 px) */
  overflow: hidden;
}
.ps-tab {
  flex: 1 1 0;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s;
}
.ps-tab:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-light); }
.ps-tab.active {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  color: var(--accent);
  font-weight: 600;
}
/* 徽章: 让"这个 tab 里有内容/有多少家机构"一眼可见, 不用点进去才发现是空的。
   没数据时徽章为空 → 不占位(不留一个空圆圈)。 */
.ps-badge {
  font-style: normal;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 16%, transparent);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.ps-badge:empty { display: none; }
.ps-badge.up { background: var(--up-bg); color: var(--up); }
.ps-badge.down { background: var(--down-bg); color: var(--down); }
.ps-tab.active .ps-badge { background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--accent); }

/* 面板容器: 每个 ps-pane 都撑满这块剩余高度(不是按内容撑开),
   于是"内容比框高"这种塞不进的情况从结构上就不存在 —— 超出的部分在面板内滚。 */
.ps-body {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  display: flex;
  flex-direction: column;
}
/* 面板栈内各 pane 一律是 flex 项, 用 display:flex 而不是 block ——
   block 会按内容撑高, 在面板栈里就变成"内容比框高" → 又回到整页滚动。
   ⚠️ 这里必须显式写 display:flex, 而不是靠上面的 `.panel{display:flex}`:
      `.ps-body > .ps-pane` 的优先级 (0,2,0) 高于 `.panel` (0,1,0) 的 display:none,
      所以宽视口下隐藏 F10 tab 时用 `display:none !important` 会在 JS 切 tab 时
      被内联 style 反复覆盖 → 表现成"切到 F10 一片空白"。改用属性选择器控制,
      显示与否只由 JS 的内联 style 决定(单一真源)。 */
.ps-body > .ps-pane {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* 盘口宽度交回容器: 旧的 clamp(280px,26vw,380px) 是"侧栏小窗"时代的尺寸,
   进面板栈后必须让轨道决定宽度, 否则与"核心指标"面板宽度不一致(用户说的"对不齐")。 */
.ps-body > .order-book-panel { width: auto; min-width: 0; }
.ps-body > .trade-info-panel { width: auto; min-width: 0; }
.ps-body > .finance-panel { width: auto; min-width: 0; }

/* 桌面端: 每块内部都必须能"自己消化"超出高度的内容, 不能把面板栈撑高。
   ① 盘口: 5 档等分剩余高度(旧版 .ob-row flex:1 1 0 的意图), 内容少时也不塌成 0;
   ② 评级: 明细表可能十几行 → .rating-body 自己滚;
   ③ F10 : 长文本 → .f10-body 自己滚;
   ④ 财务: 18 项双列 ≈ 9 行, 窄视口下放不下 → .finance-body 自己滚。 */
@media (min-width: 769px) {
  .ps-body > .ps-pane { overflow: hidden; }
  .ps-body > .rating-panel > .rating-body { min-height: 0; }
  .ps-body > .f10-panel > .f10-body { min-height: 0; }
  .ps-body > .trade-info-panel > .indicator-grid.compact { min-height: 0; }
  .ps-body > .finance-panel > .finance-body { min-height: 0; }
}

/* ===== 财务指标面板 (2026-10-22) =====
   版面照东财 App「财务指标」: 左标签 / 右数值, 数值下面一行小字写口径。
   为什么双列而不是单列: 18 项单列要 18 行, 面板只有约 1/3 屏高 → 必须滚;
   双列压到 9 行, 大多数视口一屏看完, 只有很窄的手机端才需要滚。
   涨红跌绿只用在"同比"类(由 JS 给 .up/.down), 其余指标不用颜色 ——
   估值/利润率本身没有方向性, 上色反而会被误读成"利好/利空"。 */
.finance-body {
  flex: 1 1 auto;
  min-height: 0;
  /* 这块**就是**本面板的滚动容器(kb铁律 63: 面板自己是滚动容器时,
     overflow 只能给 auto, 不许改成 visible, 否则超出内容被父级裁掉且全页零滚动) */
  overflow-y: auto;
  padding: 2px 4px 6px 2px;
}
/* 列数交给容器自己算(auto-fill + 最小列宽), 不写死 2/3/4 列 ——
   因为这块面板的宽度随视口变化很大(有 F10 侧栏时 780px, 窄屏时 360px),
   固定列数要么在宽屏浪费横向空间, 要么在窄屏把标签挤成省略号。
   150px 一列: 781px → 5 列(4 行), 620px → 4 列(5 行), 390px → 2 列(9 行, 与东财 App 一致)。 */
/* ⚠️ 2026-10-22 修「全屏显得太空」: 原来只有 minmax(142px, 1fr), 宽度一涨就无脑加列 ——
   2560×1440 实测排到 **9 列 × 2 行**, 只占面板高度的 30%(底部空白 154px / 59%);
   而同一时刻盘口空白 2%、核心指标 8%, 只有财务这块是"一条字带顶在空盒子上"。
   现在给列数加**上限 6**: 轨道下限取 max(142px, (100% - 5×12px)/6)
     · 宽度 ≤ 894px → 142px 更大 → 与改前完全一致(已验证过的 5 列版面不动)
     · 宽度 >  894px → 1/6 宽更大 → 恒 6 列, 多出来的宽度只把格子拉宽, 不再新增列
   配合下面的行高等分, 18 项在宽屏恒为 3 行并撑满面板高度。 */
.fin-grid {
  display: grid;
  /* 列宽是"能排几列"的唯一旋钮, 同时决定标签会不会被省略号吃掉:
     118px → 6 列但 9 个标签截断(每股收益(计…);实测过, 不可用)
     148px → 781px 宽只有 4 列 = 5 行, 矮视口必须滚
     142px → 标签零截断的**下限**(781px 宽时正好 5 列) ← 现值
     620px 宽 → 4 列; 390px(手机) → 2 列, 与东财 App 一致 */
  grid-template-columns: repeat(auto-fill, minmax(max(142px, calc((100% - 60px) / 6)), 1fr));
  /* 行高按面板**可用高度等分**(与「核心指标」`.indicator-grid.compact` 同一套做法):
     min-content 兜底 —— 面板太矮时行不会被压扁到丢内容, 而是整块溢出由 .finance-body 滚动。 */
  grid-auto-rows: minmax(min-content, 1fr);
  align-content: stretch;
  min-height: 100%;
  gap: 5px 12px;
}
/* 口径小字退场模式: 由 fitFinanceHints() 按真实几何打类(见 app.js) ——
   矮视口下宁可少一行解释, 也要让 18 个数字全部露出。解释仍在每格 title 里。 */
.finance-body.fin-tight .fin-hint { display: none; }
.fin-item {
  min-width: 0;
  /* 行被拉高时内容**垂直居中** —— 否则数字全贴顶、下面留一条空带,
     看起来像"只渲染了一半"(实测 2560×1440 下每格 70px 高、内容只有 34px)。 */
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.fin-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.fin-label {
  color: var(--text-secondary);
  font-size: 11.5px;
  line-height: 1.4;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fin-val {
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}
.fin-val.up { color: var(--up); }
.fin-val.down { color: var(--down); }
.fin-hint {
  color: var(--text-muted);
  font-size: 10px;
  line-height: 1.25;
  margin-top: 0;
  /* 口径说明收成**一行**。
     原先是两行, 单格 45px 高 × 9 行 = 401px, 而面板栈固定只有 ~170px —— 必然要滚,
     而用户要求"K 线仍是主体、五块 tab 高度一致", 不能再靠压 K 线腾空间。
     折中: 一行 + 完整的 口径 放进 title 悬停提示(item 上), 信息没丢, 版面省一半。 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ⚠️ 这里**故意不做**"打开财务指标就把 K 线压矮"的版面调整。
   曾经试过 .fin-focus 把 .chart-wrapper-3 收到 228px 来给 18 项腾高度, 但:
   ① K 线/成交量/MACD 必须始终是版面主体(用户明确要求);
   ② 5 块 tab 若各自改高度, 切 tab 时上方图表会跳动, 高度就不一致了。
   所以高度分配对所有 tab 完全一致, 财务面板靠"多列 + 单行口径"自己塞进这块固定高度。 */

.fin-loading,
.fin-empty {
  padding: 14px 6px;
  color: var(--text-muted);
  font-size: 12px;
}
/* 5 个 tab 之后每格变窄: 中等视口先收 padding/字号, 避免文字被 overflow:hidden 裁掉。
   ⚠️ 手机端(<=768px)另有规则把 .ps-tabs 改成横向滚动, 不用在这里救。 */
@media (max-width: 1280px) and (min-width: 769px) {
  .ps-tab { padding: 6px 6px; font-size: 11.5px; gap: 4px; }
}

/* 手机端: 面板栈不再分配剩余高度 —— .ps-pane 撑成内容高、由页面(.main-content)统一滚。
   所以这里必须把 .finance-body 的 overflow 放开成 visible: 否则会出现
   "面板内部一个滚动条 + 页面一个滚动条"的双层滚动, 手指在面板里滑不动(本项目踩过)。 */
@media (max-width: 768px) {
  .finance-body { overflow-y: visible; }
  .fin-grid { gap: 8px 12px; }
  .fin-label { font-size: 11.5px; }
  .fin-val { font-size: 13px; }
  .fin-hint { font-size: 10px; }
}

.ps-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 12px;
  padding: 16px;
  text-align: center;
}

/* ==== 窄视口降级 (<=1280px) ====
   三栏(min 176 + min 0 + 268)在 1280 宽下只剩约 748px 给详情区, 而"核心指标"
   网格要 4 列 × min 内容宽 ≈ 620px、评级面板要 3 栏 ≈ 790px —— 宽度不够就必然
   出现"文字被压窄/被裁", 那正是本次要根治的。做法: 收掉 F10 独立侧栏,
   三栏比例退成 2 栏(列表 15 : 详情 85), 详情区多出 268px, F10 内容移入第 4 个 tab。
   ⚠️ 断点必须大于 min-list + 详情最小宽 + min-f10 —— 取 1280px。
   ⚠️ 数值与下方文件末尾的同名断点重复声明, 那是刻意的: 旧版 CSS 在文件更后面
      (见 @media (max-width:1100px) 的 .stock-panel-layout 两栏规则) 会把这些覆盖掉,
      而按"先写基础、后写覆盖"的顺序无法在此处胜出 —— 真正的生效声明统一放在文件末尾。 */

/* F10 宿主切换 (2026-10-03 v4):
   宽视口(>1280px): F10 走右侧独立栏 → 详情区第 4 个 tab 的入口隐藏
                    (否则"点 F10 没反应", 因为那块内容在侧栏里)。
   窄视口(<=1280px): 侧栏整体 display:none, F10 内容移入第 4 个 tab。
   两份 DOM 由 renderF10() 同时写入, 永远不会出现"一边加载好了另一边空着"。
   ⚠️ 可见性只有两个真源, 不要第三处:
      · 左侧栏  → 文件末尾断点里的 `.f10-sidebar{display:none}`
      · 面板栈  → JS 的 `box.style.display` (setPanelStack)
      tab 按钮本身用 `visibility` 隐藏而不是 display:none —— 因为面板栈是 4 等分,
      留一个不可见的占位比变成 3 等分更稳定(切视口时不会跳来跳去)。 */
#f10AsidePanel { display: none; }
@media (min-width: 1281px) {
  .ps-tab[data-ps="f10"] { visibility: hidden; pointer-events: none; }
}

/* ===== Stock Panel: browser sidebar + detail ===== */
.stock-panel-layout {
  display: grid;
  /* 比例式三栏: 15 : 66.5 : 18.5 (fr), 各自带"内容实测最小宽"兜底。
     旧写法 clamp(190px,13vw,270px) / clamp(230px,16vw,310px) 的问题是下限口径不齐 ——
     1440 视口下列表栏落到下限 190、F10 栏落到下限 230, 而中部拿走剩余全部,
     三栏比例在断点附近突变, F10 里的股东名/公司全名就被压到截断。 */
  grid-template-columns: minmax(var(--min-list), var(--fr-list))
                         minmax(0, var(--fr-main))
                         minmax(var(--min-f10), var(--fr-f10));
  gap: var(--gutter);
  flex: 1;
  min-height: 0;
}
.stock-panel-layout.f10-collapsed {
  grid-template-columns: minmax(var(--min-list), var(--fr-list)) minmax(0, 85fr) 26px;
}

/* F10 right sidebar */
.f10-sidebar {
  display: flex;
  flex-direction: row-reverse;
  gap: 0;
  min-height: 0;
  overflow: hidden;
}
.f10-sidebar .f10-toggle {
  width: 26px;
  flex-shrink: 0;
  box-sizing: border-box;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  letter-spacing: 2px;
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 6px 0 0 6px;
  border-right: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 0;
  user-select: none;
}
.f10-sidebar .f10-toggle:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.f10-sidebar .f10-panel {
  flex: 1;
  min-width: 0;
  min-height: 0;
  border-radius: 6px 0 0 6px;
  display: flex;
  flex-direction: column;
}
.f10-sidebar.collapsed .f10-panel { display: none; }
.f10-sidebar.collapsed .f10-toggle {
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
}
.f10-sidebar .side-stack {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.f10-sidebar.collapsed .side-stack { display: none; }

.stock-browser {
  display: flex;
  flex-direction: column;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  min-height: 0;
}
.sb-toolbar {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-shrink: 0;
}
.sb-toolbar-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* 选股列表折叠开关:仅移动端显示(桌面端隐藏) */
.sb-toggle { display: none; }
.sb-search {
  width: 100%;
  background: var(--bg-dark);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-size: 12px;
  padding: 8px 10px;
  outline: none;
}
.sb-search:focus { border-color: var(--accent); }
.sb-meta { font-size: 11px; color: var(--text-muted); }
.sb-list {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}
.sb-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 7px 12px;
  cursor: pointer;
  border-left: 2px solid transparent;
  transition: background 0.12s;
}
.sb-item:hover { background: var(--bg-hover); }
.sb-item.active {
  background: var(--bg-hover);
  border-left-color: var(--accent);
}
.sb-info { display: flex; flex-direction: column; min-width: 0; }
.sb-name {
  font-size: 12px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 110px;
}
.sb-code { font-size: 10px; color: var(--text-muted); }
.sb-quote { display: flex; flex-direction: column; align-items: flex-end; }
.sb-price { font-size: 12px; font-weight: 600; }
.sb-chg { font-size: 10px; }
.sb-loading {
  padding: 14px;
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
}
.stock-detail {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  min-height: 0;
}
@media (max-width: 1100px) {
  /* F10 收起后只剩两栏, 仍走同一套比例(15 : 66.5) */
  .stock-panel-layout { grid-template-columns: minmax(var(--min-list), var(--fr-list)) minmax(0, var(--fr-main)); }
  .f10-sidebar { display: none; }
}

/* ===== Watchlist add / remove controls ===== */
.wl-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: 12px;
  padding: 4px 10px;
  cursor: pointer;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
  white-space: nowrap;
}
.wl-toggle:hover { border-color: var(--accent); color: var(--accent); }
.wl-toggle.in { border-color: color-mix(in srgb, var(--gold) 50%, transparent); color: var(--gold); }
.wl-toggle.in:hover { border-color: var(--down); color: var(--down); }
.wl-toggle-star { font-size: 13px; line-height: 1; }

.wl-remove {
  margin-left: 6px;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 12px;
  cursor: pointer;
  opacity: 0;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
  padding: 2px 4px;
  line-height: 1;
  flex-shrink: 0;
}
.watchlist-item:hover .wl-remove { opacity: 1; }
.wl-remove:hover { color: var(--down); }

.wt-remove {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: 11px;
  padding: 3px 8px;
  cursor: pointer;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
  white-space: nowrap;
}
.wt-remove:hover { border-color: var(--down); color: var(--down); }

/* ===== News enhancements ===== */
.news-item.clickable { cursor: pointer; transition: background 0.15s; }
.news-item.clickable:hover { background: var(--bg-hover); }
.news-summary {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 3px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ===== Modal ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--bg-darkest) 75%, transparent);
  backdrop-filter: blur(4px);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.modal-overlay.open { display: flex; }
.modal-box {
  width: min(720px, 92vw);
  max-height: 85vh;
  background: var(--bg-panel);
  border: 1px solid var(--border-light);
  border-radius: var(--r-md);
  padding: 24px 28px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.modal-header { display: flex; justify-content: space-between; align-items: center; }
.modal-tag {
  background: var(--accent-glow);
  color: var(--accent);
  font-size: 12px;
  padding: 3px 10px;
  border-radius: var(--r-md);
}
.modal-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 16px;
  cursor: pointer;
  padding: 4px 8px;
}
.modal-close:hover { color: var(--text-primary); }
.modal-title { font-size: 19px; line-height: 1.4; }
.modal-meta {
  display: flex;
  gap: 12px;
  font-size: 12px;
  color: var(--text-muted);
  align-items: center;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.modal-content {
  overflow-y: auto;
  font-size: 13px;
  line-height: 1.9;
  color: var(--text-secondary);
  white-space: pre-line;
  padding-right: 6px;
}
.modal-footer { padding-top: 8px; border-top: 1px solid var(--border); }

/* ===== 资讯「关联个股 / 所属板块」 =====
   放在 meta 与正文之间: 用户点开资讯第一眼就能看到"讲的是谁", 不用读完正文再滚回去找。
   ⚠️ 没有关联时整块 display:none —— 不许留空标题(会让人以为"还没加载完", kb铁律 15/26)。 */
.modal-rel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  padding: 2px 0 10px;
  border-bottom: 1px dashed var(--border);
}
.modal-rel[hidden] { display: none; }
.rel-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.rel-k {
  font-size: 11px;
  color: var(--text-muted);
  flex-shrink: 0;
}
.rel-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 2px 9px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-light);
  background: var(--bg-dark);
  color: var(--text-primary);
  font-size: 12px;
  line-height: 1.5;
  cursor: pointer;
  font-family: inherit;
  transition: border-color .15s, color .15s, background .15s;
  max-width: 100%;
}
.rel-chip:hover { border-color: var(--accent); color: var(--accent); }
.rel-chip .rel-code {
  font-size: 10.5px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.rel-chip:hover .rel-code { color: var(--accent); }
/* 板块 chip 用青色描边区分"这不是个股" —— 两者点击后去的是完全不同的页面,
   只靠文字区分太慢(个股是名称+6位数字, 板块是名称+BK 码, 扫一眼看不出规矩)。 */
.rel-chip.board { border-color: color-mix(in srgb, var(--cyan) 35%, transparent); }
.rel-chip.board:hover { border-color: var(--accent); }

/* Abnormal Analysis Modal */
.modal-box-wide { width: min(840px, 94vw); }
.modal-box-sm { width: min(380px, 90vw); }

/* 自选删除确认弹窗 */
.wl-confirm-text {
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-secondary);
  text-align: center;
  padding: 6px 0 2px;
}
.wl-confirm-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  padding-top: 14px;
}
.wl-confirm-btn {
  min-width: 96px;
  padding: 8px 18px;
  border-radius: var(--r-sm);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  border: 1px solid var(--border);
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.wl-confirm-btn.cancel {
  background: var(--bg-panel);
  color: var(--text-secondary);
}
.wl-confirm-btn.cancel:hover { border-color: var(--text-muted); color: var(--text-primary); }
.wl-confirm-btn.danger {
  background: color-mix(in srgb, var(--up) 14%, transparent);
  border-color: color-mix(in srgb, var(--up) 35%, transparent);
  color: var(--up);
}
.wl-confirm-btn.danger:hover {
  background: color-mix(in srgb, var(--up) 24%, transparent);
  border-color: var(--up);
}
.aa-section { margin-bottom: 16px; }
.aa-section-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.aa-items { display: flex; flex-direction: column; gap: 6px; }
.aa-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-secondary);
}
.aa-item-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-top: 7px;
  flex-shrink: 0;
}
.aa-item-dot.up { background: var(--up); }
.aa-item-dot.down { background: var(--down); }
.aa-item-dot.warn { background: var(--gold); }
.aa-item-dot.info { background: var(--accent); }
.aa-item-note {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 11px;
  white-space: nowrap;
}
.aa-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}
.aa-tag {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
}
.aa-tag.up { background: color-mix(in srgb, var(--up) 12%, transparent); color: var(--up); border-color: color-mix(in srgb, var(--up) 25%, transparent); }
.aa-tag.down { background: color-mix(in srgb, var(--down) 12%, transparent); color: var(--down); border-color: color-mix(in srgb, var(--down) 25%, transparent); }
.aa-tag.warn { background: color-mix(in srgb, var(--gold) 12%, transparent); color: var(--gold); border-color: color-mix(in srgb, var(--gold) 25%, transparent); }
.aa-tag.info { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 25%, transparent); }

/* 走势分析弹窗行情信息条 */
.aa-quote-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.aaq-item {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
}
.aaq-label { color: var(--text-muted); }
.aaq-val { color: var(--text-primary); font-weight: 600; }
.aaq-val.up { color: var(--up); }
.aaq-val.down { color: var(--down); }
.aaq-note { color: var(--text-muted); font-weight: 400; font-size: 11px; }
.aa-empty {
  color: var(--text-muted);
  font-size: 12px;
  text-align: center;
  padding: 20px 0;
}

/* ===== 站内文章阅读 (新闻正文) ===== */
.article-p {
  margin: 0 0 12px;
  text-indent: 2em;
  white-space: normal;
}
.article-imgs { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 12px; }
.article-img { max-width: 100%; border-radius: var(--r-sm); border: 1px solid var(--border); }
.article-src-link {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  text-align: right;
}
.article-src-link a { color: var(--accent); font-size: 12px; text-decoration: none; }
.article-src-link a:hover { text-decoration: underline; }

/* ===== PDF 内嵌预览 ===== */
.pdf-box { width: min(900px, 94vw); padding: 18px 20px 14px; }
.pdf-title {
  flex: 1;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.pdf-viewer {
  overflow: auto;
  min-height: 200px;
  max-height: 66vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--bg-hover, rgba(255,255,255,0.03));
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 12px;
}
#pdfCanvas { border-radius: var(--r-xs); box-shadow: 0 4px 18px rgba(0,0,0,0.45); max-width: 100%; }
#pdfLoading, #pdfError { padding: 40px 0; font-size: 12px; }
#pdfError a { color: var(--accent); }
.pdf-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding-top: 10px;
  font-size: 12px;
  color: var(--text-secondary);
}
.pdf-nav-btn {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-secondary);
  font-size: 12px;
  padding: 4px 12px;
  cursor: pointer;
  font-family: inherit;
}
.pdf-nav-btn:hover { color: var(--text-primary); border-color: var(--accent); }

.btn-primary {
  background: var(--accent);
  color: #121214;
  border: none;
  padding: 8px 18px;
  border-radius: var(--r-sm);
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
}
.btn-primary:hover { opacity: 0.9; }

/* ===== V3: Live market panel ===== */
.market-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.search-input {
  flex: 0 1 320px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-size: 13px;
  padding: 8px 14px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.2s;
}
.search-input:focus { border-color: var(--accent); }
.board-select-custom {
  position: relative;
  display: inline-flex;
  font-size: 13px;
  user-select: none;
}
.board-select-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 92px;
  padding: 7px 10px 7px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.board-select-trigger:hover {
  border-color: color-mix(in srgb, var(--cyan) 50%, transparent);
}
.board-select-custom.open .board-select-trigger {
  border-color: var(--accent);
}
.board-select-text { white-space: nowrap; }
.board-select-arrow {
  font-size: 11px;
  color: var(--text-muted);
  transition: transform 0.2s;
}
.board-select-custom.open .board-select-arrow {
  transform: rotate(180deg);
}
.board-select-options {
  position: absolute;
  top: calc(100% + 5px);
  left: 0;
  z-index: 100;
  min-width: 120px;
  margin: 0;
  padding: 5px;
  list-style: none;
  background: var(--bg-panel);
  border: 1px solid color-mix(in srgb, var(--cyan) 45%, transparent);
  border-radius: var(--r-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04) inset;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.18s, transform 0.18s, visibility 0.18s;
}
.board-select-custom.open .board-select-options {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.board-select-option {
  padding: 7px 12px;
  border-radius: var(--r-sm);
  color: var(--text-primary);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.board-select-option:hover,
.board-select-option.active {
  background: color-mix(in srgb, var(--cyan) 14%, transparent);
  color: var(--accent);
}
.board-select-option.active {
  font-weight: 600;
}
.board-select {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-size: 13px;
  padding: 8px 10px;
  font-family: inherit;
  outline: none;
  cursor: pointer;
}
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: color-mix(in srgb, var(--down) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--down) 35%, transparent);
  color: var(--up);
  font-size: 11px;
  padding: 3px 10px;
  border-radius: var(--r-md);
}
.live-badge.small { padding: 1px 8px; font-size: 10px; margin-left: 6px; }
.live-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--up);
  animation: pulse 1.6s infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}
.market-meta { font-size: 12px; color: var(--text-muted); flex: 1; text-align: right; }
.market-meta b { color: var(--text-primary); }
.refresh-btn {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 12px;
  padding: 7px 14px;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-family: inherit;
  transition: color .2s, background-color .2s, border-color .2s, opacity .2s, transform .2s;
}
.refresh-btn:hover { border-color: var(--accent); color: var(--accent); }

/* ===== 股票筛选按钮 + 面板 ===== */
.filter-wrap {
  position: relative;
  display: inline-flex;
  font-size: 13px;
  user-select: none;
}
.filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.2s, box-shadow 0.2s, color 0.2s;
}
.filter-btn:hover { border-color: color-mix(in srgb, var(--cyan) 50%, transparent); color: var(--text-primary); }
.filter-btn.active {
  border-color: var(--accent);
  color: var(--accent);
}
.filter-icon { font-size: 13px; line-height: 1; }
.filter-count {
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--bg-darkest);
  font-size: 11px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
  display: none;
}
.filter-btn.active .filter-count { display: inline-block; }
.filter-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 120;
  width: 262px;
  padding: 10px 12px 12px;
  background: var(--bg-panel);
  border: 1px solid color-mix(in srgb, var(--cyan) 45%, transparent);
  border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04) inset;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.18s, transform 0.18s, visibility 0.18s;
}
.filter-wrap.open .filter-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.filter-panel-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 8px;
}
.filter-panel-sub {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
  margin-top: 2px;
}
.filter-opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 8px;
  border-radius: var(--r-sm);
  transition: background 0.15s;
}
.filter-opt:hover { background: color-mix(in srgb, var(--cyan) 8%, transparent); }
.filter-opt-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-primary);
  cursor: pointer;
  flex: 1;
}
.filter-opt-label input[type="checkbox"] {
  width: 15px;
  height: 15px;
  accent-color: var(--accent);
  cursor: pointer;
  flex-shrink: 0;
}
.filter-opt-label input[type="checkbox"]:checked + span { color: var(--accent); }
.filter-newdays {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}
.filter-newdays input[type="number"] {
  width: 52px;
  padding: 3px 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  text-align: center;
  outline: none;
}
.filter-newdays input[type="number"]:focus { border-color: var(--accent); }
.filter-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.filter-reset, .filter-done {
  padding: 6px 14px;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: color .2s, background-color .2s, border-color .2s, opacity .2s, transform .2s;
}
.filter-reset {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.filter-reset:hover { border-color: var(--down); color: var(--down); }
.filter-done {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: var(--bg-darkest);
  font-weight: 600;
}
.filter-done:hover { filter: brightness(1.1); }

.market-table-panel { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto; }

/* ===== Hot stock ranking sidebar (全部股票面板左侧) ===== */
.market-layout {
  display: flex;
  gap: 12px;
  flex: 1;
  min-height: 0;
  align-items: stretch;
}
.market-side {
  width: clamp(200px, 16vw, 270px);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}
.hot-stock-panel {
  flex: 1.15;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.channel-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.hot-stock-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--border);
}
.hot-stock-title { font-size: 14px; font-weight: 700; }
.hot-stock-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.hs-tab {
  flex: 1 1 calc(50% - 2px);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: 11px;
  padding: 4px 0;
  cursor: pointer;
  transition: color .2s, background-color .2s, border-color .2s, opacity .2s, transform .2s;
  font-family: inherit;
}
.hs-tab:hover { border-color: var(--border-light); color: var(--text-secondary); }
.hs-tab.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.hot-stock-meta {
  font-size: 11px;
  color: var(--text-muted);
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
}
.hot-stock-list {
  flex: 1;
  overflow-y: auto;
  padding: 4px 0;
}
.hs-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  cursor: pointer;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
  font-size: 12px;
}
.hs-row:last-child { border-bottom: none; }
.hs-row:hover { background: var(--bg-hover); }
.hs-rank {
  flex-shrink: 0;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  color: var(--text-muted);
}
.hs-rank.r1 { background: var(--up); border-color: var(--up); color: var(--on-accent); }
.hs-rank.r2 { background: color-mix(in srgb, var(--up) 75%, transparent); border-color: transparent; color: #fff; }
.hs-rank.r3 { background: color-mix(in srgb, var(--up) 45%, transparent); border-color: transparent; color: #fff; }
.hs-rank.cu1 { background: var(--up); border-color: transparent; color: var(--on-accent); }
.hs-rank.cu2 { background: color-mix(in srgb, var(--up) 70%, transparent); border-color: transparent; color: #fff; }
.hs-rank.cu3 { background: color-mix(in srgb, var(--up) 40%, transparent); border-color: transparent; color: #fff; }
.hs-rank.cd1 { background: var(--down); border-color: transparent; color: #121214; }
.hs-rank.cd2 { background: color-mix(in srgb, var(--down) 70%, transparent); border-color: transparent; color: #fff; }
.hs-rank.cd3 { background: color-mix(in srgb, var(--down) 40%, transparent); border-color: transparent; color: #fff; }
.hs-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.hs-name {
  color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hs-code { font-size: 10px; color: var(--text-muted); }
.hs-val { flex-shrink: 0; font-weight: 600; font-variant-numeric: tabular-nums; }

.market-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.market-table th {
  text-align: left; padding: 9px 12px; color: var(--text-muted);
  font-weight: 500; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; background: var(--bg-panel); z-index: 2;
  white-space: nowrap;
}
.market-table th.sortable { cursor: pointer; user-select: none; }
.market-table th.sortable:hover { color: var(--text-primary); }
.market-table th.sortable.active { color: var(--accent); }
.sort-arrow { font-size: 9px; margin-left: 2px; }
.market-table td {
  padding: 7px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
  white-space: nowrap;
}
.market-table tbody { display: table-row-group; }
.market-table thead, .market-table tbody tr {
  display: table; width: 100%; table-layout: fixed;
}
.market-table tbody tr { cursor: pointer; }
.market-table tbody tr:hover { background: var(--bg-hover); }
.mkt-badge {
  font-size: 10px; padding: 2px 7px; border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--cyan);
}
.mkt-badge.沪 { background: color-mix(in srgb, var(--up) 12%, transparent); color: var(--up); }
.mkt-badge.北 { background: color-mix(in srgb, var(--purple) 15%, transparent); color: var(--purple); }

/* 市场大列表: 上次走势评级徽标 */
.mkt-rating {
  display: inline-block;
  font-size: 10px;
  padding: 2px 7px;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--cyan);
  white-space: nowrap;
}
.mkt-rating.up { background: color-mix(in srgb, var(--up) 12%, transparent); color: var(--up); }
.mkt-rating.down { background: color-mix(in srgb, var(--down) 12%, transparent); color: var(--down); }
.mkt-rating.info { background: color-mix(in srgb, var(--gold) 12%, transparent); color: var(--gold); }
.mkt-rating.none { background: color-mix(in srgb, var(--text-muted) 10%, transparent); color: var(--text-muted); }
.loading-cell { text-align: center; padding: 30px 0 !important; color: var(--text-muted); }

.pagination {
  display: flex; align-items: center; justify-content: center;
  gap: 4px; padding: 10px 0; border-top: 1px solid var(--border);
  flex-shrink: 0;
}
.pg-btn {
  background: var(--bg-panel); border: 1px solid var(--border);
  color: var(--text-secondary); font-size: 12px;
  padding: 5px 12px; border-radius: var(--r-sm); cursor: pointer;
  font-family: inherit; transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.pg-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.pg-btn.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.pg-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.pg-ellipsis { color: var(--text-muted); padding: 0 4px; }


/* ===== 通道股票「查看全部」弹窗 ===== */
.hot-stock-title-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.chf-btn {
  margin-left: 0;
  flex-shrink: 0;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: var(--r-md);
  padding: 2px 9px;
  font-size: 11px;
  line-height: 1.45;
  cursor: pointer;
  transition: opacity 0.15s;
}
.chf-btn:hover { opacity: 0.85; }
.channel-full-box { width: min(560px, 92vw); }
.chf-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.chf-toolbar .hot-stock-tabs { display: flex; gap: 6px; }
.chf-search { flex: 1; min-width: 160px; }
.chf-sortbar { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-top: 1px solid var(--border); flex-wrap: wrap; }
.chf-sort-label { font-size: 11px; color: var(--text-muted); margin-right: 2px; }
.chf-sort-btn {
  font-size: 11px; padding: 2px 9px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: transparent;
  color: var(--text-muted); cursor: pointer; transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.chf-sort-btn:hover { color: var(--text); border-color: var(--text-muted); }
.chf-sort-btn.active { color: var(--up); border-color: var(--up); background: color-mix(in srgb, var(--down) 8%, transparent); }
.chf-meta { font-size: 12px; color: var(--text-muted); padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.chf-list { overflow-y: auto; flex: 1; min-height: 120px; max-height: 62vh; }

/* ============================================================
   Mobile / small-screen adaptation
   All rules scoped inside @media (max-width: 768px) — desktop
   (>= 769px) is completely unaffected.
   ============================================================ */
@media (max-width: 768px) {
  html, body { overscroll-behavior-y: contain; }

  /* ---- Top bar: 2 rows. Row1: brand + ticker + clock; Row2: nav tabs ---- */
  .top-bar {
    height: auto;
    flex-wrap: wrap;
    gap: 5px 10px;
    padding: 6px 10px;
    padding-bottom: calc(6px + env(safe-area-inset-top, 0px));
  }
  .brand { order: 1; flex-shrink: 0; }
  .brand-sub { display: none; }
  .brand-text { font-size: 16px; }
  .market-ticker {
    order: 2;
    flex: 1;
    min-width: 0;
    gap: 12px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .market-ticker::-webkit-scrollbar { display: none; }
  .ticker-item { flex-shrink: 0; }
  .top-actions { order: 3; flex-shrink: 0; gap: 8px; margin-left: auto; }
  #marketStatus { display: none; } /* keep the status dot, drop the text */
  .clock { font-size: 13px; }
  .nav-tabs {
    order: 4;
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .nav-tabs::-webkit-scrollbar { display: none; }
  .nav-tab { flex-shrink: 0; padding: 7px 13px; font-size: 13px; min-height: 36px; }

  /* ---- Layout: hide left watchlist sidebar, content full width ---- */
  .sidebar-left { display: none; }
  .main-content { padding: 8px; gap: 8px; }

  /* ---- Panorama ---- */
  .panorama-grid { grid-template-columns: 1fr; }
  .panorama-news { grid-column: span 1; }
  .index-cards { gap: 8px; }
  .index-card { flex: 1 1 calc(50% - 4px); min-width: 0; padding: 10px 12px; }
  .ic-price { font-size: 21px; }
  .market-stats-strip { gap: 8px; }
  .ms-item { padding: 8px 12px; gap: 8px; }
  .ms-label { font-size: 11px; }
  .ms-val { font-size: 13px; }

  /* ---- A股涨跌家数: 手机端压缩间距, 家数仍要一眼可读 ---- */
  .breadth-panel { padding: 8px 10px 10px; }
  .bp-bar { height: 12px; }
  .bp-legend { gap: 5px 14px; margin-top: 7px; }
  .bp-cell { gap: 4px; }
  .bp-cell-num { font-size: 16px; }
  .bp-cell-pct { display: none; }       /* 窄屏只留"跌 3972"这种最小可读单元, 百分比让位 */
  .bp-head { flex-wrap: wrap; gap: 2px 10px; }
  .bp-sub { margin-left: 0; flex: 1 1 100%; }
  .bp-foot { margin-left: 0; flex: 1 1 100%; gap: 10px; }

  /* ---- Market page (全部股票) ---- */
  .market-toolbar { flex-wrap: wrap; gap: 8px; }
  .search-input { flex: 1 1 100%; min-width: 0; font-size: 14px; padding: 9px 10px; }
  .market-meta { font-size: 11px; }
  .market-layout { flex-direction: column; gap: 8px; }
  .market-side { width: 100%; flex-direction: row; gap: 8px; }
  .hot-stock-panel, .channel-panel { flex: 1; min-width: 0; }
  .hot-stock-head { flex-wrap: wrap; gap: 6px; }
  .hot-stock-tabs { overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .hot-stock-tabs::-webkit-scrollbar { display: none; }
  .hs-tab { flex-shrink: 0; font-size: 11px; padding: 5px 9px; min-height: 32px; }
  .market-table-panel { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .market-table { min-width: 640px; }
  .refresh-btn { min-height: 34px; }
  .trend-rating-strip { gap: 8px; margin: 6px 0 2px; }
  .tr-card { flex: 1 1 calc(50% - 4px); min-width: 0; padding: 9px 10px; }
  .tr-card-count { font-size: 18px; }
  .tr-card-top1 { font-size: 10px; }
  .tr-row-score { display: none; }
  .tr-sort-hint { display: none; }
  .tr-row-price { width: 52px; }

  /* ---- Themes / Sectors ---- */
  .sectors-layout { flex-direction: column; gap: 8px; }
  .hot-rank-panel { width: 100%; position: static; max-height: none; }
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }

  /* ---- Board detail (板块成分股) ---- */
  .board-toolbar { flex-wrap: wrap; gap: 8px; }
  .board-table-panel { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .board-table { min-width: 500px; }

  /* ---- Stock panel (个股): single column ---- */
  .stock-panel { padding: 8px; gap: 8px; }
  .stock-panel-layout { grid-template-columns: 1fr; gap: 8px; }
  .f10-sidebar { display: none; }
  .stock-browser { max-height: 24vh; }
  .stock-browser.collapsed { max-height: none; }
  .sb-toolbar { padding: 8px; }
  .sb-toolbar-row { width: 100%; }
  .sb-search { font-size: 14px; padding: 9px 10px; flex: 1; min-width: 0; }
  .sb-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    min-height: 36px;
    padding: 0 12px;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
    color: var(--accent);
    border-radius: var(--r-sm);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
  }
  .sb-toggle.collapsed { color: var(--text-muted); background: rgba(255, 255, 255, 0.05); border-color: var(--border); }
  .stock-browser.collapsed .sb-list { display: none; }
  .sb-item { padding: 6px 10px; }
  .stock-header { flex-wrap: wrap; gap: 8px 12px; padding: 8px 10px; }
  .abnormal-analysis-row { padding: 6px 10px; }
  .aa-more { display: none; }
  .sh-back { min-height: 32px; }
  .sh-name { font-size: 17px; }
  .sh-code { font-size: 12px; }
  .sh-price { font-size: 24px; }
  .sh-change, .sh-change-percent { font-size: 13px; }
  .sh-stats { margin-left: 0; width: 100%; justify-content: space-between; gap: 6px; flex-wrap: nowrap; }
  .sh-stat { flex: 1; }
  .sh-stat-label { font-size: 10px; }
  .sh-stat-val { font-size: 12px; }
  .chart-toolbar { padding: 6px 8px; gap: 6px; }
  .toolbar-left { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; max-width: 100%; }
  .toolbar-left::-webkit-scrollbar { display: none; }
  .period-btn, .indicator-btn { flex-shrink: 0; padding: 6px 11px; font-size: 12px; min-height: 34px; }
  .toolbar-right { display: none; }
  .chart-wrapper-3 { min-height: 240px; }
  .chart-wrapper-3 > #klineChart { min-height: 150px; }
  /* 移动端副图允许被压缩，优先保障主图高度(高度含 26px 的 chip 条) */
  .chart-wrapper-3 > .sub-slot { flex: 0 1 clamp(78px, 11vh, 92px); min-height: 74px; }
  .sub-slot-bar { height: 26px; padding: 0 4px 0 8px; }
  .sub-slot-name { font-size: 10.5px; }
  .sub-chip { font-size: 11px; padding: 4px 8px; }
  .sub-slot-close { width: 26px; height: 26px; font-size: 14px; }
  .subchart-tabs { padding: 6px 8px; gap: 6px; }
  .subchart-tab { flex: 1; justify-content: center; padding: 8px 6px; font-size: 12px; }
  .order-book-panel { max-height: none; }
  .order-book { padding: 4px 8px; }
  .ob-row { gap: 4px; font-size: 11px; padding: 1px 0; }
  .ob-label { width: 20px; font-size: 9px; }
  .ob-volume { width: 44px; font-size: 10px; }
  .indicator-grid.compact { grid-template-columns: repeat(2, 1fr); }
  /* 面板栈: 手机端交给页面滚动, 每块按内容撑开(见文件末尾 v4 段的覆盖说明) */
  .panel-stack { flex: none; overflow: visible; }
  .ps-body { flex: none; }
  .ps-body > .ps-pane { flex: none; overflow: visible; }
  .ps-tabs { overflow-x: auto; scrollbar-width: none; }
  .ps-tabs::-webkit-scrollbar { display: none; }
  .ps-tab { flex: 0 0 auto; min-width: 78px; }

  /* ---- Watchlist page ---- */
  .panel-scroll { gap: 8px; }
  .panel-scroll > .panel { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .watchlist-table { min-width: 720px; }

  /* ---- Misc panels / tables ---- */
  .panel-header { padding: 8px 10px; }
  .rank-table th, .rank-table td { padding: 7px 8px; }
  .news-feed { gap: 6px; }

  /* ---- Touch friendly controls ---- */
  .btn-primary, .btn-secondary, .back-btn, .filter-btn, .refresh-btn,
  .wl-toggle, .wt-remove, .chf-btn, .f10-toggle { min-height: 34px; }

  /* ---- Modals ---- */
  .modal-box { padding: 16px; }
  .modal-title { font-size: 16px; }
  .modal-meta { flex-wrap: wrap; gap: 8px; }
  .pdf-box { padding: 12px; }
  .pdf-nav-btn { min-height: 34px; }

  /* ---- Kline long-hover tooltip slightly smaller on mobile ---- */
  #klineTooltip { min-width: 128px; max-width: 168px; font-size: 11px; padding: 4px 8px; }
  .kline-tooltip .kt-row { gap: 10px; }
  .kline-tooltip .kt-label { font-size: 10px; }
  .kline-tooltip .kt-val { font-size: 11px; }
  .kline-tooltip .kt-title { font-size: 11px; }
}

/* ===== Paper Trading 模拟盘 (桌面端) ===== */
.paper-panel { display: flex; flex-direction: column; gap: 8px; }

.paper-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  flex-shrink: 0;
  overflow-x: auto;
}
.ps-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 14px;
  border-right: 1px solid var(--border);
  min-width: 96px;
  flex-shrink: 0;
}
.ps-item:last-child { border-right: none; }
.ps-label { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
.ps-val { font-size: 15px; font-weight: 600; white-space: nowrap; }
.ps-val.up { color: var(--up); }
.ps-val.down { color: var(--down); }
.ps-val.flat { color: var(--text-secondary); }
.ps-sub { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
.ps-sub.up, .ps-sub.up * { color: var(--up); }
.ps-sub.down, .ps-sub.down * { color: var(--down); }
.ps-actions { flex-direction: row; align-items: center; gap: 10px; margin-left: auto; }
.paper-reset-btn {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border-light);
  border-radius: var(--r-sm);
  padding: 5px 12px;
  cursor: pointer;
  font-size: 12px;
  white-space: nowrap;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.paper-reset-btn:hover { color: var(--up); border-color: var(--up); }
.ps-updated { font-size: 11px; color: var(--text-muted); white-space: nowrap; }

.paper-layout {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 8px;
  flex: 1;
  min-height: 0;
}
.paper-left { display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.paper-order-panel { flex-shrink: 0; }
.paper-positions-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.paper-trades-panel { display: flex; flex-direction: column; min-height: 0; }

.paper-order-form { padding: 12px 16px; display: flex; flex-direction: column; gap: 10px; }
.po-row { display: flex; gap: 12px; align-items: flex-end; min-width: 0; }
.po-row > * { min-width: 0; }
.po-side-row { width: 100%; }
.po-field { display: flex; flex-direction: column; gap: 4px; }
.po-field label { font-size: 11px; color: var(--text-muted); }
.po-field input {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  padding: 7px 10px;
  font-size: 13px;
  width: 130px;
  outline: none;
}
.po-field input:focus { border-color: var(--accent); }
.po-code-inputs { display: flex; gap: 6px; }
.po-code-inputs input { width: 96px; letter-spacing: 1px; }
.po-fill-btn {
  background: var(--bg-hover);
  border: 1px solid var(--border-light);
  color: var(--text-secondary);
  border-radius: var(--r-sm);
  padding: 7px 10px;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}
.po-fill-btn:hover { color: var(--accent); border-color: var(--accent); }
.po-stock-info { font-size: 13px; color: var(--text-secondary); line-height: 32px; }
.po-price { font-weight: 600; font-size: 15px; }
.po-query-btn {
  background: var(--bg-hover);
  border: 1px solid var(--border-light);
  color: var(--text-primary);
  border-radius: var(--r-sm);
  padding: 8px 16px;
  cursor: pointer;
  font-size: 13px;
}
.po-query-btn:hover { border-color: var(--accent); color: var(--accent); }

.po-side-row { gap: 10px; }
.po-side-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 96px;
  padding: 9px 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.po-side-btn.po-buy.active { background: var(--up-bg); border-color: var(--up); color: var(--up); }
.po-side-btn.po-sell.active { background: var(--down-bg); border-color: var(--down); color: var(--down); }

.po-quick-row { align-items: center; gap: 6px; flex-wrap: wrap; }
.po-quick-label { font-size: 11px; color: var(--text-muted); }
.po-quick {
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  border-radius: var(--r-xs);
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.po-quick:hover { color: var(--accent); border-color: var(--accent); }

.po-submit-row { align-items: center; }
.po-estimate { flex: 1; font-size: 12px; color: var(--text-secondary); }
.po-submit {
  padding: 9px 32px;
  border: none;
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  color: #fff;
  transition: opacity 0.15s;
}
.po-submit:disabled { opacity: 0.5; cursor: not-allowed; }
.po-submit-buy { background: var(--up); }
.po-submit-sell { background: var(--down); }

.po-msg { min-height: 18px; font-size: 12px; color: var(--text-muted); }
.po-msg.po-msg-ok { color: var(--down); }
.po-msg.po-msg-err { color: var(--up); }

.paper-table-wrap { overflow: auto; padding: 0 6px 8px; min-height: 0; }
.paper-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.paper-table th {
  text-align: left;
  color: var(--text-muted);
  font-weight: 500;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg-panel);
  white-space: nowrap;
}
.paper-table td { padding: 7px 8px; border-bottom: 1px solid var(--border); color: var(--text-primary); white-space: nowrap; }
.paper-table .up { color: var(--up); }
.paper-table .down { color: var(--down); }
.paper-table .flat { color: var(--text-secondary); }
.pt-name { font-weight: 500; }
.pt-code { font-size: 11px; color: var(--text-muted); }
.pt-time { font-size: 11px; color: var(--text-muted); }
.pt-action { font-weight: 600; }
.pt-action.up { color: var(--up); }
.pt-action.down { color: var(--down); }
.pt-fees { color: var(--text-muted); }
.pt-sell-btn {
  background: transparent;
  border: 1px solid var(--down);
  color: var(--down);
  border-radius: var(--r-xs);
  padding: 3px 10px;
  font-size: 12px;
  cursor: pointer;
}
.pt-sell-btn:hover { background: var(--down-bg); }
.paper-table .loading-cell { text-align: center; color: var(--text-muted); padding: 18px 0; }

/* ---- Paper panel mobile ---- */
@media (max-width: 768px) {
  .paper-panel { gap: 6px; }
  .paper-summary { flex-wrap: wrap; row-gap: 8px; padding: 10px 12px; }
  .ps-item { min-width: 0; padding: 0 10px; }
  .ps-val { font-size: 14px; }
  .ps-actions { width: 100%; margin-left: 0; border-right: none; }
  .paper-layout { grid-template-columns: minmax(0, 1fr); }
  .paper-order-form { padding: 10px 12px; }
  .po-row { flex-wrap: wrap; gap: 8px; }
  .po-row.po-side-row { flex-wrap: nowrap; }
  .po-side-btn { flex: 1; }
  .po-field input { width: 110px; }
  .po-code-inputs input { width: 90px; }
  .po-stock-info { line-height: 20px; }
  .po-submit { width: 100%; }
  .paper-table-wrap { overflow-x: auto; }
  .paper-table { min-width: 640px; }
  .paper-trades-panel .paper-table { min-width: 560px; }
  .po-quick, .paper-reset-btn, .pt-sell-btn, .po-query-btn, .po-fill-btn { min-height: 30px; }
}

/* ===== Global Indices Panel (全球指数) ===== */
.global-panel { gap: 14px; }
.global-head { margin-bottom: 0; }
.global-head h3 { margin: 0; font-size: 16px; }
.global-head-right { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
/* 数据来源角标 (2026-10-04): 仅在东财主源不可用(已切第三方)或全部失败时出现,
   平时 display:none —— 不常驻一个"看起来正常"的无信息量标签。 */
.global-source-badge {
  font-size: 11px; line-height: 1.6; padding: 1px 8px; border-radius: 999px;
  border: 1px solid currentColor; white-space: nowrap;
}
.global-source-badge.fallback { color: var(--dp-warn); }
.global-source-badge.err { color: var(--down); }
/* 无可信数据源的区域: 显式说明而不是留白(铁律16 —— 没有数据就说没有数据) */
.global-unsupported {
  display: flex; flex-direction: column; gap: 8px;
  border: 1px dashed var(--border); border-radius: var(--r-md);
  padding: 12px 16px; background: rgba(255, 255, 255, 0.015);
}
.gu-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; font-size: 12px; color: var(--text-muted); }
.gu-region { flex: 0 0 auto; font-weight: 600; color: var(--text-secondary); }
/* ⚠️ 不要用 flex:1 1 auto —— 宽屏下会把"暂无可用的实时数据源"甩到最右,
   中间凭空多出上千像素空白(铁律18: 内容量 ≪ 容器宽时, 让内容紧凑, 别拉散)。 */
.gu-names { flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; }
.gu-names::after { content: '·'; margin-left: 10px; opacity: 0.5; }
.gu-reason { flex: 0 0 auto; font-style: italic; opacity: 0.85; }
.global-groups { display: flex; flex-direction: column; gap: 16px; }
.global-group {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 14px 16px;
}
.gg-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.gg-header h4 { margin: 0; font-size: 14px; font-weight: 600; }
.gg-hint { font-size: 11px; color: var(--text-muted); }
.gg-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; }
.gi-card {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 12px 14px;
  transition: color .25s, background-color .25s, border-color .25s, opacity .25s, transform .25s;
}
.gi-card:hover { border-color: var(--border-light); background: var(--bg-card); }
.gi-currency {
  font-size: 10px; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 1px 6px; letter-spacing: 0.5px;
}
.gi-detail {
  display: flex; gap: 10px; flex-wrap: wrap;
  font-size: 11px; color: var(--text-muted); margin-top: 8px;
}
.gi-detail b { font-weight: 600; color: var(--text); }

/* ---- Global panel mobile ---- */
@media (max-width: 768px) {
  .global-panel { gap: 8px; }
  .global-group { padding: 10px 12px; border-radius: var(--r-md); }
  .gg-cards { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
  .gi-card { padding: 10px 12px; min-width: 0; }
  .gi-card .ic-price { font-size: 20px; }
  .gi-detail { gap: 6px; }
}

/* ---- Paper reset modal (自定义初始资金) ---- */
.pr-cash-field { margin: 12px 0 4px; }
.pr-cash-field label {
  display: block; font-size: 12px; color: var(--text-muted); margin-bottom: 6px;
}
#prCashInput {
  width: 100%; box-sizing: border-box;
  padding: 8px 12px; font-size: 15px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text); background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  outline: none;
}
#prCashInput:focus { border-color: var(--accent, var(--accent)); }
#prCashInput.invalid { border-color: var(--danger, var(--up)); }
.pr-presets { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.pr-preset {
  padding: 4px 10px; font-size: 12px; border-radius: var(--r-sm);
  color: var(--text-muted); background: transparent;
  border: 1px solid var(--border); cursor: pointer;
}

/* ---- Auto-Trade Panel 自动交易面板 ---- */
.auto-panel { padding: 14px 20px; }
.auto-header-right { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.auto-mode-badge {
  padding: 4px 10px; border-radius: var(--r-sm); font-size: 12px; font-weight: 600;
  cursor: pointer; user-select: none;
}
.auto-mode-badge.dry { background: color-mix(in srgb, var(--gold) 15%, transparent); color: var(--gold); border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent); }
.auto-mode-badge.live { background: color-mix(in srgb, var(--up) 15%, transparent); color: var(--up); border: 1px solid color-mix(in srgb, var(--up) 30%, transparent); }
.auto-mode-badge:hover { filter: brightness(1.15); }
.auto-polling { font-size: 12px; color: var(--text-muted); padding: 4px 8px; }
.auto-run-btn, .auto-config-btn {
  padding: 5px 12px; font-size: 12px; border-radius: var(--r-sm);
  color: var(--text); background: var(--bg-elev);
  border: 1px solid var(--border); cursor: pointer;
}
.auto-run-btn:hover, .auto-config-btn:hover { background: var(--accent, var(--accent)); border-color: var(--accent, var(--accent)); }
.auto-config-btn { background: transparent; }

.auto-summary {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px; margin-bottom: 16px;
}
.as-card {
  padding: 10px 14px; border-radius: var(--r-sm);
  background: var(--bg-elev); border: 1px solid var(--border);
}
.as-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
.as-val { font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* ---- 全自动总控卡 (2026-10-02) ---- */
.auto-master-card {
  padding: 12px 16px; margin-bottom: 16px; border-radius: var(--r-md);
  background: var(--bg-elev); border: 1px solid var(--border);
}
.am-row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.am-master-btn {
  padding: 10px 22px; font-size: 15px; font-weight: 700; border-radius: var(--r-sm);
  cursor: pointer; white-space: nowrap; letter-spacing: 1px;
}
.am-master-btn.off {
  color: #121214; background: var(--down); border: 1px solid var(--down);
}
.am-master-btn.off:hover { background: var(--down); }
.am-master-btn.on {
  color: var(--on-accent); background: var(--up); border: 1px solid var(--up);
}
.am-master-btn.on:hover { background: var(--up); }
.am-master-btn:active { transform: scale(0.98); }
.am-state { display: flex; flex-direction: column; gap: 2px; min-width: 160px; }
.am-state-line { font-size: 13px; font-weight: 600; color: var(--text); }
.am-state-sub { font-size: 11px; color: var(--text-muted); }

/* 阶段状态灯 */
.am-stages { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.am-stage {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--r-sm); font-size: 12px;
  background: transparent; border: 1px solid var(--border);
  color: var(--text-muted);
}
.am-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); flex: 0 0 auto; }
.am-time { font-size: 10px; color: var(--text-muted); opacity: 0.8; }
.am-arrow { color: var(--text-muted); font-size: 12px; opacity: 0.6; }
.am-stage.done { color: var(--text); border-color: color-mix(in srgb, var(--down) 50%, transparent); }
.am-stage.done .am-dot { background: var(--down); }
.am-stage.running { color: var(--text); border-color: color-mix(in srgb, var(--accent) 50%, transparent); }
.am-stage.running .am-dot { background: var(--accent); animation: am-pulse 1.2s infinite; }
.am-stage.error { color: var(--text); border-color: color-mix(in srgb, var(--up) 50%, transparent); }
.am-stage.error .am-dot { background: var(--up); }
.am-stage.idle { color: var(--text-muted); }
.am-stage.idle .am-dot { background: var(--gold); }
.am-stage.off .am-dot { background: var(--text-muted); }
@keyframes am-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

/* 事件流 */
.am-log-wrap { margin-top: 12px; border-top: 1px dashed var(--border); padding-top: 10px; }
.am-log-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.am-log-title { font-size: 12px; font-weight: 600; color: var(--text); }
.am-log-hint { font-size: 10px; color: var(--text-muted); }
.am-log {
  max-height: 220px; overflow-y: auto; border-radius: var(--r-sm);
  background: var(--bg); border: 1px solid var(--border);
  padding: 6px 10px; font-size: 12px;
}
.am-log-empty { color: var(--text-muted); padding: 8px 4px; font-size: 11px; }
.am-log-item {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 4px; border-radius: var(--r-xs); color: var(--text);
}
.am-log-item:hover { background: rgba(255,255,255,0.04); }
.am-log-time { font-variant-numeric: tabular-nums; color: var(--text-muted); font-size: 11px; flex: 0 0 auto; }
.am-log-tag {
  flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--cyan);
}
.am-log-msg { flex: 1 1 auto; min-width: 0; word-break: break-all; }
.am-log-item.lv-ok .am-log-msg { color: var(--down); }
.am-log-item.lv-warn .am-log-msg { color: var(--gold); }
.am-log-item.lv-err .am-log-msg { color: var(--up); }
.am-log-item.lv-warn .am-log-tag { background: color-mix(in srgb, var(--gold) 12%, transparent); color: var(--gold); }
.am-log-item.lv-err .am-log-tag { background: color-mix(in srgb, var(--up) 12%, transparent); color: var(--up); }

/* ---- 两段式漏斗 + 候选池 + 集合竞价 (2026-10-04) ----
   宽度口径: 两个子栏进 grid 后必须 min-width:0, 否则内部 nowrap 表格会把轨道撑破
   (这正是过往"板块面板压住隔壁面板"的同一种错法)。 */
.auto-funnel-card {
  padding: 12px 16px; margin-bottom: 16px; border-radius: var(--r-md);
  background: var(--bg-elev); border: 1px solid var(--border);
}
.afc-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.afc-head .auto-section { margin: 0; }
.afc-meta { font-size: 11px; color: var(--text-muted); }

/* 漏斗步进条: 每格等分, 数值等宽数字, 空态淡化而不是隐藏 —— 否则同行步数会变 */
.afc-steps { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap; margin: 10px 0 14px; }
.afc-step {
  flex: 1 1 0; min-width: 104px; padding: 8px 10px; border-radius: var(--r-sm);
  background: rgba(255,255,255,0.03); border: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 2px;
}
.afc-step-label { font-size: 10px; color: var(--text-muted); white-space: nowrap; }
.afc-step-val { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text); }
.afc-step-sub { font-size: 10px; color: var(--text-muted); white-space: nowrap; }
.afc-step.is-empty .afc-step-val { color: var(--text-muted); opacity: 0.6; }
.afc-sep { align-self: center; color: var(--text-muted); opacity: 0.45; font-size: 12px; flex: 0 0 auto; }

.afc-cols { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 14px; }
.afc-col { min-width: 0; display: flex; flex-direction: column; }
.afc-col-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 12px; color: var(--text); margin-bottom: 6px;
}
.afc-count { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.afc-table-wrap { max-height: 300px; overflow: auto; border: 1px solid var(--border); border-radius: var(--r-sm); }
.afc-note { font-size: 10px; color: var(--text-muted); margin-top: 6px; line-height: 1.5; }
.afc-tabs { display: flex; gap: 4px; margin-top: 8px; }
.afc-tab {
  padding: 3px 10px; font-size: 11px; border-radius: var(--r-sm); cursor: pointer;
  color: var(--text-muted); background: transparent; border: 1px solid var(--border);
}
.afc-tab.active { color: var(--text); border-color: var(--accent, var(--accent)); }
.afc-gap-up { color: var(--up, var(--up)); }
.afc-gap-down { color: var(--down); }
.afc-note-cell { font-size: 11px; color: var(--text-muted); max-width: 240px; overflow: hidden; text-overflow: ellipsis; }
/* 观察名单里被淘汰的行: 淡化但仍可读 (保留"为什么没选它"的审计价值) */
.afc-row-out td { opacity: 0.62; }
.afc-cand-rank { color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* 触发状态标签 */
.auto-trigger-tag { display: inline-block; padding: 1px 6px; border-radius: var(--r-xs); font-size: 10px; white-space: nowrap; }
.auto-trigger-tag.t-pending { color: var(--gold); border: 1px solid color-mix(in srgb, var(--gold) 50%, transparent); }
.auto-trigger-tag.t-triggered { color: var(--up, var(--up)); border: 1px solid color-mix(in srgb, var(--up) 50%, transparent); }
.auto-trigger-tag.t-expired { color: var(--text-muted); border: 1px solid var(--border); }
.auto-trigger-tag.t-rejected { color: var(--down); border: 1px solid color-mix(in srgb, var(--down) 50%, transparent); }
.auto-trigger-tag.t-legacy { color: var(--gold); border: 1px solid color-mix(in srgb, var(--gold) 50%, transparent); cursor: help; }
/* 入场区间里的硬上限后缀: 小一号, 不抢主区间的视觉权重 */
.auto-cap { margin-left: 4px; font-size: 10px; color: var(--text-muted); }

.auto-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px;
}
.auto-section { font-size: 14px; margin: 16px 0 8px; color: var(--text); }
.auto-meta { font-size: 11px; color: var(--text-muted); margin-bottom: 8px; }

.auto-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
.auto-tab {
  padding: 4px 12px; font-size: 12px; border-radius: 6px 6px 0 0;
  color: var(--text-muted); background: transparent;
  border: 1px solid var(--border); border-bottom: none; cursor: pointer;
}
.auto-tab.active { color: var(--text); background: var(--bg-elev); border-bottom: 1px solid var(--bg-elev); }

.auto-table-wrap, .auto-decision-wrap, .auto-journal-wrap {
  max-height: 360px; overflow: auto;
  border: 1px solid var(--border); border-radius: var(--r-sm);
}
.auto-journal-wrap { max-height: 260px; }
.auto-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.auto-table th, .auto-table td {
  padding: 6px 8px; border-bottom: 1px solid var(--border);
  text-align: left; white-space: nowrap;
}
.auto-table th { background: var(--bg-elev); color: var(--text-muted); position: sticky; top: 0; font-weight: 500; }
.auto-table .up { color: var(--up, var(--up)); }
.auto-table .down { color: var(--down); }
.auto-empty { text-align: center; color: var(--text-muted); padding: 24px; font-style: italic; }
.auto-act-buy { color: var(--up, var(--up)); font-weight: 600; }
.auto-act-sell { color: var(--down); font-weight: 600; }
.auto-act-skip { color: var(--text-muted); }
.auto-exec-ok { color: var(--up, var(--up)); }
.auto-exec-err { color: var(--down); cursor: help; }
.auto-exec-no { color: var(--text-muted); }
.auto-reason { font-size: 11px; color: var(--text-muted); max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
.auto-jump { color: var(--accent, var(--accent)); text-decoration: none; cursor: pointer; }
.auto-jump:hover { text-decoration: underline; }

/* ---- 决策 ↔ 模拟盘持仓 同步状态 (2026-09-27) ---- */
.auto-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.auto-sync-btn {
  padding: 3px 10px; font-size: 11px; border-radius: var(--r-sm); cursor: pointer;
  color: var(--accent, var(--accent)); background: transparent;
  border: 1px solid var(--accent, var(--accent)); opacity: .85;
}
.auto-sync-btn:hover { opacity: 1; background: color-mix(in srgb, var(--accent) 12%, transparent); }
.auto-sync-btn:disabled { opacity: .5; cursor: default; }
.auto-sync-tag {
  display: inline-block; padding: 1px 6px; border-radius: var(--r-xs);
  font-size: 10px; cursor: help; white-space: nowrap;
}
.auto-sync-tag.auto-sync-cancel { color: var(--text-muted); border: 1px solid var(--border); }
.auto-sync-tag.auto-sync-closed { color: var(--accent, var(--accent)); border: 1px solid var(--accent, var(--accent)); }
.auto-sync-tag.auto-sync-manual { color: var(--gold); border: 1px solid var(--gold); }
/* 已失效决策整行降透明度, 但仍可读 (保留审计价值) */
.auto-row-inactive td { opacity: .55; }
.auto-row-inactive:hover td { opacity: .85; }
.auto-held-dot { color: var(--up, var(--up)); font-size: 10px; cursor: help; }

.auto-msg {
  margin-top: 12px; padding: 8px 12px; border-radius: var(--r-sm);
  font-size: 12px; min-height: 18px;
  background: transparent; color: var(--text-muted);
}
.auto-msg.ok { background: color-mix(in srgb, var(--down) 10%, transparent); color: var(--down); }
.auto-msg.err { background: color-mix(in srgb, var(--up) 10%, transparent); color: var(--up); }

/* ===== 自动交易参数弹窗（2026-10-29 重做：中文名 + 白话说明 + 单位 + 预设档） =====
   旧版把后端英文键名直接当 label 显示（maxCircMvYi / distStopPctRange），用户看不懂。
   现结构：每行 = 中文名+一句白话 | 控件+单位 | 恢复默认。*/
.ac-section { margin: 14px 0; }
.ac-section h4 { font-size: 13px; margin: 6px 0; color: var(--accent, var(--accent)); }

.ac-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 10px 0 4px; }
.ac-presets { display: flex; gap: 6px; flex-wrap: wrap; }
.ac-preset {
  padding: 5px 12px; font-size: 12px; border-radius: 14px; cursor: pointer;
  border: 1px solid var(--border); background: transparent; color: var(--text-muted);
}
.ac-preset:hover { border-color: var(--accent, var(--accent)); color: var(--text); }
.ac-preset.on { background: color-mix(in srgb, var(--accent) 15%, transparent); border-color: var(--accent, var(--accent)); color: var(--accent, var(--accent)); }
.ac-verinfo { margin-left: auto; font-size: 11px; color: var(--text-muted); }
.ac-verinfo b { color: var(--text); font-weight: 600; }

.ac-sec { margin: 16px 0; border-top: 1px solid var(--border); padding-top: 10px; }
.ac-sec-head { margin-bottom: 6px; }
.ac-sec-title { font-size: 13.5px; font-weight: 600; color: var(--accent, var(--accent)); }
.ac-sec-sub { font-size: 11px; color: var(--text-muted); margin-top: 2px; line-height: 1.45; }

.ac-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto 22px;
  gap: 10px; align-items: center; padding: 9px 6px; border-radius: var(--r-sm);
}
.ac-row:hover { background: rgba(255,255,255,0.035); }
.ac-row + .ac-row { border-top: 1px dashed rgba(255,255,255,0.075); }
.ac-name { min-width: 0; }
.ac-name b { display: block; font-size: 12.5px; font-weight: 500; color: var(--text); line-height: 1.3; }
.ac-name i { display: block; font-style: normal; font-size: 10.5px; color: var(--text-muted); line-height: 1.5; margin-top: 2px; }
.ac-money {
  display: inline-block; margin-top: 3px; padding: 0 5px; border-radius: var(--r-xs);
  font-style: normal; font-size: 10px; line-height: 16px;
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--cyan);
}
.ac-row.is-dead { opacity: 0.5; }
.ac-row.is-dead .ac-name b { color: var(--text-muted); }
/* 顶部说明段落：默认 .wl-confirm-text 是居中的，参数弹窗里改左对齐（长段落居中很难读） */
#autoConfigModal .wl-confirm-text { text-align: left; line-height: 1.55; font-size: 11.5px; }

.ac-ctl { display: flex; align-items: center; gap: 4px; justify-content: flex-end; }
.ac-ctl input[type="text"], .ac-ctl select {
  width: 78px; padding: 4px 7px; font-size: 12px; text-align: right; border-radius: var(--r-sm);
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  outline: none; box-sizing: border-box;
}
.ac-ctl select { width: 94px; text-align: left; }
.ac-ctl input:focus, .ac-ctl select:focus { border-color: var(--accent, var(--accent)); }
.ac-ctl input.bad { border-color: var(--up); background: color-mix(in srgb, var(--up) 8%, transparent); }
.ac-unit { font-size: 11px; color: var(--text-muted); flex: none; min-width: 12px; }
.ac-range { display: flex; align-items: center; gap: 4px; }
.ac-range input { width: 58px !important; }
.ac-range > span { color: var(--text-muted); font-size: 11px; }

.ac-switch { position: relative; display: inline-block; width: 38px; height: 20px; flex: none; }
.ac-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.ac-switch span { position: absolute; inset: 0; background: var(--border-light); border-radius: var(--r-md); cursor: pointer; transition: 0.15s; }
.ac-switch span::after {
  content: ''; position: absolute; width: 16px; height: 16px; left: 2px; top: 2px;
  background: #fff; border-radius: 50%; transition: 0.15s;
}
.ac-switch input:checked + span { background: var(--accent, var(--accent)); }
.ac-switch input:checked + span::after { transform: translateX(18px); }

.ac-reset {
  width: 20px; height: 20px; line-height: 1; padding: 0; font-size: 13px; cursor: pointer;
  border: none; background: transparent; color: var(--text-muted); border-radius: var(--r-xs);
}
.ac-reset:hover { color: var(--accent, var(--accent)); background: color-mix(in srgb, var(--accent) 12%, transparent); }

.ac-wide { grid-template-columns: minmax(0, 1fr); gap: 6px; }
.ac-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.ac-chip {
  display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; font-size: 11px;
  border-radius: var(--r-md); background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--cyan); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}
.ac-chip.neg { background: color-mix(in srgb, var(--up) 10%, transparent); color: var(--up); border-color: color-mix(in srgb, var(--up) 30%, transparent); }
.ac-chip button { border: none; background: transparent; color: inherit; cursor: pointer; font-size: 12px; padding: 0 1px; opacity: 0.7; }
.ac-chip button:hover { opacity: 1; }
.ac-tag-input {
  width: 110px; padding: 2px 6px; font-size: 11px; border-radius: var(--r-md);
  background: transparent; color: var(--text); border: 1px dashed var(--border); outline: none;
}
.ac-tag-input:focus { border-color: var(--accent, var(--accent)); }

.ac-scale { gap: 8px; flex-wrap: wrap; }
.ac-scale label { display: flex; align-items: center; gap: 3px; font-size: 11px; color: var(--text-muted); }
.ac-scale input { width: 50px !important; }

.ac-adv { margin-top: 10px; border-top: 1px dashed var(--border); padding-top: 8px; }
.ac-adv summary { cursor: pointer; font-size: 12px; color: var(--text-muted); outline: none; }
.ac-adv summary:hover { color: var(--text); }
.ac-adv[open] summary { margin-bottom: 4px; }
.ac-note-warn {
  display: inline-block; margin-left: 4px; padding: 0 4px; font-size: 9.5px; border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--gold) 15%, transparent); color: var(--gold); vertical-align: 1px;
}
.ac-note-new {
  display: inline-block; margin-left: 4px; padding: 0 4px; font-size: 9.5px; border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--text-muted) 15%, transparent); color: var(--text-secondary); vertical-align: 1px;
}

.modal-box-lg { width: min(780px, 94vw); max-height: 86vh; overflow: auto; }
#acConfigNote { width: 100%; padding: 6px 10px; box-sizing: border-box; border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--bg); color: var(--text); margin-top: 4px; }
/* 校验错误直接贴在弹窗里 —— autoShowMsg 显示在面板底部, 弹窗盖住时用户看不到 */
.ac-errbox { display: none; margin: 10px 0 0; padding: 8px 10px; font-size: 11.5px; line-height: 1.5;
  border-radius: var(--r-sm); background: color-mix(in srgb, var(--up) 10%, transparent); color: var(--up); border: 1px solid color-mix(in srgb, var(--up) 30%, transparent); }
.ac-errbox.show { display: block; }

@media (max-width: 768px) {
  .ac-row { grid-template-columns: minmax(0, 1fr) auto 20px; gap: 6px; padding: 6px 2px; }
  .ac-ctl input[type="text"] { width: 62px; }
  .ac-ctl select { width: 82px; }
  .ac-ctl select { font-size: 11px; }
  .ac-name i { font-size: 10px; }
  .ac-verinfo { margin-left: 0; width: 100%; }
}

@media (max-width: 768px) {
  .auto-layout { grid-template-columns: minmax(0, 1fr); }
  .auto-header-right { gap: 4px; }
  .auto-run-btn, .auto-config-btn { padding: 4px 8px; font-size: 11px; }
  .as-card { padding: 8px 10px; }
  .as-val { font-size: 16px; }
  .auto-table th, .auto-table td { padding: 4px 6px; font-size: 11px; }
  /* 全自动总控: 手机端按钮全宽 + 状态灯换行铺满 */
  .auto-master-card { padding: 10px 12px; }
  .am-row { gap: 10px; }
  .am-master-btn { width: 100%; padding: 10px 16px; }
  .am-state { min-width: 0; flex: 1 1 100%; }
  .am-stages { margin-left: 0; width: 100%; justify-content: space-between; }
  .am-stage { padding: 5px 8px; font-size: 11px; flex: 1 1 0; justify-content: center; }
  .am-time { display: none; }
  .am-log { max-height: 160px; }
  /* 两段式漏斗: 手机端单列堆叠, 步进条允许横向滚动而不是把格子压到看不清 */
  .auto-funnel-card { padding: 10px 12px; }
  .afc-cols { grid-template-columns: minmax(0, 1fr); }
  .afc-steps { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px; }
  .afc-step { flex: 0 0 auto; min-width: 96px; }
  .afc-sep { display: none; }
  .afc-table-wrap { max-height: 240px; }
}
.pr-preset:hover { border-color: var(--accent, var(--accent)); color: var(--text); }

/* ============================================================
   Mobile layout v2 (2026-10-01) — 手机端可用性重构
   ① 底部 Tab 导航: 取代顶栏横向滚动, 9 个面板全部可见可点
   ② 表格瘦身: 只留核心列, 手机端彻底消除横向滚动
   ③ 个股页: K 线图/盘口放大, 页面改为纵向滚动
   ④ 移动端视口: dvh 跟随地址栏 + 底部安全区
   作用域: 仅 <=768px。本块位于文件末尾, 同权重覆盖旧移动端规则;
           桌面端 (>=769px) 完全不受影响。
   ============================================================ */
@media (max-width: 768px) {

  /* ---------- 0. 视口高度: dvh 跟随移动端地址栏收起/展开 ---------- */
  .app-scale { height: 100vh; height: 100dvh; }
  body { -webkit-tap-highlight-color: transparent; }

  /* ---------- 1. 顶栏: 压成一行(品牌 + 行情条 + 时钟) ---------- */
  .top-bar {
    height: auto;
    min-height: 46px;
    flex-wrap: nowrap;
    align-items: center;
    gap: 8px;
    padding: calc(3px + env(safe-area-inset-top, 0px)) 10px 3px;
  }
  .market-ticker { mask-image: linear-gradient(90deg, #000 90%, transparent 100%); }

  /* ---------- 2. 底部 Tab 导航: 5 列 × 2 行, 全部可见 ---------- */
  .nav-tabs {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 90;
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 3px;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
    border: none;
    border-top: 1px solid var(--border-light);
    border-radius: 0;
    background: color-mix(in srgb, var(--bg-dark) 97%, transparent);
    /* 去掉毛玻璃：底色已经是 97% 不透明，blur 在暗底上几乎看不出效果，
       却要为此多一层离屏合成。简洁优先。 */
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.55);
    overflow: visible;
    -webkit-overflow-scrolling: auto;
  }
  .nav-tabs::-webkit-scrollbar { display: none; }
  .nav-tab {
    width: 100%;
    min-height: 38px;
    padding: 4px 2px;
    font-size: 12px;
    line-height: 1.15;
    border-radius: var(--r-sm);
    white-space: nowrap;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .nav-tab.active {
    background: color-mix(in srgb, var(--accent) 13%, transparent);
    color: var(--accent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  }
  .nav-tab:active { background: var(--bg-hover); }

  /* 底部导航占位: 直接缩短布局区高度(而非给内容加内边距),
     这样内部自带滚动的面板(热门排行/持仓表)也不会被导航遮住最后一行 */
  .main-layout {
    padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px));
  }
  .main-content {
    padding: 8px;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
  }

  /* ---------- 3. 表格瘦身: 消除横向滚动 ---------- */
  .watchlist-table, .market-table, .board-table, .paper-table,
  .rank-table, .ts-table, .auto-table { min-width: 0 !important; width: 100%; }
  .watchlist-table th, .watchlist-table td,
  .market-table th, .market-table td,
  .board-table th, .board-table td,
  .paper-table th, .paper-table td,
  .rank-table th, .rank-table td { padding: 8px 6px; }
  .watchlist-table th, .market-table th, .board-table th,
  .paper-table th, .rank-table th { font-size: 11px; }
  .watchlist-table td, .market-table td, .board-table td,
  .paper-table td, .rank-table td { font-size: 12px; }

  /* 自选清单(12列) → 留: ①名称 ②代码 ③现价 ⑤涨跌幅 ⑩换手率 ⑫操作 */
  .watchlist-table th:nth-child(4),  .watchlist-table td:nth-child(4),
  .watchlist-table th:nth-child(6),  .watchlist-table td:nth-child(6),
  .watchlist-table th:nth-child(7),  .watchlist-table td:nth-child(7),
  .watchlist-table th:nth-child(8),  .watchlist-table td:nth-child(8),
  .watchlist-table th:nth-child(9),  .watchlist-table td:nth-child(9),
  .watchlist-table th:nth-child(11), .watchlist-table td:nth-child(11) { display: none; }
  .watchlist-table .wt-name,
  .watchlist-table .wt-code { max-width: 70px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .watchlist-table .wt-remove { padding: 4px 8px; }

  /* 全部股票(9列) → 留: ②名称/代码 ③最新价 ④涨跌幅 ⑤成交额 ⑧评级 */
  .market-table th:nth-child(1), .market-table td:nth-child(1),
  .market-table th:nth-child(6), .market-table td:nth-child(6),
  .market-table th:nth-child(7), .market-table td:nth-child(7),
  .market-table th:nth-child(9), .market-table td:nth-child(9) { display: none; }
  /* 板块成分(5列) → 再隐藏 ⑤市场 */
  .board-table th:nth-child(5), .board-table td:nth-child(5) { display: none; }

  /* 模拟盘·持仓(9列) → 留: ①名称/代码 ④成本价 ⑤现价 ⑦浮动盈亏 ⑨操作 */
  #paperPositionsTable th:nth-child(2), #paperPositionsTable td:nth-child(2),
  #paperPositionsTable th:nth-child(3), #paperPositionsTable td:nth-child(3),
  #paperPositionsTable th:nth-child(6), #paperPositionsTable td:nth-child(6),
  #paperPositionsTable th:nth-child(8), #paperPositionsTable td:nth-child(8) { display: none; }
  /* 模拟盘·成交(8列) → 留: ①时间 ②名称/代码 ③方向 ④价格 ⑧盈亏 */
  #paperTradesTable th:nth-child(5), #paperTradesTable td:nth-child(5),
  #paperTradesTable th:nth-child(6), #paperTradesTable td:nth-child(6),
  #paperTradesTable th:nth-child(7), #paperTradesTable td:nth-child(7) { display: none; }

  /* 自动交易·信号(9列) → 留: ①代码 ②名称 ③评级 ⑤现价 ⑥涨% */
  #autoSignalTable th:nth-child(4), #autoSignalTable td:nth-child(4),
  #autoSignalTable th:nth-child(7), #autoSignalTable td:nth-child(7),
  #autoSignalTable th:nth-child(8), #autoSignalTable td:nth-child(8),
  #autoSignalTable th:nth-child(9), #autoSignalTable td:nth-child(9) { display: none; }
  /* 自动交易·决策(9列) → 留: ①代码 ②动作 ③止损 ④目标 ⑨已执行 */
  #autoDecisionTable th:nth-child(5), #autoDecisionTable td:nth-child(5),
  #autoDecisionTable th:nth-child(6), #autoDecisionTable td:nth-child(6),
  #autoDecisionTable th:nth-child(7), #autoDecisionTable td:nth-child(7),
  #autoDecisionTable th:nth-child(8), #autoDecisionTable td:nth-child(8) { display: none; }
  /* 自动交易·复盘(10列) → 留: ①开仓日 ②代码 ④入场 ⑤出场 ⑥盈亏 ⑩质量分 */
  #autoJournalTable th:nth-child(3), #autoJournalTable td:nth-child(3),
  #autoJournalTable th:nth-child(7), #autoJournalTable td:nth-child(7),
  #autoJournalTable th:nth-child(8), #autoJournalTable td:nth-child(8),
  #autoJournalTable th:nth-child(9), #autoJournalTable td:nth-child(9) { display: none; }

  /* 名称/代码列在 fixed 布局下自动均分, 手动加宽可读性更好 */
  .market-table td:nth-child(2) .rank-name,
  .market-table td:nth-child(2) .rank-code { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .market-table-panel, .board-table-panel, .paper-table-wrap { overflow-x: visible; }
  .board-table-panel { overflow-y: auto; }

  /* ---------- 4. 个股页: K 线放大 + 纵向滚动 ---------- */
  #panel-stock.stock-panel { display: block; padding: 8px; }
  .stock-panel-layout { display: block; }
  .stock-detail { display: block; }
  .stock-detail > * + * { margin-top: 8px; }
  .chart-wrapper-3 {
    height: 356px;
    min-height: 356px;
    flex: none;
  }
  .chart-wrapper-3 > #klineChart { min-height: 196px; }
  .chart-wrapper-3 > .sub-slot { flex: 0 0 64px; min-height: 64px; }
  .stock-panel .bottom-panels {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto;
    height: auto;
    gap: 8px;
    margin-top: 8px;
    overflow: visible;
  }
  .stock-panel .bottom-panels > .panel { overflow: visible; }
  .order-book { padding: 6px 10px; }
  .ob-row { font-size: 12px; padding: 2px 0; }
  .ob-label { width: 24px; font-size: 10px; }
  .ob-volume { width: 52px; font-size: 11px; }
  .indicator-grid.compact { grid-template-columns: repeat(2, 1fr); }
  .chart-toolbar { position: sticky; top: 0; z-index: 40; background: var(--bg-panel); }

  /* ---------- 5. 输入框: 16px 避免 iOS 聚焦自动放大整页 ---------- */
  .search-input, .sb-search, .po-field input, #prCashInput,
  .ac-field input, #acConfigNote, .market-toolbar input { font-size: 16px; }

  /* ---------- 6. 触摸反馈与细节 ---------- */
  .clickable-row:active { background: var(--bg-hover); }
  .watchlist-table .wt-remove { white-space: nowrap; }
  .market-meta { display: flex; flex-wrap: wrap; gap: 2px 8px; line-height: 1.5; flex: 1 1 100%; justify-content: flex-end; }
  .pagination { flex-wrap: wrap; gap: 4px; }
  .panel-header h3 { font-size: 14px; }
  .nav-tabs, .nav-tab { -webkit-user-select: none; user-select: none; }

  /* K线/分时(共用 #klineChart): 纵向滑动交给浏览器滚动页面(否则手指在图上滑不动),
     横向拖动与双指缩放仍由图表接管 */
  #klineChart, #volumeChart, #macdChart, #capitalChart { touch-action: pan-y pinch-zoom; }

  /* ---------- 7. 模拟盘: 取消高度受限布局, 改为自然高度 + 页面滚动 ---------- */
  .paper-layout { flex: none; grid-template-columns: minmax(0, 1fr); }
  .paper-left { min-height: 0; }
  .paper-positions-panel { flex: none; }
  .paper-table-wrap { overflow-x: visible; }
  .paper-positions-panel .paper-table-wrap { max-height: 46vh; overflow-y: auto; }
  .paper-trades-panel { min-height: 0; }

  /* ---------- 8. 自动交易: 概览卡与表格可读性 ---------- */
  .auto-summary { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; margin-bottom: 12px; }
  .auto-table-wrap, .auto-decision-wrap { max-height: 52vh; }
  .auto-journal-wrap { max-height: 40vh; }
}

/* ============================================================
   Mobile layout v3 (2026-10-01) — 修复真实使用中暴露的缺陷
   ① 全部股票: 排行榜不受限地把 .market-layout 撑高(593px > 布局区 333px),
                导致股票表格容器 flex:1 只能分到 0 高度 → 表格完全看不见
   ② 主题/板块: 父级 .sectors-layout 的 align-items:flex-start 使卡片区
                宽度按内容收缩(242 / 257px, 应 374px) → 卡片单列 + 右侧大片空白
   ③ 个股: 盘口面板沿用桌面 width:clamp(280px,26vw,380px), 被塞进 183px 的
                网格列 → 盘口溢出并压住核心指标, 五档数字被挤没
   作用域: 仅 <=768px; 桌面端 (>=769px) 零影响
   ============================================================ */
@media (max-width: 768px) {

  /* ---------- ① 全部股票: 排行榜限高, 表格获得可用高度 ---------- */
  #panel-market .market-layout {
    flex: none;                 /* 不再只切分剩余高度 */
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  #panel-market .market-side {
    width: 100%;
    flex: none;
    flex-direction: row;
    gap: 8px;
    min-height: 0;
  }
  #panel-market .hot-stock-panel,
  #panel-market .channel-panel {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    max-height: 322px;          /* 排行榜封顶, 列表内部滚动 */
  }
  #panel-market .hot-stock-head { padding: 8px 10px 6px; }
  #panel-market .hot-stock-title { font-size: 13px; }
  #panel-market .hot-stock-meta { padding: 0 10px 4px; font-size: 10px; }
  #panel-market .hot-stock-list { flex: 1 1 auto; max-height: 178px; }
  #panel-market .hs-row { padding: 5px 10px; font-size: 12px; }

  /* 股票表格: 固定可用高度 + 内部滚动, 表头吸顶, 分页随手可点
     注意用 display:block —— 父级若保持 flex-column, 表格会被 flex-shrink 压扁 */
  #panel-market .market-table-panel {
    display: block;
    flex: none;
    min-height: 0;
    height: clamp(340px, 58vh, 620px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  #panel-market .market-table thead th {
    position: sticky;
    top: 0;
    z-index: 6;
    background: var(--bg-panel);
    box-shadow: 0 1px 0 var(--border);
  }
  #panel-market .market-table-panel .pagination { margin: 8px 0 4px; }

  /* 工具栏: 搜索框独占一行, 其余并排, 元信息换行 */
  #panel-market .market-toolbar .search-input { flex: 1 1 100%; }
  #panel-market .market-toolbar .board-select-custom { flex: 0 1 auto; min-width: 0; }
  #panel-market .market-toolbar .filter-wrap { flex: 0 0 auto; }
  #panel-market .market-meta { flex: 1 1 100%; justify-content: flex-start; }

  /* ---------- ② 主题 / 板块: 修宽度塌缩 + 卡片双列 ---------- */
  #panel-themes .sectors-layout,
  #panel-sectors .sectors-layout {
    flex-direction: column;
    align-items: stretch;       /* 关键: 默认 flex-start 会让卡片区宽度按内容收缩 */
    gap: 8px;
  }
  #panel-themes .sectors-main,
  #panel-sectors .sectors-main {
    width: 100%;
    flex: none;
    min-width: 0;
  }
  #panel-themes .hot-rank-panel,
  #panel-sectors .hot-rank-panel {
    width: 100%;
    position: static;
    max-height: 268px;
  }
  #panel-themes .hot-rank-head,
  #panel-sectors .hot-rank-head { padding: 9px 12px 7px; }
  #panel-themes .hot-rank-list,
  #panel-sectors .hot-rank-list {
    flex: 1 1 auto;
    max-height: 194px;
  }
  .card-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .card-grid .ts-header { padding: 9px 10px; gap: 8px; }
  .card-grid .ts-title h3 { font-size: 13px; line-height: 1.25; }
  .card-grid .ts-desc { font-size: 10px; }
  .card-grid .ts-change { font-size: 14px; }
  .card-grid .btn-primary.sm { padding: 6px 8px; font-size: 12px; }

  /* ---------- ③ 个股: 面板栈内每块独占整行 ----------
     ⚠️ 2026-10-03 v4: 手机端页面本来就纵向滚动(桌面端"零滚动"的约束不适用手机),
        所以这里不再给面板栈设固定高, 而是每块按内容撑开 +
        面板栈自身不滚动, 交给页面滚 —— 否则会变成"页面滚到底还要在面板里再滚一次"。
        .ps-body 的 flex:1/min-height:0 在内容自适应下会把 ps-pane 压成 0 高,
        这里显式改回 auto。 */
  .ps-body { flex: none; }
  .ps-body > .ps-pane { flex: none; min-height: 0; overflow: visible; }
  .ps-tabs { overflow-x: auto; scrollbar-width: none; }
  .ps-tabs::-webkit-scrollbar { display: none; }
  .ps-tab { flex: 0 0 auto; min-width: 78px; font-size: 12.5px; padding: 8px 10px; }
  .panel-stack { flex: none; overflow: visible; }
  .stock-panel .order-book {
    flex: none;
    overflow: visible;
    padding: 4px 10px 8px;
  }
  .stock-panel .ob-wrap { height: auto; gap: 4px; }
  .stock-panel .ob-columns { flex: none; gap: 0 14px; }
  .stock-panel .ob-col { justify-content: flex-start; gap: 4px; }
  .stock-panel .ob-row { font-size: 13px; padding: 2px 0; }
  .stock-panel .ob-label { width: 30px; font-size: 11px; }
  .stock-panel .ob-price { font-size: 13px; }
  .stock-panel .ob-volume { width: 62px; font-size: 12px; }
  .stock-panel .trade-info-panel { width: 100%; min-width: 0; }
  .stock-panel .indicator-grid.compact { gap: 8px 12px; }

  /* ---------- ④ 排行榜 tab: 桌面本是 2×2, 旧移动规则改成 nowrap 横滑后
       "成交额 / 换手率" 被滑出视野(只看得到 2 个)。恢复 2×2, 4 个全部可见 ---------- */
  #panel-market .hot-stock-tabs {
    flex-wrap: wrap;
    overflow: visible;
    -webkit-overflow-scrolling: auto;
    scrollbar-width: auto;
  }
  #panel-market .hs-tab {
    flex: 1 1 calc(50% - 2px);
    min-width: 0;
    min-height: 30px;
    padding: 4px 6px;
    font-size: 11px;
  }
  #panel-market .hot-stock-title { font-size: 13px; }
  #panel-market .hot-stock-title-row { gap: 4px; }
  #panel-market .chf-btn { padding: 3px 7px; font-size: 10px; border-radius: var(--r-sm); }

  /* ---------- ⑤ 主题/板块卡片: 按钮瘦身, 一屏信息量更大 ---------- */
  .card-grid .btn-primary.sm { padding: 5px 8px; font-size: 11px; }
  .card-grid .ts-title h3 { font-size: 12.5px; }

  /* ---------- ⑥ 走势评级汇总条: 压缩纵向占用, 把首屏让给股票表格 ---------- */
  #panel-market .trend-rating-strip { gap: 6px; margin: 4px 0 0; }
  #panel-market .tr-card { padding: 7px 9px; min-width: 0; }
  #panel-market .tr-card-count { font-size: 17px; }
  #panel-market .tr-card-top1 { font-size: 10px; }
}

/* ============================================================
   Mobile v4 专用元素(桌面端一律不显示)
   .nt-ico / .nt-mini: 底部 tab 的图标与手机端短标题, 桌面端只保留 .nt-full
   .m-subnav: 手机端二级分段导航容器, 由 app.js 的 renderMobileSubNav() 填充
   ============================================================ */
.nt-ico, .nt-mini { display: none; }
.m-subnav { display: none; }
.m-collapse-toggle { display: none; }

/* ============================================================
   Mobile layout v4 (2026-10-02) — 手机端原生行情 App 化改造
   ------------------------------------------------------------
   设计原则(本次与 v2/v3 的根本区别):
     v2/v3 的思路是「把桌面布局压进手机」——表格裁列、面板堆叠, 本质仍是桌面信息架构。
     本版改为按移动端行情软件(同花顺/东方财富)的惯例重新组织:
       ① 信息架构: 9 个平级 tab → 5 个底部主入口 + 入口内二级分段控件
       ② 列表形态: 多列表格 → 卡片行(左名称代码 / 右大字价格+涨跌幅)
       ③ 个股页  : 大字价格头 + 3 列指标网格 + 分段周期切换 + 加高五档盘口
       ④ 视觉语言: 完全沿用桌面端的配色/字体/圆角/边框, 只改排布密度与层级
     作用域: 仅 <=768px, 位于文件末尾同权重覆盖 v2/v3; 桌面端 (>=769px) 零影响。
   ============================================================ */
@media (max-width: 768px) {

  /* ========== ① 底部主入口: 5 个(图标 + 文字), 同花顺式 ========== */
  .nav-tabs {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0;
    padding: 4px 2px calc(4px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--bg-dark) 98%, transparent);
    border-top: 1px solid var(--border-light);
  }
  .nav-tab {
    flex-direction: column;
    gap: 2px;
    min-height: 46px;
    padding: 3px 0 1px;
    font-size: 10.5px;
    line-height: 1.1;
    border-radius: 0;
    background: transparent !important;
    box-shadow: none !important;
    color: var(--text-muted);
    position: relative;
  }
  .nav-tab .nt-ico { display: block; font-size: 17px; line-height: 1; opacity: 0.75; }
  .nav-tab .nt-mini { display: block; }
  .nav-tab .nt-full { display: none; }
  .nav-tab.active { color: var(--accent); }
  .nav-tab.active .nt-ico { opacity: 1; }
  /* 顶部细高亮条 = 选中指示(比整块底色更接近原生底部栏) */
  .nav-tab.active::before {
    content: '';
    position: absolute; top: -4px; left: 50%;
    transform: translateX(-50%);
    width: 20px; height: 2px;
    background: var(--accent);
    border-radius: 0 0 2px 2px;
  }
  .nav-tab:active { color: var(--text-primary); }
  /* 白名单: 手机端只显示显式声明 data-morder 的入口, 其余(已下沉为二级分段控件的
     market/themes/sectors/auto/data)一律不占底部位置。
     ⚠️ 这里必须是白名单而不是逐条 display:none 的黑名单 —— 黑名单漏掉一个就会多出一个
     格子: 新增的「数据处理」只带 .nt-full(手机端 display:none) → 变成"占位却不可见的
     空格子" + order:0 抢到第一格, 把「全球」挤到第二排(底部栏 54px → 101px 并压住内容)。 */
  .nav-tabs .nav-tab:not([data-morder]) { display: none; }
  /* 手机端底部顺序: ⭐自选 → 📊行情 → 📈个股 → 💰交易 → 🧠AI → 📰资讯 → 🌍全球
     7 个入口在 5 列网格里自动折成两行(第一行 5 个, 第二行 资讯+全球),
     底部栏高度随之从 54px 涨到约 100px —— 必须同步调大 .main-layout 的 padding-bottom,
     否则最后一屏内容会被底部栏永久压住。 */
  .nav-tab[data-morder="1"] { order: 1; }
  .nav-tab[data-morder="2"] { order: 2; }
  .nav-tab[data-morder="3"] { order: 3; }
  .nav-tab[data-morder="4"] { order: 4; }
  .nav-tab[data-morder="5"] { order: 5; }
  .nav-tab[data-morder="6"] { order: 6; }
  .nav-tab[data-morder="7"] { order: 7; }

  /* 底部栏总高 = 46×2 + 8 = 100, 加安全区后再多留 12px 呼吸空间 */
  .main-layout { padding-bottom: calc(112px + env(safe-area-inset-bottom, 0px)); }

  /* ========== 二级分段导航 ========== */
  .m-subnav {
    display: flex;
    /* gap/padding 缩小是为了让 6 个二级项在 390px 屏上**一屏装完**：
       「概念板块/行业板块/全部股票/数据处理」都是 4 字，均分会被裁、按内容又会超出屏宽 23px */
    gap: 4px;
    flex-shrink: 0;
    padding: 6px 8px;
    background: var(--bg-dark);
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .m-subnav::-webkit-scrollbar { display: none; }
  .msub-btn {
    /* 不许用 `flex: 1 1 0` 均分：4 字标签（全部股票/概念板块/行业板块/数据处理）
       在 390px 屏上每格只有 57px，字数一多就被裁掉 4px（实测「全部股票」一直如此）。
       改成 basis=auto（按内容宽度）后再均分剩余空间；真装不下时外层 .m-subnav 自己横滚。 */
    flex: 1 0 auto;
    min-width: 0;
    min-height: 32px;
    padding: 5px 6px;
    font-family: inherit;
    font-size: 12.5px;
    white-space: nowrap;
    color: var(--text-secondary);
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    -webkit-tap-highlight-color: transparent;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .msub-btn.active {
    color: var(--cyan);
    font-weight: 600;
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  }
  .msub-btn:active { background: var(--bg-hover); }

  /* 顶栏压成 App 标题栏: 品牌 + 指数条 + 时钟 */
  .top-bar {
    min-height: 44px;
    padding: calc(5px + env(safe-area-inset-top, 0px)) 10px 5px;
    gap: 8px;
    background: var(--bg-dark);
    border-bottom: 1px solid var(--border);
  }
  .brand-text { font-size: 15px; }
  .clock { font-size: 12px; }
  /* 刷新状态只保留状态点(颜色仍表达 ok/warn/bad/paused), 文字在手机上会把
     顶栏撑爆 —— 实测 "自动刷新…" 状态文案让 .top-actions 宽达 256px */
  #pollHbText { display: none; }
  .poll-hb { padding: 4px; border-radius: 50%; }
  .top-actions { gap: 8px; }
  .market-ticker { flex: 1 1 0; min-width: 0; }

  /* ========== ② 多列表格 → 卡片行 ==========
     统一做法: table/tbody 改 block, tr 改 grid + grid-template-areas,
     表头隐藏, 每行 = 一张独立卡片。桌面端完全不受影响(全部选择器在媒体查询内)。 */
  #watchlistTable, #watchlistTable tbody,
  #marketTable, #marketTable tbody,
  .board-table, .board-table tbody,
  .rank-table, .rank-table tbody,
  #paperPositionsTable, #paperPositionsTable tbody,
  #paperTradesTable, #paperTradesTable tbody { display: block; width: 100%; }
  #watchlistTable thead, #marketTable thead, .board-table thead,
  .rank-table thead, #paperPositionsTable thead, #paperTradesTable thead { display: none; }
  #watchlistTable td, #marketTable td, .board-table td, .rank-table td,
  #paperPositionsTable td, #paperTradesTable td {
    display: block;
    padding: 0;
    border: none;
    white-space: nowrap;
  }
  #watchlistTable tr, #marketTable tr, .board-table tr, .rank-table tr,
  #paperPositionsTable tr, #paperTradesTable tr {
    align-items: center;
    column-gap: 10px;
    row-gap: 1px;
    padding: 9px 12px;
    margin-bottom: 6px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    -webkit-tap-highlight-color: transparent;
  }
  #watchlistTable tr:active, #marketTable tr:active, .board-table tr:active,
  .rank-table tr:active, #paperPositionsTable tr:active { background: var(--bg-hover); }
  /* 加载/空态行: 单格跨满整行(必须排在 nth-child 隐藏规则之后才能生效) */
  #watchlistTable td[colspan], #marketTable td[colspan], .board-table td[colspan],
  .rank-table td[colspan], #paperPositionsTable td[colspan], #paperTradesTable td[colspan] {
    display: block !important;
    grid-area: auto !important;
    grid-column: 1 / -1;
    text-align: center;
    color: var(--text-muted);
    padding: 22px 0;
    font-size: 12.5px;
  }
  /* ⚠️ 上面 `#xxx td { display:block }` 用的是 ID 选择器, 特异性 (1,0,1) 会盖掉
     v2 里 `.class td:nth-child(n) { display:none }` 的 (0,2,1) —— 被裁掉的列会
     全部复活并挤进网格。所以这里必须用同等的 ID 特异性把该隐藏的列重新声明一遍。 */
  #watchlistTable td:nth-child(4), #watchlistTable td:nth-child(6),
  #watchlistTable td:nth-child(7), #watchlistTable td:nth-child(8),
  #watchlistTable td:nth-child(9), #watchlistTable td:nth-child(10),
  #watchlistTable td:nth-child(11) { display: none; }
  #marketTable td:nth-child(1) { display: none; }
  #paperTradesTable td:nth-child(5), #paperTradesTable td:nth-child(6),
  #paperTradesTable td:nth-child(7) { display: none; }

  /* 名称/代码两行文本的统一排版 */
  #watchlistTable .rank-name, #marketTable .rank-name, .board-table .rank-name,
  .rank-table .rank-name, #paperPositionsTable .pt-name, #paperTradesTable .pt-name {
    font-size: 14.5px;
    font-weight: 600;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #watchlistTable .rank-code, #marketTable .rank-code, .board-table .rank-code,
  .rank-table .rank-code, #paperPositionsTable .pt-code, #paperTradesTable .pt-code {
    font-size: 10.5px;
    line-height: 1.3;
    color: var(--text-muted);
    font-family: var(--font-mono);
  }

  /* ---- 自选清单: 名称/代码 | 现价/涨跌幅 | ✕ ---- */
  #watchlistTable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "wl-name wl-price wl-del"
      "wl-code wl-chg   wl-del";
  }
  #watchlistTable td:nth-child(1) { grid-area: wl-name; }
  #watchlistTable td:nth-child(2) { grid-area: wl-code; }
  #watchlistTable td:nth-child(3) { grid-area: wl-price; }
  #watchlistTable td:nth-child(5) { grid-area: wl-chg; }
  #watchlistTable td:nth-child(12) { grid-area: wl-del; }
  #watchlistTable .wt-name, #watchlistTable .wt-code { max-width: none; }
  #watchlistTable .wt-name { font-size: 15px; font-weight: 600; line-height: 1.25; }
  #watchlistTable .wt-code { font-size: 10.5px; line-height: 1.3; }
  #watchlistTable td:nth-child(3) {
    font-size: 17px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.2;
  }
  #watchlistTable td:nth-child(5) {
    font-size: 12.5px; font-weight: 600; text-align: right;
    font-family: var(--font-mono); line-height: 1.3;
  }
  /* 删除按钮: 收成圆形图标, 不再占用一列文字宽度 */
  #watchlistTable .wt-remove {
    width: 26px; height: 26px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--border);
    color: var(--text-muted);
  }
  #watchlistTable .wt-remove::before { content: '✕'; font-size: 12px; }
  #watchlistTable .wt-remove:active { color: var(--up); border-color: color-mix(in srgb, var(--up) 50%, transparent); }

  /* ---- 全部股票: 名称/代码 | 评级/成交额 | 现价/涨跌幅 ---- */
  #marketTable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "mk-name mk-rating mk-price"
      "mk-name mk-amount mk-chg";
  }
  #marketTable td:nth-child(2) { grid-area: mk-name; }
  #marketTable td:nth-child(3) { grid-area: mk-price; }
  #marketTable td:nth-child(4) { grid-area: mk-chg; }
  #marketTable td:nth-child(5) { grid-area: mk-amount; }
  #marketTable td:nth-child(8) { grid-area: mk-rating; }
  #marketTable td:nth-child(6), #marketTable td:nth-child(7),
  #marketTable td:nth-child(9) { display: none; }
  #marketTable td:nth-child(2) .rank-name,
  #marketTable td:nth-child(2) .rank-code { max-width: none; }
  #marketTable td:nth-child(3) {
    font-size: 17px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.2;
  }
  #marketTable td:nth-child(4) {
    font-size: 12.5px; font-weight: 600; text-align: right;
    font-family: var(--font-mono); line-height: 1.3;
  }
  #marketTable td:nth-child(5) { font-size: 11px; text-align: right; line-height: 1.4; }
  #marketTable td:nth-child(5)::before { content: '额 '; color: var(--text-muted); }
  #marketTable td:nth-child(8) { text-align: right; }
  .market-table .mkt-rating { padding: 1px 7px; border-radius: 999px; font-size: 10.5px; }

  /* ---- 涨跌幅榜(全景 TOP10): 名称/代码 | 换手 | 现价/涨幅 ---- */
  .rank-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "rk-name rk-turn rk-price"
      "rk-name rk-turn rk-chg";
  }
  .rank-table td:nth-child(1) { grid-area: rk-name; }
  .rank-table td:nth-child(2) { grid-area: rk-price; }
  .rank-table td:nth-child(3) { grid-area: rk-chg; }
  .rank-table td:nth-child(4) { grid-area: rk-turn; }
  .rank-table td:nth-child(2) {
    font-size: 15px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.25;
  }
  .rank-table td:nth-child(3) {
    font-size: 14px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.3;
  }
  .rank-table td:nth-child(4) { font-size: 10.5px; text-align: right; padding-right: 6px; opacity: 0.85; }
  .rank-table td:nth-child(4)::before { content: '换手 '; color: var(--text-muted); }

  /* ---- 板块成分股: 名称/代码 | 现价/涨跌幅 ---- */
  .board-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "bd-name bd-price"
      "bd-name bd-chg";
  }
  .board-table td:nth-child(2) { grid-area: bd-name; }
  .board-table td:nth-child(3) { grid-area: bd-price; }
  .board-table td:nth-child(4) { grid-area: bd-chg; }
  .board-table td:nth-child(3) {
    font-size: 16px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.25;
  }
  .board-table td:nth-child(4) {
    font-size: 13px; font-weight: 600; text-align: right;
    font-family: var(--font-mono); line-height: 1.3;
  }

  /* ---- 模拟盘·持仓: 名称 | 成本/现价 | 浮盈 | 卖出 ---- */
  #paperPositionsTable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto auto;
    grid-template-areas:
      "pp-name pp-cost pp-pnl pp-act"
      "pp-name pp-price pp-pnl pp-act";
    column-gap: 8px;
  }
  #paperPositionsTable td:nth-child(1) { grid-area: pp-name; }
  #paperPositionsTable td:nth-child(4) { grid-area: pp-cost; }
  #paperPositionsTable td:nth-child(5) { grid-area: pp-price; }
  #paperPositionsTable td:nth-child(7) { grid-area: pp-pnl; }
  #paperPositionsTable td:nth-child(9) { grid-area: pp-act; }
  #paperPositionsTable td:nth-child(2), #paperPositionsTable td:nth-child(3),
  #paperPositionsTable td:nth-child(6), #paperPositionsTable td:nth-child(8) { display: none; }
  #paperPositionsTable td:nth-child(4),
  #paperPositionsTable td:nth-child(5) {
    font-size: 12.5px; text-align: right; font-family: var(--font-mono);
  }
  #paperPositionsTable td:nth-child(4)::before { content: '成本 '; color: var(--text-muted); font-family: inherit; }
  #paperPositionsTable td:nth-child(5)::before { content: '现价 '; color: var(--text-muted); font-family: inherit; }
  #paperPositionsTable td:nth-child(7) {
    font-size: 14px; font-weight: 700; text-align: right;
    font-family: var(--font-mono); line-height: 1.25;
  }
  #paperPositionsTable .pt-sell-btn { padding: 5px 10px; font-size: 12px; }

  /* ---- 模拟盘·成交: 名称 | 价格/方向 | 盈亏 ---- */
  #paperTradesTable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "pt-name pt-price pt-pnl"
      "pt-time pt-dir   pt-pnl";
  }
  #paperTradesTable td:nth-child(1) { grid-area: pt-time; }
  #paperTradesTable td:nth-child(2) { grid-area: pt-name; }
  #paperTradesTable td:nth-child(3) { grid-area: pt-dir; }
  #paperTradesTable td:nth-child(4) { grid-area: pt-price; }
  #paperTradesTable td:nth-child(8) { grid-area: pt-pnl; }
  #paperTradesTable td:nth-child(1) { font-size: 10.5px; color: var(--text-muted); }
  #paperTradesTable td:nth-child(4) {
    font-size: 12.5px; text-align: right; font-family: var(--font-mono);
  }
  #paperTradesTable td:nth-child(8) {
    font-size: 13px; font-weight: 700; text-align: right;
    font-family: var(--font-mono);
  }

  /* ---- 全部股票: 表格容器改自然高度, 由页面统一滚动(更像原生 App) ---- */
  #panel-market .market-table-panel {
    height: auto;
    max-height: none;
    overflow: visible;
  }
  /* 首屏优先级: 评级条(一行) → 排行榜折叠开关 → [展开后的排行榜] → 股票列表 */
  #panel-market .m-collapse-toggle { order: 1; }
  #panel-market .market-side { order: 2; }
  #panel-market .market-table-panel { order: 3; }
  #panel-market .market-side.m-collapsed { display: none; }
  .m-collapse-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    min-height: 40px;
    padding: 8px 12px;
    font-family: inherit;
    font-size: 12.5px;
    color: var(--text-secondary);
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    -webkit-tap-highlight-color: transparent;
  }
  .m-collapse-toggle .mct-arrow { color: var(--text-muted); transition: transform 0.2s; }
  .m-collapse-toggle.open { color: var(--text-primary); }
  .m-collapse-toggle.open .mct-arrow { transform: rotate(180deg); }
  /* 走势评级条: 5 张卡压成一行横滑, 省下约 140px 首屏高度
     ⚠️ 一旦设了 overflow-x, overflow-y 也会变成 auto, 于是这条的自动最小高度
        从「内容高度」变成 0 —— 在父级 flex column 里会被 5800px 高的股票列表
        压扁成 3px。必须显式 flex: none 锁住高度。 */
  #panel-market .trend-rating-strip {
    flex: none;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 3px;
  }
  #panel-market .trend-rating-strip::-webkit-scrollbar { display: none; }
  #panel-market .tr-card { flex: 0 0 auto; min-width: 108px; }
  /* 排行榜保持限高 + 内部滚动, 避免把股票列表挤到屏幕外 */
  #panel-market .hot-stock-panel,
  #panel-market .channel-panel { max-height: 246px; }
  #panel-market .hot-stock-list { max-height: 128px; }

  /* ========== ③ 个股页: 原生行情详情页 ========== */
  /* 头部: 名称行 → 大字价格行 → 3 列核心指标网格 */
  #panel-stock .stock-header {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 12px 14px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
  }
  #panel-stock .sh-left { flex-wrap: wrap; align-items: center; gap: 6px 8px; }
  #panel-stock .sh-name { font-size: 19px; line-height: 1.2; }
  #panel-stock .sh-code { font-size: 12px; }
  #panel-stock .sh-price-block { align-items: baseline; gap: 10px; flex-wrap: wrap; }
  #panel-stock .sh-price { font-size: 34px; line-height: 1.05; letter-spacing: -0.5px; }
  #panel-stock .sh-change, #panel-stock .sh-change-percent { font-size: 15px; font-weight: 700; }
  #panel-stock .sh-change-percent { padding: 2px 8px; border-radius: var(--r-sm); }
  #panel-stock .sh-change-percent.up { background: var(--up-bg); }
  #panel-stock .sh-change-percent.down { background: var(--down-bg); }
  #panel-stock .sh-stats {
    width: 100%;
    margin-left: 0;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 9px 8px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
  }
  #panel-stock .sh-stat { align-items: flex-start; gap: 1px; }
  #panel-stock .sh-stat-label { font-size: 10.5px; }
  #panel-stock .sh-stat-val { font-size: 13.5px; }
  /* 播报按钮: 手机端独占一行放在价格行下方(左对齐, 与名称行同宽逻辑), 点按=播报 / 长按=选内容 */
  #panel-stock .sh-bc-wrap { justify-content: flex-start; }
  #panel-stock .sh-bc-btn { padding: 8px 16px; font-size: 13px; min-height: 36px; }
  /* 全景图资讯播报按钮: 触控命中区 ≥32px; 头部右侧允许换行, 时间戳过长时收缩 */
  .pn-bc-btn { padding: 6px 12px; min-height: 32px; }
  .pn-news-right { gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
  .pn-news-right .panel-sub { font-size: 10.5px; }

  /* 涨停原因 / 走势分析: 卡片行 */
  #panel-stock .abnormal-analysis-row {
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    font-size: 12px;
  }
  #panel-stock .aa-label { flex-shrink: 0; }
  #panel-stock .aa-summary {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  #panel-stock .aa-more { flex-shrink: 0; font-size: 11px; }

  /* 周期切换: 分段控件(分时/日线/周线/月线 等分整行) */
  #panel-stock .chart-toolbar {
    padding: 6px 8px;
    gap: 6px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
  }
  #panel-stock .toolbar-left { flex-wrap: wrap; gap: 4px; width: 100%; }
  #panel-stock .period-btn {
    flex: 1 1 0;
    min-width: 56px;
    min-height: 32px;
    font-size: 12.5px;
    border-radius: var(--r-sm);
    border-color: var(--border);
  }
  #panel-stock .toolbar-left .divider { display: none; }
  #panel-stock .indicator-btn {
    flex: 0 1 auto;
    min-height: 28px;
    font-size: 11.5px;
    border-radius: var(--r-sm);
    background: rgba(255, 255, 255, 0.03);
  }
  #panel-stock .toolbar-right { width: 100%; justify-content: flex-end; }

  /* 图表: 主图更高, 副图保持紧凑 */
  #panel-stock .chart-wrapper-3 { height: 404px; min-height: 404px; border-radius: var(--r-md); }
  #panel-stock .chart-wrapper-3 > #klineChart { min-height: 236px; }
  #panel-stock .chart-wrapper-3 > .sub-slot { flex: 0 0 66px; min-height: 66px; }
  #panel-stock .subchart-tabs { gap: 6px; padding: 6px 8px; }
  #panel-stock .subchart-tab { flex: 1 1 0; min-height: 34px; justify-content: center; font-size: 12.5px; border-radius: var(--r-sm); }

  /* 五档盘口: 行高加大 + 深度条更明显(移动端拇指区块) */
  #panel-stock .order-book-panel, #panel-stock .trade-info-panel { border-radius: var(--r-md); }
  #panel-stock .ob-wrap { gap: 5px; }
  #panel-stock .ob-last-price { font-size: 17px; padding: 5px 0; }
  #panel-stock .ob-columns { gap: 0 10px; }
  #panel-stock .ob-side-label { padding: 3px 0; font-size: 11px; }
  #panel-stock .ob-row { padding: 5px 6px; font-size: 12.5px; border-radius: var(--r-sm); }
  #panel-stock .ob-row + .ob-row { margin-top: 1px; }
  #panel-stock .ob-label { width: 28px; font-size: 11px; }
  #panel-stock .ob-volume { width: 58px; font-size: 11.5px; }
  #panel-stock .ob-bar { opacity: 0.18; border-radius: var(--r-sm); }
  #panel-stock .ob-l2-hint { font-size: 10.5px; padding: 4px 0 2px; }
  #panel-stock .indicator-grid.compact { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }
  #panel-stock .stock-browser { border-radius: var(--r-md); }

  /* ========== ④ 模拟盘: 账户卡 + 下单/持仓/成交 ========== */
  .paper-summary {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    padding: 10px;
    overflow: visible;
    align-items: stretch;
  }
  .paper-summary .ps-item {
    min-width: 0;
    padding: 9px 11px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-right: 1px solid var(--border);
    border-radius: var(--r-md);
  }
  .paper-summary .ps-item:first-child { grid-column: 1 / -1; }
  .paper-summary .ps-item:first-child .ps-val { font-size: 26px; }
  .paper-summary .ps-val { font-size: 15px; }
  .paper-summary .ps-actions {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    margin-left: 0;
  }
  .paper-positions-panel .paper-table-wrap { max-height: none; overflow: visible; }
  .paper-order-panel .po-row { flex-wrap: wrap; gap: 8px; }
  .paper-order-panel .po-field { flex: 1 1 140px; min-width: 0; }
  .paper-order-panel .po-code-inputs { width: 100%; }

  /* ========== ⑤ 主题/板块: 排行榜改成顶部横滑卡片条 ==========
     桌面端的排行是左侧竖向小窗口(268px 高)。手机端若照搬, 卡片区要被推到
     屏幕下方; 但整块移到卡片之后又会掉到 276 张卡片的最底部(实测 top=14514px)
     等于不可达。折中为移动端行情软件常见的做法: 压成一条横向滑动的热榜卡片条,
     高度从 268px 降到约 95px, 首屏仍能看到 2~3 行板块卡片。 */
  .card-grid { gap: 10px; }
  .card-grid > .ts-card { border-radius: var(--r-md); }
  .card-grid .ts-header { border-radius: 11px 11px 0 0; }
  #panel-themes .hot-rank-panel, #panel-sectors .hot-rank-panel {
    flex: none;
    max-height: none;
  }
  #panel-themes .hot-rank-list, #panel-sectors .hot-rank-list {
    flex: none;
    flex-direction: row;
    gap: 8px;
    max-height: none;
    padding: 2px 2px 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #panel-themes .hot-rank-list::-webkit-scrollbar,
  #panel-sectors .hot-rank-list::-webkit-scrollbar { display: none; }
  .hot-rank-list .hr-row {
    position: relative;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    width: 122px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--bg-card);
  }
  .hot-rank-list .hr-row:last-child { border-bottom: 1px solid var(--border); }
  .hot-rank-list .hr-row:hover { background: var(--bg-hover); }
  .hot-rank-list .hr-rank {
    position: absolute;
    top: 6px;
    right: 6px;
    /* 序号从方块改成纯数字后，固定 16px 宽会把两位数（10、11）挤在一起 → 改成自适应 */
    width: auto;
    min-width: 16px;
    justify-content: flex-end;
    font-size: 11px;
  }
  .hot-rank-list .hr-info { min-width: 0; width: 100%; display: block; }
  .hot-rank-list .hr-name {
    font-size: 12.5px;
    font-weight: 600;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-right: 18px;
  }
  .hot-rank-list .hr-sub {
    font-size: 10px;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .hot-rank-list .hr-pct { font-size: 14px; font-weight: 700; font-family: var(--font-mono); }
  /* 卡片上的「查看成分股」按钮: 收成一行, 不要把卡片一半高度吃掉 */
  .card-grid .btn-primary.sm {
    min-height: 34px;
    padding: 6px 8px;
    font-size: 12px;
    border-radius: var(--r-sm);
  }

  /* ========== ⑤b 自动交易: 标题独占一行, 操作按钮一行横滑 ========== */
  #panel-auto { padding: 10px; }
  #panel-auto > .panel-header {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 0 0 10px;
  }
  #panel-auto > .panel-header h2 { font-size: 16px; }
  .auto-header-right {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 6px;
    padding-bottom: 2px;
  }
  .auto-header-right::-webkit-scrollbar { display: none; }
  .auto-mode-badge, .auto-polling, .auto-run-btn, .auto-config-btn {
    flex: 0 0 auto;
    min-height: 30px;
    padding: 5px 10px;
    font-size: 11.5px;
    white-space: nowrap;
  }
  .auto-run-btn, .auto-config-btn { display: inline-flex; align-items: center; border-radius: var(--r-sm); }

  /* ========== ⑥ 通用细节: 触摸反馈 / 吸顶 / 隐藏冗余提示 ========== */
  .main-content { padding: 8px; gap: 8px; }
  .panel-header { padding: 9px 12px; }
  .panel-sub { display: none; }        /* 手机端省掉说明性副标题, 把首屏让给数据 */
  #panel-market .market-meta { font-size: 11px; }
  .pagination { flex-wrap: wrap; gap: 5px; }
  .pagination button { min-width: 32px; min-height: 32px; }

  /* K线/分时: 纵向滑动交给页面滚动(横拖与双指缩放仍归图表) */
  #klineChart, #volumeChart, #macdChart, #capitalChart { touch-action: pan-y pinch-zoom; }
}

/* ============================================================
   指数条下沉为整宽底栏 (2026-10-02)
   ------------------------------------------------------------
   问题: 顶栏一行里 brand + 9 个 nav-tab + top-actions 已占满宽度,
         .market-ticker 只剩 flex:1 的残余空间 —— 实测 5 个指数
         (上证/深证/创业板/科创50/北证50) 只露出 2.5 个, 后面的被
         overflow:hidden 直接裁掉, 用户看不到科创50 与 北证50。
   方案: 桌面端把它拉到窗口最底部, 成为一条独立整宽横条, 每个指数
         等分宽度并居中 → 5 个全可见, 且不再与导航抢顶栏空间。
   作用域: 仅 >=769px。手机端底部已被固定 .nav-tabs 占用, 指数条
         保持原样(顶栏内横向滚动)—— 那是移动端行情软件的惯例。
   ============================================================ */
@media (min-width: 769px) {
  /* 预留出固定底栏的高度, 让 .main-layout 真正变矮, 而不是被盖住 */
  .app-scale { padding-bottom: var(--ticker-h); }

  .market-ticker {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--ticker-h);
    z-index: 85;                    /* 低于 modal(1000) 与 loading(9999) */
    gap: 0;
    padding: 0;
    background: var(--bg-dark);
    border-top: 1px solid var(--border);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.35);
    /* 兜底: 窗口极窄时等分会导致文字挤压 → 宁可整体横滚, 也不裁掉任何指数 */
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
  }
  .market-ticker::-webkit-scrollbar { display: none; }

  /* flex-basis:0 + grow 等分 → 每个指数宽度完全一致;
     min-width:max-content 保证内容永远不换行/不被压缩, 这是"显示不全"的根治点 */
  .market-ticker .ticker-item {
    flex: 1 1 0;
    min-width: max-content;
    justify-content: center;
    gap: 8px;
    padding: 0 12px;
    border-left: 1px solid var(--border);
  }
  .market-ticker .ticker-item:first-child { border-left: none; }

  /* 底栏有整条宽度可用, 顺便把字号提上来, 远处也能看清 */
  .market-ticker .ticker-name { font-size: 12.5px; }
  .market-ticker .ticker-price { font-size: 14px; }
  .market-ticker .ticker-change { font-size: 12px; padding: 2px 6px; }

  /* 指数条离开顶栏后, 右侧动作区失去 flex:1 的推挤, 需自己贴住右边缘 */
  .top-actions { margin-left: auto; }
}

/* 中等宽度窗口(769~1200px): 收紧内边距与字号, 让 5 个指数仍能在一整条内放下,
   避免退化成横向滚动(实测 900px 宽时原始尺寸需 941px, 差 41px) */
@media (min-width: 769px) and (max-width: 1200px) {
  .market-ticker .ticker-item { padding: 0 8px; gap: 6px; }
  .market-ticker .ticker-name { font-size: 12px; }
  .market-ticker .ticker-price { font-size: 13px; }
  .market-ticker .ticker-change { font-size: 11.5px; padding: 1px 5px; }
}

/* ==================== 数据处理面板 ==================== */
/* 语义色与涨跌色分开: 状态用"健康/警告/错误", 与个股涨红跌绿不共享语义 */
:root {
  --dp-ok: var(--down);
  --dp-warn: var(--gold);
  --dp-err: var(--up);
  --dp-live: var(--cyan);
}

#panel-data { overflow-y: auto; }

.dp-header-right { display: flex; align-items: center; gap: 10px; }
.dp-updated { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.dp-btn {
  padding: 5px 12px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--bg-card); border: 1px solid var(--border-light);
  color: var(--text-primary); font-size: 12px; transition: background .15s, border-color .15s;
}
.dp-btn:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--accent); }
.dp-btn:disabled { opacity: .55; cursor: default; }

/* 顶部速览条: 六个一眼可见的事实 */
.dp-strip {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px; margin-bottom: 12px;
}
.dp-strip-cell {
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--bg-panel); border: 1px solid var(--border);
  border-left: 3px solid var(--border-light); min-width: 0;
}
.dp-strip-cell.ok { border-left-color: var(--dp-ok); }
.dp-strip-cell.warn { border-left-color: var(--dp-warn); }
.dp-strip-cell.live { border-left-color: var(--dp-live); }
.dp-sc-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; white-space: nowrap; }
.dp-sc-val {
  font-size: 17px; font-weight: 600; color: var(--text-primary);
  font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dp-sc-sub {
  font-size: 11px; color: var(--text-muted); margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 卡片网格 */
.dp-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.dp-card-wide { grid-column: 1 / -1; }
.dp-card {
  background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 12px 14px; min-width: 0;
}
.dp-card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border);
}
.dp-card-head h3 { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--text-primary); }
.dp-card-sub { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
/* SWR 过期态: 值仍是上一份统计, 必须让人看出来而不是假装是新的 */
.dp-stale { color: var(--dp-warn, var(--gold)); }
.dp-card-body { font-size: 12px; }

/* 键值行 */
.dp-kv {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding: 4px 0; border-bottom: 1px dashed rgba(255, 255, 255, .04);
}
.dp-kv:last-child { border-bottom: none; }
.dp-k { color: var(--text-secondary); flex: none; }
.dp-v {
  color: var(--text-primary); text-align: right; font-variant-numeric: tabular-nums;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dp-v.accent { color: var(--accent); }
.dp-v.ok { color: var(--dp-ok); }
.dp-v.warn { color: var(--dp-warn); }
.dp-v.err { color: var(--dp-err); }
.dp-v.flat { color: var(--flat); }

.dp-sub-head {
  font-size: 11px; color: var(--text-muted); margin: 10px 0 4px;
  padding-top: 6px; border-top: 1px solid var(--border);
}
.dp-rows { display: flex; flex-direction: column; }

/* 小格子(数据库表/熔断器) */
.dp-cells { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
.dp-cell {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding: 5px 8px; border-radius: var(--r-sm); background: var(--bg-card); font-size: 11.5px; min-width: 0;
}
.dp-cell-l { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-cell-v { color: var(--text-primary); font-variant-numeric: tabular-nums; flex: none; }
.dp-cell-v.ok { color: var(--dp-ok); }
.dp-cell-v.err { color: var(--dp-err); }

/* 进度条 */
.dp-prog-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: 11.5px; color: var(--text-secondary); }
.dp-prog-head span { font-variant-numeric: tabular-nums; }
.dp-bar { height: 6px; border-radius: var(--r-xs); background: var(--bg-darkest); overflow: hidden; margin-bottom: 10px; }
.dp-bar-fill { height: 100%; background: var(--accent); border-radius: var(--r-xs); transition: width .4s ease; }
.dp-bar-fill.live { background: var(--dp-live); }

/* 徽章 */
.dp-badge {
  display: inline-block; padding: 1px 7px; border-radius: var(--r-xs); font-size: 11px; flex: none;
  background: var(--bg-card); color: var(--text-secondary); border: 1px solid var(--border-light);
}
.dp-badge.ok { color: var(--dp-ok); border-color: color-mix(in srgb, var(--down) 40%, transparent); background: color-mix(in srgb, var(--down) 10%, transparent); }
.dp-badge.warn { color: var(--dp-warn); border-color: color-mix(in srgb, var(--gold) 40%, transparent); background: color-mix(in srgb, var(--gold) 10%, transparent); }
.dp-badge.live { color: var(--dp-live); border-color: color-mix(in srgb, var(--cyan) 40%, transparent); background: color-mix(in srgb, var(--cyan) 10%, transparent); }

/* 提示条 */
.dp-note {
  margin-top: 8px; padding: 6px 9px; border-radius: var(--r-sm); font-size: 11.5px; line-height: 1.5;
  background: var(--bg-card); color: var(--text-secondary); border-left: 3px solid var(--border-light);
}
.dp-note.ok { border-left-color: var(--dp-ok); color: var(--text-secondary); }
.dp-note.warn { border-left-color: var(--dp-warn); color: var(--text-secondary); }
.dp-note.err { border-left-color: var(--dp-err); color: var(--up); }
.dp-empty { padding: 14px 4px; color: var(--text-muted); font-size: 12px; text-align: center; }

/* 数据源表 (2026-10-04)
   「数据源健康」从"4 个熔断器小格子"改成"全量 16 个外部接口的表格" ——
   原先没登记的源挂掉, 面板上看不出来(东财 push2 集群整片不可达那次就是)。
   列宽口径: 名称/主机给"内容量级"的上限, 中间放一条弹性占位轨把三个指标列推到右边界。
   ⚠️ 不能用 `1fr 1.5fr` 均分余量 —— 1750px 的宽卡里, 90px 的文字会被摊进 600px 的轨道,
      看上去就是"名称和主机各飘在半空"(实测过, 见 14-踩坑档案 §8)。
   ⚠️ 占位轨是第 3 个 DOM 子元素, 手机端隐藏它时必须同时隐藏主机与失败数 ——
      隐藏后可见子元素 3 个正好对上 3 条轨道; 只藏 1 个会让剩下的元素被挤到第二行。 */
.src-table { display: flex; flex-direction: column; }
.src-row {
  display: grid;
  grid-template-columns:
    minmax(104px, 200px)          /* 名称 + 角色徽章 */
    minmax(150px, 236px)          /* 主机(最长 np-anotice-stock.eastmoney.com) */
    minmax(0, 1fr)                /* 弹性占位轨: 把指标列推到右边界 */
    94px 84px 52px;               /* 状态 / 最近成功 / 失败 */
  gap: 10px; align-items: baseline;
  padding: 4px 6px; font-size: 11.5px;
}
.src-row + .src-row { border-top: 1px dashed rgba(255, 255, 255, .05); }
.src-row.head {
  font-size: 10.5px; padding-bottom: 3px;
  border-top: none; border-bottom: 1px solid var(--border);
}
.src-row.head span { color: var(--text-muted); }
.src-row.flag { background: color-mix(in srgb, var(--gold) 7%, transparent); }
.src-name { display: flex; align-items: baseline; gap: 6px; min-width: 0; color: var(--text-primary); }
.src-role {
  flex: none; font-size: 9.5px; line-height: 15px; padding: 0 4px; border-radius: var(--r-xs);
  background: var(--bg-card); color: var(--text-muted); border: 1px solid var(--border-light);
}
.src-role.fallback { color: var(--dp-warn); border-color: color-mix(in srgb, var(--gold) 35%, transparent); }
.src-role.proxy { color: var(--dp-live); border-color: color-mix(in srgb, var(--cyan) 35%, transparent); }
/* 增补源(2026-10-22): 多源资讯里"并列而非兜底"的那一类 —— 它挂了不会走替代,
   只会让这类资讯少一家, 所以必须和 fallback 在视觉上分开。 */
.src-role.supplement { color: var(--purple); border-color: color-mix(in srgb, var(--purple) 35%, transparent); }
/* 副源(同花顺): 与"兜底"区分开 —— 兜底是"主源挂了才用", 副源是"同一份数据换个来源再取一遍",
   两者在面板上的语义不同, 颜色也要不同, 否则整片同色看不出分组 */
.src-role.secondary { color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 40%, transparent); }

/* 多源资讯每档产出（数据处理面板） */
.dp-feeds { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 5px; }
.dp-feed {
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  font-size: 10px;
  color: var(--text-muted);
  white-space: nowrap;
}
.dp-feed.ok { color: var(--down); border-color: color-mix(in srgb, var(--down) 35%, transparent); }
.dp-feed.warn { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 35%, transparent); }
.src-host { color: var(--text-muted); font-size: 10.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.src-st { font-variant-numeric: tabular-nums; }
.src-st.ok { color: var(--dp-ok); }
.src-st.warn { color: var(--dp-warn); }
.src-st.err { color: var(--dp-err); }
.src-st.idle { color: var(--text-muted); }
.src-ago, .src-err { color: var(--text-secondary); font-variant-numeric: tabular-nums; text-align: right; }

/* 滞后股票 chips */
.dp-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.dp-chip {
  display: inline-flex; align-items: baseline; gap: 4px; padding: 3px 7px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--gold) 10%, transparent); border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent);
  color: var(--dp-warn); font-size: 11px; font-variant-numeric: tabular-nums;
}
.dp-chip i { font-style: normal; opacity: .7; font-size: 10px; }

/* 评级分布 */
.dp-rating-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: 11.5px; }
.dp-rating-name { width: 34px; flex: none; color: var(--text-secondary); }
.dp-rating-bar { flex: 1 1 auto; height: 8px; border-radius: var(--r-xs); background: var(--bg-darkest); overflow: hidden; min-width: 0; }
.dp-rating-bar i { display: block; height: 100%; border-radius: var(--r-xs); }
.dp-rating-bar i.up { background: var(--up); }
.dp-rating-bar i.down { background: var(--down); }
.dp-rating-bar i.flat { background: var(--flat); }
.dp-rating-num { width: 48px; flex: none; text-align: right; color: var(--text-primary); font-variant-numeric: tabular-nums; }

/* 活动日志 */
.dp-acts { display: flex; flex-direction: column; max-height: 320px; overflow-y: auto; }
.dp-act {
  display: flex; align-items: baseline; gap: 10px; padding: 5px 2px;
  border-bottom: 1px dashed rgba(255, 255, 255, .05); font-size: 11.5px;
}
.dp-act:last-child { border-bottom: none; }
.dp-act-time { color: var(--text-muted); font-variant-numeric: tabular-nums; flex: none; }
.dp-act-kind {
  flex: none; padding: 0 6px; border-radius: var(--r-xs); font-size: 10.5px;
  background: var(--bg-card); color: var(--text-secondary); border: 1px solid var(--border-light);
}
.dp-act-kind.k-trend { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.dp-act-kind.k-limitup { color: var(--up); border-color: color-mix(in srgb, var(--up) 40%, transparent); }
.dp-act-kind.k-channel { color: var(--purple); border-color: color-mix(in srgb, var(--purple) 40%, transparent); }
.dp-act-kind.k-reports { color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 40%, transparent); }
.dp-act-kind.k-hot { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 40%, transparent); }
.dp-act-kind.k-announce { color: var(--down); border-color: color-mix(in srgb, var(--down) 40%, transparent); }
.dp-act-text { flex: 1 1 auto; color: var(--text-primary); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-act-ago { flex: none; color: var(--text-muted); }

/* 中等宽度(769~1400): 速览条两行、卡片两列 */
@media (min-width: 769px) and (max-width: 1400px) {
  .dp-strip { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 移动端: 单列 + 速览条两列。桌面端零影响 */
@media (max-width: 768px) {
  .dp-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .dp-grid { grid-template-columns: minmax(0, 1fr); }
  .dp-sc-val { font-size: 15px; }
  /* 头部改纵向堆叠: 390px 下标题与"更新时间+按钮"挤一行会把两边的文字都折行 */
  #panel-data .panel-header { flex-direction: column; align-items: flex-start; gap: 6px; }
  #panel-data .panel-header h2 { white-space: nowrap; font-size: 16px; }
  .dp-header-right { width: 100%; justify-content: space-between; gap: 6px; }
  .dp-updated { font-size: 11px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dp-btn { white-space: nowrap; flex: none; padding: 5px 10px; }
  .dp-cells { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
  .dp-acts { max-height: none; }
  .dp-act { flex-wrap: wrap; }
  .dp-act-text { white-space: normal; }
  /* 数据源表: 390px 宽塞不下 6 列(主机域名 + 失败数必然被压窄),
     按"不能横向溢出"的硬要求减列 —— 保留名称/状态/最近成功。
     ⚠️ 被隐藏的 3 个(src-host / src-gap / src-err)必须同时隐藏: 可见子元素剩 3 个,
        正好对上 3 条轨道; 少藏一个就会多出第 4 个元素被挤到下一行(零报错的错版)。 */
  .src-row { grid-template-columns: minmax(0, 1fr) 76px 64px; gap: 8px; padding: 4px 4px; }
  .src-row .src-host, .src-row .src-gap, .src-row .src-err { display: none; }
}

/* ===== 机构评级汇总 (个股详情页) =====
   数据源: 本地研报库 SQL 聚合, 与外部接口无关, 因此样式不依赖任何加载态骨架
   配色沿用「涨红跌绿」: 看多=--up(红) / 看空=--down(绿) / 中性=--flat(灰) */
.rating-panel {
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  /* ⚠️ 2026-10-03 v4: 旧版 max-height:clamp(220px,52vh,560px) 是"评级面板堆在页面最下方"
     时代的写法 —— 它与写死的 --h-bottom 相加必然超视口, 导致整页要向下滚。
     现在评级面板独占 .panel-stack 的剩余高度(不再自己限高),
     高度不够时在 .rating-body 内滚动, 而不是把页面撑出去。 */
  max-height: none;
  min-height: 0;
}
.rating-panel.collapsed { max-height: none; }
.rating-panel.collapsed .rating-body { display: none; }
.rating-panel-header { cursor: pointer; user-select: none; }
.rating-panel-header:hover { background: var(--bg-hover); }
.rating-header-right { display: flex; align-items: center; gap: 8px; }
.rating-caret { font-size: 11px; color: var(--text-muted); transition: transform .15s; }
.rating-panel.collapsed .rating-caret { transform: rotate(-90deg); }

/* 横向分栏: 小数据量内容不该硬塞进全宽纵向卡片。
   全宽纵向卡片在 1085px 面板里只有 4 个内容块, 每块都撑满整行 → 大片空白;
   改成三栏后, 概览/分布/明细各自成块, 宽度被真正用掉。 */
.rating-body {
  overflow-y: auto;
  padding: 9px 12px 12px;
  display: grid;
  /* 三栏比例 .85 : 1 : 1.3, 明细栏(第 3 栏)带 300px 内容最小宽:
     窄栏里机构名"国金证券"(46px)会被压成 36px 显示成"国金证…"(1440 视口实测)。
     左/中两栏最小宽给 0 —— 空间不够时先缩它们, 保住明细表的可读性。 */
  grid-template-columns: minmax(0, .85fr) minmax(0, 1fr) minmax(300px, 1.3fr);
  grid-template-areas:
    "left mid  orgs"
    "foot foot foot";
  align-content: start;
  align-items: start;
  gap: 10px 18px;
}
/* 左/中两栏各自包一层纵向容器: 明细表跨行会把行高撑开, 不包壳时同行的
   下半个块会被推到行底, 中间空出一条 —— 包壳后各块按自身高度紧贴排列。 */
.rating-left, .rating-mid { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.rating-left { grid-area: left; }
.rating-mid { grid-area: mid; }

/* ① 汇总 KPI */
.rating-kpis { display: flex; flex-wrap: wrap; gap: 5px 16px; font-size: 11.5px; color: var(--text-secondary); }
.rating-kpi { display: inline-flex; align-items: baseline; gap: 4px; }
.rating-kpi b { color: var(--text-primary); font-size: 13px; font-variant-numeric: tabular-nums; }
.rating-kpi b.up { color: var(--up); }
.rating-kpi b.down { color: var(--down); }
.rating-kpi b.flat { color: var(--flat); }
.rating-kpi-muted { color: var(--text-muted); }
.rating-sub { font-style: normal; font-size: 10px; color: var(--text-muted); }
.rating-sub.warn { color: var(--gold); }

/* ② 时间窗 (本地已取全量, 切窗不重新请求) */
.rating-wins { display: flex; align-items: center; gap: 4px; }
.rating-win {
  background: var(--bg-card); border: 1px solid var(--border); color: var(--text-secondary);
  font-size: 11px; padding: 2px 9px; border-radius: var(--r-xs); cursor: pointer; font-family: inherit;
}
.rating-win:hover { background: var(--bg-hover); color: var(--text-primary); }
.rating-win.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.rating-win.empty { opacity: .45; }
.rating-win-note { margin-left: auto; font-size: 10.5px; color: var(--text-muted); }

/* ③ 评级分布
   轨道不再用 flex:1 撑满 —— 单档"增持"时填充 100%, 在 1085px 面板里会变成一根
   706px 横贯全屏的红条(语义全失, 看起来像渲染坏了)。放进 1fr 网格轨后, 轨道宽度
   由所在栏宽决定(实测 ~220px), 仍是正常图表比例。 */
.rating-dist { display: flex; flex-direction: column; gap: 3px; }
.rating-dist-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) 58px; align-items: center; gap: 8px; font-size: 11.5px; }
.rating-dist-name { color: var(--text-secondary); white-space: nowrap; }
.rating-dist-bar { min-width: 0; height: 8px; border-radius: var(--r-xs); background: var(--bg-darkest); overflow: hidden; }
.rating-dist-bar i { display: block; height: 100%; border-radius: var(--r-xs); transition: width .25s; }
.rating-dist-bar i.up { background: var(--up); }
.rating-dist-bar i.down { background: var(--down); }
.rating-dist-bar i.flat { background: var(--flat); }
.rating-dist-num { width: auto; text-align: right; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.rating-dist-num em { font-style: normal; color: var(--text-muted); font-size: 10.5px; margin-left: 4px; }
.rating-verdict { margin-top: 3px; font-size: 11px; color: var(--text-secondary); }
.rating-verdict i { font-style: normal; color: var(--text-muted); font-size: 10.5px; margin-left: 4px; }

/* ④ 月度评级分布 (近12个月, 柱高=研报量, 颜色=当月看多占比)
   固定 12 轨网格: 后端只返回"有研报的月份", 直接按数据渲染会让柱数随个股变化
   (实测 TCL中环近一年只有 3 个月有研报 → 3 根柱挤在左侧, 右侧全空)。
   补齐 12 个月后柱数恒定, 缺月渲染成零高基线, "哪几个月没有覆盖"也一眼可见。 */
.rating-trend-wrap { display: flex; flex-direction: column; gap: 4px; }
.rating-trend-title { font-size: 11px; color: var(--text-muted); }
.rating-trend { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: end; gap: 3px; height: 46px; }
.rating-trend-col {
  min-width: 0; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 2px;
}
.rating-trend-col i { display: block; width: 100%; border-radius: 2px 2px 0 0; }
.rating-trend-col.zero i { background: var(--flat); opacity: .28; }
.rating-trend-col i.up { background: var(--up); }
.rating-trend-col i.down { background: var(--down); }
.rating-trend-col i.mixed { background: var(--gold); }
.rating-trend-col i.flat { background: var(--flat); opacity: .45; }
.rating-trend-col em { font-style: normal; font-size: 9px; color: var(--text-muted); }

/* ⑤ 各机构最新评级 */
.rating-orgs { display: flex; flex-direction: column; grid-area: orgs; }
.rating-orgs-note { font-size: 10.5px; color: var(--text-muted); padding-bottom: 4px; }
.rating-orgs-note b { color: var(--text-secondary); }
/* 5 轨按"窄栏"标定: 明细栏实测 363~413px(1085 面板), 旧的 6 轨最小宽 418px 会横向溢出。
   机构名吃 1fr, 其余固定宽 → 右边界天然对齐, 不需要再靠 max-width 硬凑。 */
.rating-orgs-head, .rating-org-row {
  display: grid;
  /* 单位换算后 5 轨需求: 机构名≥46 / 评级徽章 58 / 目标价 46 / 日期(08-27) 78 / 研报 26,
     加上 4×6px 间距 = 254px 起 —— 明细栏 300px 时机构名仍能拿到 94px 富余。 */
  grid-template-columns: minmax(0, 1fr) 58px 46px 78px 26px;
  align-items: center; gap: 6px; padding: 4px 2px; font-size: 11.5px;
}
.rating-orgs-head { color: var(--text-muted); font-size: 10.5px; border-bottom: 1px solid var(--border); }
.rating-org-row { border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent); }
.rating-org-row:hover { background: var(--bg-hover); }
/* 距最新研报超过 1 年的行淡化显示: 老股常被十几家机构覆盖过, 但近年可能已无人跟踪,
   与近期观点并列且同样醒目时, 会被误读成"当前多家机构一致看多" */
.rating-org-row.stale { opacity: .48; }
.rating-org-row.stale:hover { opacity: .85; }
.rating-orgs-head .ro-target, .rating-orgs-head .ro-date { text-align: right; }
.ro-org { color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ro-rating { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.ro-target, .ro-date { text-align: right; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.ro-link { text-align: right; font-size: 10.5px; color: var(--accent); cursor: pointer; }
.ro-link:hover { text-decoration: underline; }
.ro-link.disabled { cursor: default; }

.rating-badge { display: inline-block; padding: 1px 6px; border-radius: var(--r-xs); font-size: 10.5px; white-space: nowrap; }
.rating-badge.up { background: var(--up-bg); color: var(--up); }
.rating-badge.down { background: var(--down-bg); color: var(--down); }
.rating-badge.flat { background: color-mix(in srgb, var(--text-muted) 12%, transparent); color: var(--flat); }

.rating-more { text-align: center; font-size: 11px; color: var(--accent); cursor: pointer; padding: 5px 0 2px; }
.rating-more:hover { text-decoration: underline; }
.rating-foot { font-size: 10px; color: var(--text-muted); border-top: 1px solid var(--border); padding-top: 6px; grid-area: foot; align-self: stretch; }
.rating-empty, .rating-loading { font-size: 11.5px; color: var(--text-muted); padding: 10px 2px; grid-column: 1 / -1; }

/* 手机端: 三栏折叠成单栏顺序堆叠; 明细表按窄列重新分配 */
@media (max-width: 768px) {
  .rating-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "left" "mid" "orgs" "foot";
    gap: 9px;
  }
  /* 手机端不设上限: 单栏堆叠内容 ~590px, 页面本来就要滚, 再套一层面板内滚动
     会变成"滚到底还要在面板里再滚一次"。让整块跟着页面滚更自然。 */
  .rating-panel { max-height: none; }
  .rating-kpis { gap: 4px 10px; font-size: 11px; }
  .rating-kpi b { font-size: 12px; }
  .rating-dist-row { grid-template-columns: 34px minmax(0, 1fr) 50px; }
  .rating-orgs-head, .rating-org-row {
    grid-template-columns: minmax(0, 1fr) 58px 48px 76px 24px;
    gap: 4px; font-size: 11px;
  }
  .rating-win { padding: 2px 7px; }
}

/* ===== 机构评级面板 · 横向分栏重排 (2026-10-02 v2) =====
   上一版(v1)用"把所有块压到 820px 宽以对齐右边界"的方式修"不齐", 1920 视口实测:
     ① 内容右边界 1336 vs 面板右边界 1589 → 右侧凭空多出 253px 空白;
     ② 评级分布条轨道 706px, 单档"增持"填充 100% → 一根横贯全屏的红条;
     ③ 月度柱被钉成 40px 宽 + 左对齐, 而近一年只有 3 个月有研报 → 3 根柱占 120px,
        右侧 700px 全空;
     ④ 内容 614px 塞进 max-height 248px → 正文被拦腰截断在"按各机构最新一篇计…"。
   即"对齐"达成了, 整块却像没渲染完 —— 这才是真正的别扭来源。
   v2 结论: 小数据量内容不该硬塞进"全宽纵向卡片"。改为三栏横向布局
   (概览 | 分布+月度柱 | 机构明细), 宽度被真正用掉, 不再需要任何 max-width 兜底。 */
.ro-date { white-space: nowrap; }

/* ===== 盘口/核心指标面板重叠修复 (2026-10-02) =====
   .order-book-panel 自带 width:clamp(280px,26vw,380px), 而 .stock-panel .bottom-panels
   的 grid 首轨是 clamp(260px,24vw,360px) —— 两个 clamp 口径不同, 1920 视口下
   前者算得 380px、后者算得 360px: 面板比轨道宽 20px, 扣掉 12px gap 后
   **实际压住"核心指标"面板 8px**(实测盘口 504~884, 核心指标起点 876)。
   放进 grid 后应交给轨道决定宽度, 所以 width 归零、只保留最小宽度保护。 */
.stock-panel .bottom-panels > .order-book-panel {
  width: auto;
  min-width: 0;
}

/* ==========================================================================
   个股页「零滚动」布局断点 (2026-10-03 v4) —— 权威声明块
   --------------------------------------------------------------------------
   ⚠️ 这份断点必须放在**文件最末**: 旧版在文件中部(第 ~2055 行)有一条
      `@media (max-width:1100px){ .stock-panel-layout{两栏} .f10-sidebar{隐藏} }`,
      它会盖掉写在它前面的任何同条件断点。踩过一次:
      断点写在前面 → 1280 视口下 F10 侧栏仍然显示、"搜索代码"输入框被挤成竖排单字。
   --------------------------------------------------------------------------
   规则:
     >1280px : 三栏(列表 15 : 详情 66.5 : F10 18.5), F10 走右侧独立栏
     ≤1280px : 两栏(列表 15 : 详情 85), 收掉 F10 侧栏 → F10 内容进详情区第 4 个 tab
     ≤1100px : 单栏, 连列表栏一起收掉(详情区过窄时两列网格会挤到不可读)
   依据: 1280 宽下三栏只剩约 748px 给详情区, 而核心指标 4 列需 ≈620px、
         评级面板三栏需 ≈790px —— 不收 F10 就必然压窄文字。
   ========================================================================== */
@media (max-width: 1280px) {
  .stock-panel-layout { grid-template-columns: minmax(var(--min-list), var(--fr-list)) minmax(0, 85fr); }
  .f10-sidebar { display: none; }
}
@media (max-width: 1100px) {
  .stock-panel-layout { grid-template-columns: minmax(0, 1fr); }
  .stock-browser { display: none; }
}

/* ==========================================================================
   全球指数详情弹层 (2026-10-04) —— K线(日/周/月) + 均线 + 成交量
   --------------------------------------------------------------------------
   放在文件最末, 原因同上面「零滚动布局权威声明块」: 本块的 .gidx-box 需要盖掉
   先声明的 .modal-box 的 width/max-height/padding, 同条件的移动端 @media 也必须在后。
   高度分配: 弹层定高 → 图表区 flex:1;min-height:0 → 主图 3 : 量图 1。
   ⚠️ 图表容器必须是 position:relative + overflow:hidden **且有确定高度**,
      否则 lightweight-charts 按 0 高建 canvas → 弹层里什么都没有(且不报错)。
   ========================================================================== */
.gi-card.is-clickable { cursor: pointer; }
.gi-card.is-clickable:active { transform: translateY(1px); }
.gi-card.is-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.gi-right { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.gi-go { font-size: 10.5px; color: var(--text-muted); opacity: 0.7; white-space: nowrap; }
.gi-card.is-clickable:hover .gi-go { color: var(--accent); opacity: 1; }

.gidx-box {
  width: min(920px, 94vw);
  height: min(700px, 88vh);
  max-height: 88vh;
  padding: 18px 20px 16px;
  gap: 8px;
  overflow: hidden;
}
.gidx-quote { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.gidx-quote .gq-price { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.gidx-quote .gq-chg { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.gidx-quote .gq-sub { font-size: 11.5px; color: var(--text-muted); }
.gidx-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  padding: 7px 0 8px; border-top: 1px solid var(--border);
}
.gidx-periods { display: flex; gap: 6px; }
.gidx-p {
  padding: 4px 13px; font-size: 12px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--bg-card); border: 1px solid var(--border); color: var(--text-secondary);
}
.gidx-p:hover { color: var(--text-primary); border-color: var(--border-light); }
.gidx-p.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.gidx-status { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.gidx-chart-wrap {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.gidx-main { position: relative; flex: 3 1 0; min-height: 0; overflow: hidden; border-radius: var(--r-sm); }
.gidx-vol { position: relative; flex: 1 1 0; min-height: 0; overflow: hidden; border-radius: var(--r-sm); background: var(--bg-dark); }
#gidxKline, #gidxVol { position: absolute; inset: 0; }
.gidx-main > .chart-legend, .gidx-vol > .chart-legend {
  position: absolute; left: 6px; top: 4px; z-index: 50;
  display: flex; flex-wrap: wrap; gap: 4px 6px; align-items: center;
  font-size: 11px; line-height: 1.2; font-variant-numeric: tabular-nums;
  pointer-events: none; user-select: none; background: transparent;
}
.gidx-empty {
  position: absolute; inset: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 20px; text-align: center;
  background: color-mix(in srgb, var(--bg-dark) 94%, transparent); border-radius: var(--r-sm);
}
.gidx-empty .ge-msg { font-size: 14px; color: var(--text-secondary); }
.gidx-empty .ge-reason { font-size: 12px; color: var(--text-muted); }
.gidx-stats {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: 8px; padding-top: 10px; border-top: 1px solid var(--border);
}
.gidx-stats .gs-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.gidx-stats .gs-k { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
.gidx-stats .gs-v {
  font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

@media (max-width: 768px) {
  .gidx-box {
    width: 96vw; height: min(620px, 86vh); max-height: 86vh;
    padding: 14px 14px 12px; gap: 6px;
  }
  .gidx-quote .gq-price { font-size: 22px; }
  .gidx-quote .gq-chg { font-size: 13px; }
  .gidx-status { font-size: 11px; }
  /* 手机上 7 列并排会把每列压到 <40px(数值被截断) → 改 2 列换行 */
  .gidx-stats { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 10px; }
  .gidx-p { padding: 4px 11px; }
}

/* ==========================================================================
   自选股清单: 行业列口径标注 (2026-10-04)
   --------------------------------------------------------------------------
   【为什么】「行业」列可能混三种口径: 东财二级行业板块名(超市/铝) / 本地板块快照(同一套
   板块名) / 本地 F10 证监会行业(取细分末段, 如"黑色金属冶炼和压延加工业")。名称长度差
   3~4 倍, 长名会把整张 12 列表格撑变形。故: ① 列内限宽省略, 悬停看全文与来源;
   ② 面板头如实写出"有几项来自本地兜底"。
   规则: 降级必须可见(铁律 11) —— 同一列用不同口径而不标注, 等于让用户拿两把尺子量同一列。
   ========================================================================== */
/* 下限宽度: 窄视口(≤1440)下 auto 布局会把富余宽度优先给"内容最长"的列, 行业列理论上
   不会被压; 但一旦出现更宽的列(如新增列)或窗口更窄, 行业列就会被压到放不下 8 个汉字。
   给一个下限兜住这种退化。 */
.watchlist-table th:nth-child(11),
.watchlist-table td:nth-child(11) { min-width: 178px; }
.watchlist-table .sh-industry {
  display: inline-block;
  /* 220px = 18 个 11px 汉字 + padding/border: 实测最长的「计算机、通信和其他电子设备
     制造业」(18 字)刚好放得下, 更长的才走省略号 + title。限宽的目的是**防超长名撑破
     表格**, 不是尽量多截 —— 截得越多, 用户越以为"数据没显示完"(本 bug 的原始症状)。 */
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
.panel-sub.warn { color: var(--dp-warn, var(--gold)); }

/* ==========================================================================
   左侧「自选股」侧栏 展开 / 收起 (2026-10-04)
   --------------------------------------------------------------------------
   折叠态不是"把宽度压到 0" —— 那会让面板头(标题/按钮)一起消失, 用户**没法再展开**。
   做法: 折叠后侧栏固定为一个窄条(仅露出展开按钮), 内部列表与页脚用 display:none 收起。
   ⚠️ 折叠态必须保证按钮本身可见 —— 这是"能收回来"的唯一入口。
   ========================================================================== */
.sidebar-left {
  transition: width .18s ease;
  position: relative;
}

/* 头部改为三段式: 标题 | 计数 | 折叠按钮 */
.sidebar-left .panel-header { gap: 6px; }
.sidebar-left .panel-header h3 { flex: 1 1 auto; min-width: 0; }

.sidebar-toggle {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-card);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  line-height: 1;
  font-family: inherit;
}
.sidebar-toggle:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
  border-color: var(--text-muted);
}
.sidebar-toggle .st-chev {
  display: block;
  font-size: 15px;
  font-weight: 700;
  /* ‹ 与 › 字形左右不对称, 微调让它视觉居中 */
  transform: translateX(-1px) scaleX(1.15);
  transition: transform .18s ease;
}

/* ---- 折叠态 ---- */
.sidebar-left.is-collapsed {
  width: 40px;
  min-width: 40px;
}
/* 折叠态按钮放大: 40px 窄条里 22px 的按钮太不起眼, 用户找不到怎么再展开 */
.sidebar-left.is-collapsed .sidebar-toggle {
  width: 28px;
  height: 28px;
  border-radius: var(--r-sm);
}
.sidebar-left.is-collapsed .sidebar-toggle .st-chev { font-size: 17px; }
.sidebar-left.is-collapsed .watchlist,
.sidebar-left.is-collapsed .sidebar-footer { display: none; }
/* 折叠后只留按钮: 标题/计数收起 */
.sidebar-left.is-collapsed .panel-header {
  padding: 8px 0;
  justify-content: center;
}
.sidebar-left.is-collapsed .panel-header h3,
.sidebar-left.is-collapsed .panel-count { display: none; }
/* 展开箭头翻转: ‹ → › */
.sidebar-left.is-collapsed .st-chev { transform: translateX(1px) scaleX(-1.15); }

/* ==========================================================================
   全景页 A 股指数卡片 —— 与「全球指数」卡片统一显示口径 (2026-10-05)
   --------------------------------------------------------------------------
   原样式只有 名称/代码/现价/涨跌/成交额 五行; 现改为与 .gi-card 一致的
   名称+代码 / 现价 / 涨跌 / 开·高·低·昨收, 并支持点击看 K 线。
   指标浮层(.gi-detail/.gi-currency/.gi-go)直接复用全球卡片那套类, 不另建一套 ——
   两处口径必须同源, 否则改一边就两边不一致(kb 铁律 10 / 46)。
   ========================================================================== */
.index-card.is-clickable { cursor: pointer; }
.index-card.is-clickable:active { transform: translateY(1px); }
.index-card.is-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.index-card.is-clickable .gi-go { font-size: 10.5px; color: var(--text-muted); opacity: 0.7; white-space: nowrap; }
.index-card.is-clickable:hover .gi-go { color: var(--accent); opacity: 1; }
/* 卡片里两项元信息(代码 / K线›)并排, 与全球卡片的 (币种 / K线›) 同布局 */
.index-card .gi-right { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
/* 代码用 gi-currency 的徽标框承载, 与全球卡片的币种徽标视觉一致 */
.index-card .gi-currency {
  font-size: 10px; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 1px 6px; letter-spacing: 0.5px;
}
.index-card .gi-detail { margin-top: 8px; }

@media (max-width: 768px) {
  .index-card .gi-detail { gap: 6px; }
  .index-card .gi-go { display: none; }   /* 窄屏省空间: 整张卡片本就是可点的 */
}

/* ==========================================================================
   底部指数条：悬停明细浮层 + 点击弹层 (2026-10-05)
   --------------------------------------------------------------------------
   显示口径与「指数卡片 / 全球指数卡片」统一：开 / 高 / 低 / 昨收。
   底栏本身只有 30px 高（--ticker-h），四行直接铺开会把 12.5px 的字压到 8px 以下
   → 改为 **悬停浮出**：底栏视觉零变化，信息补全。
   浮层向上弹出（底栏贴窗口底边，向下必然被裁）。
   ========================================================================== */
.ticker-item { cursor: pointer; }

/* 浮层挂在内联的 .ticker-detail 上：默认 display:none 不占位、不参与 flex 等分 */
.ticker-item .ticker-detail { display: none; }

.ticker-item:hover .ticker-detail,
.ticker-item:focus-visible .ticker-detail {
  display: flex;
  flex-direction: column;
  gap: 5px;
  position: fixed;
  bottom: calc(var(--ticker-h) + 6px);   /* 贴在底栏上方, 不遮住指数本体 */
  z-index: 300;                          /* 高于底栏(85), 低于 modal(1000) */
  width: 214px;                          /* 定宽: 与 positionTickerTip() 的 TIP_W 必须一致 */
  box-sizing: border-box;
  padding: 9px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--r-sm);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
  pointer-events: none;                  /* 浮层不吃鼠标事件, 不会被自己的出现打断 hover */
  white-space: nowrap;
}
.ticker-item:hover .ticker-detail .td-chg,
.ticker-item:focus-visible .ticker-detail .td-chg {
  font-size: 12px;
  font-weight: 600;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
}
.ticker-item:hover .ticker-detail .td-rows,
.ticker-item:focus-visible .ticker-detail .td-rows {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);   /* 列宽固定, 不随数值长短跳动(否则两列错位) */
  gap: 4px 10px;
}
.ticker-detail .td-cell { font-size: 11.5px; color: var(--text-muted); display: flex; align-items: baseline; }
.ticker-detail .td-cell b { font-weight: 600; color: var(--text-primary); margin-left: 4px; white-space: nowrap; }
.ticker-detail .td-cell b.up { color: var(--up); }
.ticker-detail .td-cell b.down { color: var(--down); }
.ticker-detail .td-chg.up { color: var(--up); }
.ticker-detail .td-chg.down { color: var(--down); }
.ticker-detail .td-chg.flat { color: var(--flat); }

/* 浮层水平位置由 JS(positionTickerTip) 设置: fixed 定位下要跟随指数项, 且需避开左侧固定侧栏。
   这里只给一个"JS 尚未跑"时的合理兜底值(居中于视口), 避免首帧出现在左上角。 */
.ticker-item .ticker-detail { left: 50%; transform: translateX(-50%); }
.ticker-item:hover .ticker-detail,
.ticker-item:focus-visible .ticker-detail { transform: none; }   /* JS 接管后不要 transform 叠加 */

/* 移动端不启用悬停浮层（无 hover 概念，且顶栏指数条本就是横滑紧凑态）；
   点击仍可打开 K 线弹层，信息不丢。 */
@media (max-width: 768px) {
  .ticker-item:hover .ticker-detail,
  .ticker-item:focus-visible .ticker-detail { display: none; }
}

/* ==================== 播报面板 (2026-10-09) ====================
   布局口径(与全站一致): 面板本身不滚, 由「左: 选择区」「右: 播报稿」两栏各自滚。
   栏宽沿用「比例优先 + 内容最小宽兜底」的写法(fr 分配, 缩到放不下就不再缩),
   不写死 px —— 1085px/800px/374px 三种容器宽下都不该出现"大片空白"或"文字被压扁"。
   注: 变量就近定义在 #panel-broadcast 上而不是 :root, 避免与其它面板的全局 token 互相干扰。 */
#panel-broadcast {
  overflow: hidden;
  --bc-min-config: 300px;     /* 选择区最小宽: 实测"注册资本 125008.1601万元"整行不折行所需 */
  --bc-min-script: 320px;     /* 播报稿最小宽 */
  --bc-fr-config: 30fr;
  --bc-fr-script: 46fr;
}
.bc-layout {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(var(--bc-min-config), var(--bc-fr-config)) minmax(0, var(--bc-fr-script));
  gap: var(--gutter);
  align-items: stretch;
}
.bc-config, .bc-output {
  min-width: 0;
  min-height: 0;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.bc-config { overflow-y: auto; padding: 10px 12px; }
.bc-header-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bc-status { font-size: 11.5px; color: var(--text-muted); max-width: 60ch; overflow-wrap: anywhere; }

/* ---- 通用按钮/输入 ---- */
.bc-btn {
  background: var(--bg-hover); border: 1px solid var(--border); color: var(--text-secondary);
  border-radius: var(--r-sm); font-size: 12px; padding: 6px 10px; cursor: pointer; white-space: nowrap;
}
.bc-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--text-primary); }
.bc-btn:disabled { opacity: .5; cursor: default; }
.bc-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.bc-btn.primary:hover:not(:disabled) { background: var(--cyan); color: var(--on-accent); }
.bc-btn-xs { font-size: 11px; padding: 2px 7px; }

/* ---- 区块 ---- */
.bc-sec { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-card); }
.bc-sec + .bc-sec { margin-top: 10px; }
.bc-sec-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; cursor: pointer; }
.bc-sec-head input { margin: 0; width: 13px; height: 13px; accent-color: var(--accent); }
.bc-sec-title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.bc-sec-hint { font-size: 11px; color: var(--text-muted); margin-left: auto; text-align: right; }
.bc-sec-off-tag {
  font-size: 10.5px; color: var(--dp-warn, var(--gold));
  border: 1px solid currentColor; border-radius: var(--r-xs); padding: 0 4px; white-space: nowrap;
}
.bc-sec-body { padding: 0 10px 10px; }
/* 关掉的区块只变暗, 不隐藏 —— 配置要一直看得见, 用户才能"先挑好再打开" */
.bc-sec-off .bc-sec-body { opacity: .5; }
.bc-sec-off .bc-sec-title { color: var(--text-muted); }

.bc-sub { margin-top: 8px; }
.bc-sub-head { display: flex; align-items: baseline; gap: 8px; font-size: 12px; color: var(--text-secondary); margin-bottom: 6px; }
.bc-note { font-size: 11px; color: var(--text-muted); }
.bc-sub-row { display: flex; align-items: center; gap: 10px; }
.bc-sub-row .bc-sub-head { margin-bottom: 0; }
.bc-select {
  background: var(--bg-darkest); border: 1px solid var(--border); color: var(--text-primary);
  border-radius: var(--r-sm); font-size: 11.5px; padding: 4px 6px;
}

/* ---- 勾选项 ---- */
.bc-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.bc-chip {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  font-size: 11.5px; color: var(--text-secondary); line-height: 1.35;
  background: var(--bg-hover); border: 1px solid var(--border);
  border-radius: var(--r-xs); padding: 3px 7px; cursor: pointer;
}
.bc-chip.on { color: var(--text-primary); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.bc-chip input { margin: 0; width: 12px; height: 12px; accent-color: var(--accent); flex: none; }
.bc-chip span { overflow-wrap: anywhere; }
.bc-chip-code { color: var(--text-muted); font-weight: 400; margin-left: 4px; font-variant-numeric: tabular-nums; }

/* ---- 指数: 市场分组 ---- */
.bc-groups { display: flex; flex-direction: column; gap: 8px; }
.bc-group { border-left: 2px solid var(--border-light); padding-left: 8px; }
.bc-group-head { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-primary); cursor: pointer; margin-bottom: 5px; }
.bc-group-head input { margin: 0; width: 12px; height: 12px; accent-color: var(--accent); }

/* ---- 个股: 三级内容树 ---- */
.bc-tree { display: flex; flex-direction: column; gap: 4px; }
.bc-node { border-radius: var(--r-sm); }
.bc-node-head { display: flex; align-items: center; gap: 6px; padding: 3px 4px; border-radius: var(--r-xs); font-size: 12px; color: var(--text-secondary); cursor: pointer; }
.bc-node-head input { margin: 0; width: 12px; height: 12px; accent-color: var(--accent); flex: none; }
.bc-node-l1 > .bc-node-head { font-size: 12.5px; font-weight: 600; color: var(--text-primary); background: var(--bg-hover); }
.bc-node-l1.on > .bc-node-head { color: var(--accent); }
.bc-node-l3 > .bc-node-head { font-size: 11.5px; }
.bc-node-hint { font-size: 10.5px; font-weight: 400; color: var(--text-muted); }
/* 互斥模式组(如 公司简介 全文/摘要): 用一枚小标记告诉用户这是"二选一", 不是可叠加的复选 */
.bc-node-tag { flex: none; font-size: 10px; padding: 1px 5px; border-radius: 999px; font-weight: 500;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.bc-node-mode > .bc-node-head input { border-radius: 50%; }   /* 视觉上暗示单选(原生勾选框不变形) */
.bc-node-kids {
  display: flex; flex-direction: column; gap: 4px;
  margin: 4px 0 4px 16px; padding-left: 8px; border-left: 1px dashed var(--border-light);
}

/* ---- 个股检索 ---- */
.bc-search { display: flex; gap: 6px; }
.bc-search input[type="text"] {
  flex: 1; min-width: 0; background: var(--bg-darkest); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text-primary); font-size: 12px; padding: 6px 8px;
}
.bc-search input[type="text"]:focus { outline: none; border-color: var(--accent); }
.bc-search-hint { font-size: 11px; color: var(--text-muted); margin: 6px 0 4px; }
.bc-search-hint.err { color: var(--dp-warn, var(--gold)); }
.bc-search-res { max-height: 220px; overflow-y: auto; }
.bc-res-head { font-size: 11px; color: var(--text-muted); margin: 6px 0 4px; }
.bc-res-row { display: flex; align-items: center; gap: 6px; padding: 2px 0; }
.bc-res-stock { justify-content: space-between; }
.bc-res-toggle { background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 12px; width: 16px; padding: 0; flex: none; }
.bc-res-name { font-size: 12px; color: var(--text-primary); }
.bc-res-meta { font-size: 11px; color: var(--text-muted); margin-right: auto; }
.bc-res-members { padding: 4px 0 6px 22px; }
.bc-res-pct { font-size: 11.5px; font-variant-numeric: tabular-nums; }
.bc-res-pct.up { color: var(--up); }
.bc-res-pct.down { color: var(--down); }
.bc-res-pct.flat { color: var(--flat); }
.bc-picked { margin-top: 8px; }
.bc-picked-head { font-size: 11px; color: var(--text-muted); margin-bottom: 5px; }
.bc-hint-line { font-size: 11px; color: var(--text-muted); padding: 2px 0; overflow-wrap: anywhere; }
.bc-hint-err { color: var(--dp-warn, var(--gold)); }

/* ---- 播放器 ---- */
.bc-player { flex: 0 0 auto; padding: 10px 12px; border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; }
.bc-player-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bc-play-btn {
  background: var(--accent); border: none; border-radius: var(--r-sm); color: var(--on-accent);
  font-size: 13px; font-weight: 600; padding: 7px 14px; cursor: pointer;
}
.bc-play-btn:hover:not(:disabled) { background: var(--cyan); }
.bc-play-btn:disabled { opacity: .5; cursor: default; }
.bc-progress { font-size: 11.5px; color: var(--text-secondary); margin-left: auto; font-variant-numeric: tabular-nums; }
.bc-player-opts { font-size: 11.5px; color: var(--text-muted); }
.bc-opt { display: inline-flex; align-items: center; gap: 6px; }
.bc-opt input[type="range"] { width: 88px; accent-color: var(--accent); }
.bc-opt-val { color: var(--text-secondary); min-width: 34px; font-variant-numeric: tabular-nums; }
.bc-opt select {
  background: var(--bg-darkest); border: 1px solid var(--border); color: var(--text-primary);
  border-radius: var(--r-sm); font-size: 11.5px; padding: 4px 6px; max-width: 200px;
}
.bc-opt-inline { cursor: pointer; }
/* 播报引擎角标：让"用的是哪条嗓子"可见（手机没有本机语音引擎 → 自动转服务端语音）。
   降级必须可见，否则用户只会觉得"声音变了/变机械了"却不知道为什么。 */
.bc-eng { font-size: 11px; color: var(--text-muted); white-space: nowrap; }
.bc-eng.is-server { color: var(--dp-warn, var(--gold)); }
/* 在线直连（手机直接播, 不经过电脑）—— 与"服务端合成"用不同颜色区分, 一眼看出走的是哪条路 */
.bc-eng.is-online { color: #38bdf8; }
/* 语音来源下拉: 与音色下拉同宽即可, 手机端不要挤成两行 */
.bc-opt-src select { max-width: 170px; }
/* ⚠️ 播放器那行控件多(语速/音量/音色/来源/连续播报), 窄屏必须允许"整项换行", 但不许把
   两个字的标签(音量)拆成竖排 —— 加 nowrap, 让 flex 去决定换行位置。 */
.bc-opt { white-space: nowrap; }
@media (max-width: 768px) {
  .bc-player-opts { flex-wrap: wrap; row-gap: 8px; }
  .bc-opt-src { flex: 1 1 100%; }
  .bc-opt-src select { max-width: none; flex: 1; min-height: 36px; font-size: 13px; }
}

/* ---- 播报稿 ---- */
.bc-script { flex: 1 1 0; min-height: 0; overflow-y: auto; padding: 10px 12px; }
.bc-block { margin-bottom: 12px; }
.bc-block-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 6px; padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px; font-weight: 600; color: var(--text-primary);
}
.bc-block-count { font-size: 11px; font-weight: 400; color: var(--text-muted); }
.bc-seg { display: flex; gap: 8px; padding: 6px 8px; border: 1px solid transparent; border-radius: var(--r-sm); cursor: pointer; }
.bc-seg:hover { background: var(--bg-hover); }
.bc-seg.playing { background: color-mix(in srgb, var(--accent) 14%, transparent); border-color: var(--accent); }
.bc-seg.paused { border-color: var(--gold, var(--gold)); }
.bc-seg-empty { cursor: default; opacity: .6; }
.bc-seg-empty:hover { background: none; }
.bc-seg-idx { flex: none; min-width: 18px; padding-top: 1px; text-align: right; font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.bc-seg-main { min-width: 0; }
.bc-seg-title { font-size: 12px; font-weight: 600; color: var(--text-primary); }
.bc-seg-empty .bc-seg-title { font-weight: 400; color: var(--text-muted); }
.bc-seg-text { font-size: 12px; line-height: 1.6; color: var(--text-secondary); overflow-wrap: anywhere; }
.bc-notes { margin-bottom: 10px; padding: 8px 10px; background: var(--bg-card); border: 1px solid var(--border); border-left: 3px solid var(--dp-warn, var(--gold)); border-radius: var(--r-sm); }
.bc-note-line { font-size: 11.5px; line-height: 1.6; color: var(--text-secondary); }
.bc-empty { padding: 16px; text-align: center; font-size: 12px; color: var(--text-muted); }
.bc-empty-err { color: var(--dp-warn, var(--gold)); }

/* ---- 手机端: 单列堆叠 + 单一滚动容器, 选择区在上、播报稿在下(与移动端行情软件"先设置再看结果"一致) ----
   ⚠️ 血泪修复 (2026-10-09, kb铁律 63「面板自己就是滚动容器时, 不许把它改成 overflow:visible」)
   症状: 用户报"播报页连滑动都滑不了"。
   根因: <main class="main-content" id="panel-broadcast"> —— **面板本身就是那个滚动容器**
        (全站口径: 滚动由 .main-content 承担, 祖先 .main-layout 是 overflow:hidden)。
        桌面端 `#panel-broadcast{overflow:hidden}` 是"两栏各自滚"的配套写法, 没问题;
        但手机端上一版写成 `overflow:visible`(本意是"让整块跟着页面滚"), 等于**把唯一的滚动容器废掉**:
        内容高 1681px / 可视 691px → 溢出 990px 被 .main-layout 直接裁掉, 而 html/body 也是
        overflow:hidden → **全页零滚动**(实测 window.scrollTo(0,500) 与 panel.scrollTop=500 都恒为 0)。
        迷惑点: 元素的 scrollHeight > clientHeight 仍为真("看起来可滚"), 只是 scrollTop 完全不响应。
   做法: 手机端单列后, 由 #panel-broadcast 自己滚(恢复 .main-content 本意), 并取消所有"面板内嵌套滚动"。 */
@media (max-width: 768px) {
  #panel-broadcast {
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;   /* iOS 惯性滚动 */
  }
  .bc-layout {
    flex: none;                          /* 高度由内容决定, 不参与 flex 空间分配 */
    display: flex;                       /* 手机端改 flex 单列: 便于配合下面 display:contents 打平层级 */
    flex-direction: column;
    gap: 10px;
  }
  /* 取消嵌套滚动: 选择区 / 播报稿都跟随面板一起滚, 一次滑动到底(不再"滚到底还要在面板里再滚一次") */
  .bc-config { overflow: visible; padding: 10px; }
  /* ⚠️ display:contents —— 让 .bc-output 这个"盒子"消失, 使 .bc-player / .bc-script **直接成为
     .bc-layout 的 flex 子项**。
     原因: position:sticky 的粘性范围被**父容器边界**限制。手机端 .bc-output 高度只有内容高
     (~283px), 播放器最多只能在这 283px 内粘住 —— 一旦往下滚就被父框推走, 完全达不到
     "滚到稿子深处还能随手暂停"的目的(实测 rect.top 求解为 false)。
     打平后播放器的父级变成 .bc-layout(高 = 整个面板内容), 粘性范围覆盖全程。
     降级安全: 即使某浏览器不支持 display:contents, .bc-output 盒子仍存在 → 退化成"粘性范围较小",
     不会坏布局, 也不需要任何 JS 检测。 */
  .bc-output { display: contents; }
  .bc-script { flex: none; max-height: none; overflow: visible; padding: 10px; }
  /* 播放器粘在面板顶部: 滚到稿子深处也能随手暂停 / 上一段 / 下一段(手机端最常做的动作) */
  .bc-player {
    position: sticky; top: 0; z-index: 20;
    background: var(--bg-panel);
    box-shadow: 0 6px 12px -8px rgba(0, 0, 0, .65);
  }
  /* 检索结果保留固定高内滚(最多 30 条, 放任展开会把选择区推到几屏之外) */
  .bc-search-res { max-height: 260px; }
  .bc-progress { margin-left: 0; width: 100%; }
  /* 播放器选项行改 2 列 grid(原来是 flex-wrap 一行)。
     ⚠️ 必须给「音色」独占整行: <select> 的宽度由**最长 option 文本**决定, 而 max-width:100%
     的参照物(inline-flex 的 label)又由 select 自己撑开 → 循环参考, 限制不生效, 实测把面板
     右侧顶出 45px 的横向溢出(label.bc-opt / select#bcVoice right=427 vs 面板右边 382)。
     改成 grid item + select width:100% 后宽度由轨道决定, 不再依赖内容宽。 */
  .bc-player-opts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 10px;
    align-items: center;
  }
  .bc-opt { max-width: 100%; min-width: 0; }
  .bc-opt-voice { grid-column: 1 / -1; }
  .bc-opt select { width: 100%; max-width: none; flex: 1 1 0; min-width: 0; }
  .bc-opt input[type="range"] { flex: 1 1 auto; min-width: 0; width: auto; }
  .bc-sec-hint { display: none; }   /* 窄屏下提示会把标题挤掉, 只保留标题与不播报标记 */
  /* 触控友好: 手指命中区 ≥ 32px(桌面端沿用紧凑尺寸, 鼠标精度高不需要) */
  .bc-sec-head { min-height: 42px; }
  .bc-chip { min-height: 34px; padding: 7px 10px; }
  .bc-node-head { min-height: 32px; }
  .bc-node-kids { margin-left: 12px; padding-left: 6px; }   /* 三级缩进在 390px 宽下省 8px */
  .bc-res-toggle { width: 34px; min-height: 34px; font-size: 15px; }  /* 板块成员展开钮: 16px 宽手指点不中 */
  .bc-res-row { padding: 4px 0; }
  .bc-play-btn { flex: 1 1 auto; min-height: 40px; }        /* 主操作按钮占满一行更好点 */
  .bc-player-row .bc-btn { min-height: 36px; }
  /* ⚠️ 输入框字号必须 ≥ 16px: iOS Safari 在 <16px 的输入框获得焦点时会**自动缩放页面**,
     在播报页会表现为"点搜索框整页突然放大、之后的滚动位置全乱"。 */
  .bc-search input[type="text"] { min-height: 40px; font-size: 16px; }
}

/* ===== 全景图精选榜单 · 手机端保持"一行一只" (2026-10-22) =====
   手机端全局规则把 .rank-table 转成"每行一张卡片", 那对 9 列的行情表是对的,
   对这两块 5 列的榜却是灾难: 一行变成 5 层堆叠, 10 只股实测撑到 1022px, 一块榜就吃掉整屏 ——
   而榜单的价值恰恰是"一屏扫完看排名"。这里把表格形态还原, 只做减列与紧凑化。
   ⚠️ 必须 !important: 全局卡片规则用的是同优先级选择器(.rank-table td), 靠顺序与 !important 才能压住。 */
@media (max-width: 768px) {
  /* ⚠️ tbody 必须还原成 table-row-group, **不能**写成 display:table ——
     那会让 tbody 自成一个表格上下文, 表头(thead)与表体的列宽各自独立计算,
     结果是表头整体右移、和数字对不上(实测踩过, 视觉上像"错位一格") */
  .pn-rank-table { display: table !important; width: 100%; }
  .pn-rank-table thead { display: table-header-group !important; }
  .pn-rank-table tbody { display: table-row-group !important; }
  .pn-rank-table tr {
    display: table-row !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    border-radius: 0 !important;
    background: transparent !important;
    column-gap: 0 !important;
    row-gap: 0 !important;
  }
  .pn-rank-table th, .pn-rank-table td { display: table-cell !important; padding: 7px 6px !important; }
  /* 第 5 列(概念 / 涨停标签)在手机上让位给纵列空间: 它只是辅助信息, 名称与涨跌才是要点 */
  .pn-rank-table th:nth-child(5), .pn-rank-table td:nth-child(5) { display: none !important; }
  /* 旧「涨跌幅榜」的移动端规则给第 4 格加了「换手 」前缀与弱化字号 —— 那是 4 列表的语义,
     这里的第 4 列是热度, 必须把前缀与字号一并改回来, 否则会出现"换手 87.5万"这种错标签 */
  .pn-rank-table td:nth-child(4)::before { content: none !important; }
  .pn-rank-table td:nth-child(4) { font-size: 12px !important; opacity: 1 !important; padding-right: 6px !important; }
  .pn-rank-table .rank-code { display: none; }
  .pn-rank-table .pnr-num.heat { font-size: 11px; }
  /* 列宽: 名称列吃掉剩余宽度, 序号/涨跌/热度按内容收窄 ——
     不这么设的话 4 列会均分成 124px, 名称列被浪费、数字列又空一大块 */
  .pn-rank-table th:nth-child(1) { width: 26px; }
  .pn-rank-table th:nth-child(3), .pn-rank-table th:nth-child(4) { width: 1%; white-space: nowrap; }
  /* 名称必须左对齐: 全局移动端规则把第 2 格当"现价"右对齐了(旧榜语义), 名字右对齐读起来很别扭 */
  .pn-rank-table td:nth-child(2) { text-align: left !important; }
  /* 面板头部: 标题与 tab 同排, 标题允许压缩(否则 390px 宽会顶成两行) */
  .pn-rank-panel .panel-header { gap: 8px; }
  .pn-rank-panel .panel-header h3 { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ============================================================================
   资讯面板 (2026-10-22) —— 顶部工具条 + 分段 + 主区/侧栏两栏
   ⚠️ 三个约束(本项目反复踩过):
     ① 整块必须 height:100% + min-height:0, 否则内部滚动容器不生效、整页被撑长(铁律 63)
     ② 主区与侧栏各自 overflow-y:auto, 不许给父级 overflow:hidden 后让子级"看起来能滚"
     ③ 手机端侧栏沉到列表下方, 不并排(390px 屏两栏会把标题挤成两行)
   ========================================================================== */
.news-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: 100%;
  min-height: 0;
}
.np-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.np-tb-left { display: flex; align-items: center; gap: 8px; }
.np-title { font-size: 15px; font-weight: 600; margin: 0; }
.np-src-badge {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: var(--r-md);
  background: var(--accent-glow);
  color: var(--accent);
  white-space: nowrap;
}
.np-search { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 260px; max-width: 620px; }
.np-search input {
  flex: 1;
  min-width: 0;
  height: 30px;
  padding: 0 10px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-light);
  background: var(--bg-dark);
  color: var(--text-primary);
  font-size: 12.5px;
  font-family: inherit;
}
.np-search input:focus { outline: none; border-color: var(--accent); }
.np-search input::placeholder { color: var(--text-muted); }
.np-search button {
  height: 30px;
  padding: 0 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-light);
  background: var(--bg-panel);
  color: var(--text-primary);
  font-size: 12.5px;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.np-search button:hover { border-color: var(--accent); color: var(--accent); }
#npSearchClear { padding: 0 9px; }
.np-tb-right { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.np-updated { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
.np-refresh {
  width: 28px; height: 28px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-light);
  background: var(--bg-panel);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
}
.np-refresh:hover { color: var(--accent); border-color: var(--accent); }

.np-tabs {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.np-tab {
  padding: 6px 14px;
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--text-secondary);
  font-size: 12.5px;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.np-tab:hover { color: var(--text-primary); }
.np-tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.np-tab-search { color: var(--gold); }

.np-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 12px;
}
.np-main {
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-panel);
}
.np-side {
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ---- 快讯条目 ---- */
.np-item {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.np-item:last-child { border-bottom: none; }
.np-item:hover { background: rgba(255, 255, 255, 0.03); }
.np-item-top {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-muted);
  flex-wrap: wrap;
}
.np-time { font-variant-numeric: tabular-nums; }
.np-src {
  padding: 1px 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-light);
  color: var(--text-secondary);
  font-size: 10.5px;
}
/* 同花顺条目单独上色 —— 用户要求"以同花顺为主源", 面板上必须一眼能看出哪条是它 */
.np-src.is-ths { color: var(--accent); border-color: var(--accent); background: var(--accent-glow); }
.np-cat { color: var(--text-muted); }
.np-item-title {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.45;
  margin: 4px 0 3px;
  color: var(--text-primary);
}
.np-item-summary {
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.np-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.np-chips .rel-chip { font-size: 11px; padding: 1px 8px; }

/* ---- 侧栏卡片 ---- */
.np-card {
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-panel);
  overflow: hidden;
  flex-shrink: 0;
}
.np-card-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary);
}
.np-card-h em { font-style: normal; font-weight: 400; font-size: 10.5px; color: var(--text-muted); }
.np-card-b { padding: 4px 0; }
.np-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  font-size: 12px;
  cursor: pointer;
}
.np-row:hover { background: rgba(255, 255, 255, 0.03); }
.np-row-idx { width: 18px; color: var(--text-muted); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.np-row-idx.top { color: var(--gold); font-weight: 700; }
.np-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-row-code { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.np-row-val { font-variant-numeric: tabular-nums; flex-shrink: 0; }

/* ---- 表格(涨停池) ---- */
.np-tablewrap { overflow-x: auto; }
.np-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.np-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-dark);
  color: var(--text-muted);
  font-weight: 500;
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.np-table tbody td { padding: 6px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.np-table tbody tr { cursor: pointer; }
.np-table tbody tr:hover { background: rgba(255, 255, 255, 0.03); }
.np-table .num { font-variant-numeric: tabular-nums; text-align: right; }
.np-reason {
  color: var(--text-secondary);
  font-size: 11.5px;
  line-height: 1.5;
  max-width: 320px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.np-tag {
  display: inline-block;
  padding: 0 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-light);
  font-size: 10.5px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.np-tag.hot { color: var(--up); border-color: color-mix(in srgb, var(--up) 50%, transparent); }

/* ---- 涨停梯队 ---- */
.np-ladder { display: flex; flex-wrap: wrap; gap: 8px; padding: 10px; }
.np-ladder-col {
  min-width: 132px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 6px 8px;
  background: var(--bg-dark);
}
.np-ladder-h { font-size: 11.5px; color: var(--gold); margin-bottom: 4px; }
.np-ladder-s { font-size: 11.5px; color: var(--text-secondary); line-height: 1.7; cursor: pointer; }
.np-ladder-s:hover { color: var(--accent); }

/* ---- 搜索/公告列表 ---- */
.np-sec { padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--bg-dark); font-size: 12px; color: var(--text-secondary); }
.np-empty { padding: 26px 14px; text-align: center; color: var(--text-muted); font-size: 12.5px; }
.np-empty.err { color: var(--gold); }
.np-more { padding: 10px; text-align: center; }
.np-more button {
  padding: 5px 16px; border-radius: var(--r-sm); border: 1px solid var(--border-light);
  background: var(--bg-panel); color: var(--text-secondary); font-size: 12px; font-family: inherit; cursor: pointer;
}
.np-more button:hover { color: var(--accent); border-color: var(--accent); }

@media (max-width: 768px) {
  .news-panel { height: auto; }
  .np-body { grid-template-columns: minmax(0, 1fr); }
  .np-side { overflow-y: visible; }
  .np-main { overflow-y: visible; max-height: none; }
  /* 单列时不要用 grid：grid 的行高会被容器高度约束，内容一高就**溢出到下面的侧栏上**
     （日历展开时最明显：最后两行日期被「同花顺人气榜」盖住）。改成 block，行高就由内容决定。 */
  .np-body { display: block; }
  .np-side { margin-top: 12px; }
  .np-search { min-width: 0; max-width: none; flex-basis: 100%; order: 3; }
  .np-tb-right { margin-left: auto; }
  .np-toolbar { gap: 8px; }
  .np-item-title { font-size: 13px; }
}

/* ---- 资讯面板：事件簇（同一件事的多源报道） ---- */
.np-evbadge {
  padding: 1px 7px;
  border-radius: var(--r-sm);
  border: 1px solid var(--accent);
  color: var(--accent);
  background: var(--accent-glow);
  font-size: 10.5px;
  cursor: pointer;
  white-space: nowrap;
}
.np-evbadge:hover { filter: brightness(1.15); }
.np-evlist {
  margin-top: 6px;
  padding: 4px 0 2px 10px;
  border-left: 2px solid var(--border-light);
}
.np-ev-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 3px 0;
  font-size: 11.5px;
  color: var(--text-secondary);
  cursor: pointer;
}
.np-ev-row:hover .np-ev-t { color: var(--accent); }
.np-ev-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-table .up, .np-row-val.up { color: var(--up); }
.np-table .down, .np-row-val.down { color: var(--down); }
/* 手机端底部栏: 自选1 行情2 个股3 交易4 AI5 资讯6 全球7 (7 = 第二行) */
.nav-tab[data-morder="6"] { order: 6; }
.nav-tab[data-morder="7"] { order: 7; }

/* ---- 热度榜: 天数切换 ---- */
.np-hotrank-head { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:8px 12px; border-bottom:1px solid var(--border); background:var(--bg-dark); }
.np-days { display:flex; gap:4px; }
.np-days-btn { padding:2px 9px; border-radius: var(--r-md); border:1px solid var(--border-light); background:var(--bg-panel); color:var(--text-secondary); font-size:11.5px; font-family:inherit; cursor:pointer; }
.np-days-btn:hover { color:var(--accent); border-color:var(--accent); }
.np-days-btn.active { color:var(--accent); border-color:var(--accent); background:var(--accent-glow); }
.np-hotrank-note { font-size:11px; color:var(--text-muted); }
.np-table .np-rank.top { color:var(--gold); font-weight:700; }

/* ---- 热门事件榜（对齐"热榜"样式：序号 + 标题 + 说明 + 热/新标签） ---- */
.np-hotrank-block { background: var(--bg-panel); border-bottom: 1px solid var(--border); }
.np-hot-row { display: flex; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--border); cursor: pointer; align-items: flex-start; }
.np-hot-row:hover { background: rgba(255,255,255,.03); }
.np-hot-idx { width: 20px; text-align: center; font-size: 15px; font-weight: 700; color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.np-hot-idx.r1 { color: var(--up); }
.np-hot-idx.r2 { color: var(--gold); }
.np-hot-idx.r3 { color: var(--gold); }
.np-hot-main { min-width: 0; flex: 1; }
.np-hot-title { font-size: 13.5px; font-weight: 600; line-height: 1.45; color: var(--text-primary); }
.np-hot-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 3px; }
.np-hot-sub em { font-style: normal; color: var(--accent); }
.np-hot-tag { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs); font-size: 10px; font-weight: 600; vertical-align: 1px; }
.np-hot-tag.hot { background: color-mix(in srgb, var(--up) 16%, transparent); color: var(--up); border: 1px solid color-mix(in srgb, var(--up) 40%, transparent); }
.np-hot-tag.new { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--cyan); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }

/* ---- 热门事件：两套口径并列（同花顺话题榜 / 本店影响力榜，2026-10-28）----
   为什么是两个 tab 而不是一个合并榜：一边是论股社区黑话（"易中天"= 新易盛+中际旭创+天孚），
   一边是快讯语体（"中际旭创涨 8.3%，CPO 走强"）。硬合并会造出一个既不是同花顺、
   也不是我们的第三种东西；分开显示、各自标口径，用户才不会以为"算错了"。 */
.np-evsrc { display: flex; gap: 6px; padding: 8px 12px 6px; border-bottom: 1px solid var(--border); background: var(--bg-dark); flex-wrap: wrap; align-items: center; }
/* 标题不能被 tab 顶掉：换成 tab 后曾经整块没有"热门事件"四个字，用户不知道这块是什么 */
.np-evsrc-title { font-size: 12.5px; font-weight: 600; color: var(--text-primary); margin-right: 2px; }
.np-evsrc-btn { padding: 3px 11px; border-radius: var(--r-md); border: 1px solid var(--border-light); background: var(--bg-panel); color: var(--text-secondary); font-size: 12px; font-family: inherit; cursor: pointer; }
.np-evsrc-btn:hover { color: var(--accent); border-color: var(--accent); }
.np-evsrc-btn.active { color: var(--accent); border-color: var(--accent); background: var(--accent-glow); font-weight: 600; }
.np-ev-note { padding: 5px 12px; font-size: 11px; color: var(--text-muted); border-bottom: 1px solid var(--border); background: var(--bg-dark); }
/* 话题榜热度值：中性金色，**不用涨跌色** —— 它是同花顺站内行为分，被染成红绿会被误读成本店指标 */
.np-topic-heat { color: var(--gold); font-weight: 600; margin-right: 8px; }
.np-topic-stock { display: inline-block; margin-right: 8px; font-size: 11px; color: var(--text-secondary); cursor: pointer; }
.np-topic-stock:hover { color: var(--accent); }
.np-topic-stock b { font-weight: 600; }
.np-topic-stock b.up { color: var(--up); }
.np-topic-stock b.down { color: var(--down); }
.np-topic-desc { margin-top: 4px; font-size: 11.5px; line-height: 1.5; color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* 「官方」角标：同花顺自家运营/功能推广。**不过滤**（过滤后条数与 App 对不上），只标出来 */
.np-topic-promo { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs); font-size: 10px; font-weight: 600; vertical-align: 1px; color: var(--text-muted); border: 1px solid var(--border-light); background: var(--bg-dark); }

/* ---- 题材热度榜（concept_tag 聚合）---- */
/* 2026-10-28：整行改成可点（打开题材详情）；成分股与关联事件各自 stopPropagation，
   否则点股票会连带打开题材浮层。 */
.np-ch-row { cursor: pointer; }
.np-ch-row:hover { background: rgba(255,255,255,.04); }
.np-ch-row .np-hot-title { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.np-ch-lu { font-size: 10px; font-weight: 600; padding: 0 5px; border-radius: var(--r-xs); color: var(--up); background: color-mix(in srgb, var(--up) 16%, transparent); border: 1px solid color-mix(in srgb, var(--up) 40%, transparent); white-space: nowrap; }
.np-ch-avg { font-size: 11px; font-weight: 600; white-space: nowrap; }
.np-ch-avg.up { color: var(--up); }
.np-ch-avg.down { color: var(--down); }
.np-ch-heat { margin-left: auto; color: var(--gold); font-weight: 600; font-size: 12px; white-space: nowrap; }
/* "13 只热股" 不许被拆成 "13" + "只热股" 两行（手机 390px 实测会拆） */
.np-ch-cnt { font-size: 10.5px; color: var(--text-muted); white-space: nowrap; }
/* 关联事件：直接命中 = 蓝、仅提及成分股 = 灰。两种证据强度不同，不许用同一个颜色糊过去 */
.np-ch-ev { margin-top: 4px; font-size: 11.5px; color: var(--text-secondary); cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-ch-ev:hover { color: var(--accent); }
.np-ch-evk { display: inline-block; margin-right: 5px; padding: 0 4px; border-radius: var(--r-xs); font-size: 10px; font-weight: 600; vertical-align: 1px; }
.np-ch-evk.strong { color: var(--cyan); background: color-mix(in srgb, var(--accent) 16%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }
.np-ch-evk.weak { color: var(--text-muted); background: var(--bg-dark); border: 1px solid var(--border-light); }

/* ---- 题材详情浮层（2026-10-28）---- */
/* 板块行情：大字涨跌 + 两项副指标。这里用的是**同花顺板块自身的数**，
   不是我们按成分股平均算的 —— 两者口径不同，不能混着摆。 */
.np-cd-quote { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.np-cd-q-chg { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
.np-cd-q-chg.up { color: var(--up); }
.np-cd-q-chg.down { color: var(--down); }
.np-cd-q-sub { font-size: 12px; color: var(--text-secondary); }
.np-cd-q-sub b { font-weight: 600; }
.np-cd-q-sub b.up { color: var(--up); }
.np-cd-q-sub b.down { color: var(--down); }
.np-cd-stocks { display: flex; flex-wrap: wrap; gap: 7px; }
.np-cd-stock { display: inline-flex; align-items: baseline; gap: 5px; padding: 4px 9px; border-radius: var(--r-sm);
  background: var(--bg-dark); border: 1px solid var(--border-light); font-size: 12px; color: var(--text-primary); cursor: pointer; }
.np-cd-stock:hover { border-color: var(--accent); color: var(--accent); }
.np-cd-stock b { font-weight: 600; }
.np-cd-stock b.up { color: var(--up); }
.np-cd-stock b.down { color: var(--down); }
/* 人气标签（"5天5板"这类）用金色小字，与涨跌幅区分开 */
.np-cd-stock i { font-style: normal; font-size: 10px; color: var(--gold); }
.np-cd-ev { font-size: 12px; color: var(--text-secondary); cursor: pointer; line-height: 1.6; }
.np-cd-ev:hover { color: var(--accent); }

/* ---- 同花顺话题详情浮层（2026-10-28）----
   为什么要单独一个浮层而不是复用 newsModal：那个是"一条资讯"的版式（正文是纯文本），
   话题详情是"一个事件的档案"（官方概述 + 关联股 + 投票分布 + 报道时间线），
   塞进 newsModal 的 pre-line 正文里会全乱。 */
.np-topic-box { width: min(780px, 94vw); }
/* 两级浮层：话题档案（#npTopicModal，1000）在下、单篇原文（#newsModal）在上。
   同 z-index 时 DOM 靠后的赢，而 npTopicModal 正好排在 newsModal 后面 ——
   不显式抬高 newsModal，点开报道会被话题浮层盖住，看起来像"点了没反应"。 */
#newsModal { z-index: 1100; }
/* 覆盖 .modal-content 的 pre-line：这里是结构化 HTML，不是纯文本，否则每行都会多出空档 */
.np-topic-box .modal-content { white-space: normal; line-height: 1.7; }
.np-tp-loading { padding: 26px 0; text-align: center; color: var(--text-muted); font-size: 12.5px; }
.np-tp-sec { padding: 12px 0; border-bottom: 1px solid var(--border); }
.np-tp-sec:last-of-type { border-bottom: none; }
.np-tp-h { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; font-weight: 700; color: var(--text-primary); margin-bottom: 8px; }
.np-tp-h em { font-style: normal; font-weight: 400; font-size: 11px; color: var(--text-muted); }
.np-tp-lead { font-size: 13.5px; line-height: 1.75; color: var(--text-primary); }
.np-tp-note { margin-top: 6px; font-size: 10.5px; color: var(--text-muted); }
.np-tp-stocks { display: flex; flex-wrap: wrap; gap: 8px; }
.np-tp-stock { padding: 4px 10px; border-radius: var(--r-sm); background: var(--bg-dark); border: 1px solid var(--border-light); font-size: 12px; color: var(--text-primary); cursor: pointer; }
.np-tp-stock:hover { border-color: var(--accent); color: var(--accent); }
.np-tp-stock b { font-weight: 600; }
.np-tp-stock b.up { color: var(--up); }
.np-tp-stock b.down { color: var(--down); }
.np-tp-vq { font-size: 12.5px; color: var(--text-primary); margin-bottom: 8px; }
/* 投票条：条形是背景层，文字浮在上面（文字必须 relative，否则被条形盖住） */
.np-tp-vopt { position: relative; display: flex; align-items: center; gap: 10px; padding: 5px 10px; margin-bottom: 5px; border-radius: var(--r-sm); background: var(--bg-dark); overflow: hidden; }
.np-tp-vbar { position: absolute; left: 0; top: 0; bottom: 0; background: color-mix(in srgb, var(--accent) 16%, transparent); border-radius: var(--r-sm); }
.np-tp-vtxt { position: relative; flex: 1; font-size: 12px; color: var(--text-primary); }
.np-tp-vnum { position: relative; font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.np-tp-tl { display: flex; flex-direction: column; }
.np-tp-item { display: flex; gap: 10px; padding: 7px 0; border-top: 1px dashed var(--border); }
.np-tp-item:first-child { border-top: none; }
.np-tp-time { flex-shrink: 0; width: 76px; font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; padding-top: 2px; }
.np-tp-main { min-width: 0; flex: 1; }
.np-tp-t { font-size: 13px; line-height: 1.5; color: var(--text-primary); cursor: pointer; }
.np-tp-t:hover { color: var(--accent); text-decoration: underline; }
.np-tp-m { margin-top: 2px; font-size: 11px; color: var(--text-muted); }
.np-tp-flag { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs); font-size: 10px; color: var(--cyan); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.np-tp-foot { padding-top: 10px; font-size: 10.5px; line-height: 1.6; color: var(--text-muted); }
/* 深度专题的原文出口（本店未接入该内容类型时的唯一去处） */
.np-tp-out { color: var(--accent); text-decoration: none; border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }
.np-tp-out:hover { color: var(--text-primary); border-bottom-color: var(--border-light); }
@media (max-width: 768px) {
  .np-tp-time { width: 58px; font-size: 10.5px; }
  .np-topic-box { width: 96vw; padding: 16px 16px; }
}
@media (max-width: 768px) {
  .np-evsrc { padding: 6px 8px 5px; }
  .np-topic-desc { -webkit-line-clamp: 1; }
}

/* ============================================================
   AI 训练与决策面板 (2026-10-26)
   设计约束:
     · 只用现有设计 token(--bg-panel/--border/--accent/--up/--down),
       不引入第二套配色, 否则切主题时这块会"看起来是另一个产品"。
     · 显隐只用 class(.ai-view.active), 不写内联 display ——
       内联恒胜 class, 会出现"打开后关不掉"的老坑。
     · 手机端(<=768px)全部单列, 管线改 3 列网格, 不做横向滚动
       (横向滚动在触屏上和页面纵向滚动抢手势)。
   ============================================================ */
.ai-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px 24px;
  overflow-y: auto;
}
.ai-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ai-head-left h2 { margin: 0; font-size: 17px; color: var(--text-primary); }
.ai-sub { display: block; margin-top: 4px; font-size: 11.5px; color: var(--text-muted); }
.ai-head-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.ai-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 999px;
  font-size: 11px; border: 1px solid var(--border);
  background: var(--bg-panel); color: var(--text-secondary);
}
.ai-badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); }
.ai-badge.ok { color: var(--down); border-color: color-mix(in srgb, var(--down) 35%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }
.ai-badge.ok::before { background: var(--down); }
.ai-badge.warn { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 35%, transparent); background: color-mix(in srgb, var(--gold) 8%, transparent); }
.ai-badge.warn::before { background: var(--gold); }
.ai-badge.bad { color: var(--up); border-color: color-mix(in srgb, var(--up) 35%, transparent); background: color-mix(in srgb, var(--up) 8%, transparent); }
.ai-badge.bad::before { background: var(--up); }
.ai-badge.idle::before { background: var(--text-muted); }

.ai-btn {
  font-family: inherit; font-size: 12px; cursor: pointer;
  padding: 6px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--bg-panel); color: var(--text-secondary);
  transition: color .15s, background-color .15s, border-color .15s, opacity .15s, transform .15s;
}
.ai-btn:hover { color: var(--text-primary); border-color: var(--accent); }
.ai-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.ai-btn.primary:hover { filter: brightness(1.1); }
.ai-btn.danger { color: var(--up); border-color: color-mix(in srgb, var(--up) 40%, transparent); }
.ai-btn.danger:hover { background: color-mix(in srgb, var(--up) 10%, transparent); }
.ai-btn.ghost { background: transparent; }
.ai-btn:disabled { opacity: .45; cursor: not-allowed; }

.ai-tabs { display: flex; gap: 4px; padding: 3px; background: var(--bg-dark); border: 1px solid var(--border); border-radius: var(--r-sm); width: fit-content; max-width: 100%; overflow-x: auto; }
.ai-tab {
  font-family: inherit; font-size: 12.5px; cursor: pointer; white-space: nowrap;
  padding: 6px 14px; border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--text-secondary);
}
.ai-tab:hover { color: var(--text-primary); }
.ai-tab.active { background: var(--accent); color: var(--on-accent); font-weight: 600; }

.ai-view { display: none; }
.ai-view.active { display: flex; flex-direction: column; gap: 12px; }

.ai-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.ai-kpi {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 11px 13px;
}
.ai-kpi-label { font-size: 11px; color: var(--text-muted); }
.ai-kpi-val { margin-top: 5px; font-size: 20px; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.ai-kpi-val.up { color: var(--up); }
.ai-kpi-val.down { color: var(--down); }
.ai-kpi-sub { margin-top: 3px; font-size: 10.5px; color: var(--text-muted); }

.ai-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.ai-card-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding: 10px 13px; border-bottom: 1px solid var(--border); background: var(--bg-dark);
}
.ai-card-head h3 { margin: 0; font-size: 13px; color: var(--text-primary); }
.ai-card-hint { font-size: 10.5px; color: var(--text-muted); }
.ai-grid-2 { display: grid; grid-template-columns: 1.35fr 1fr; gap: 12px; align-items: start; }

/* ---- 管线 ---- */
.ai-pipe { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 6px; padding: 12px 13px 4px; }
.ai-pipe-node {
  position: relative; padding: 9px 6px; border-radius: var(--r-sm); text-align: center;
  border: 1px solid var(--border); background: var(--bg-dark);
}
.ai-pipe-node.ok { border-color: color-mix(in srgb, var(--down) 40%, transparent); background: color-mix(in srgb, var(--down) 7%, transparent); }
.ai-pipe-node.idle { border-style: dashed; }
.ai-pipe-node.running { border-color: color-mix(in srgb, var(--accent) 55%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ai-pipe-node.failed, .ai-pipe-node.stopped { border-color: color-mix(in srgb, var(--up) 45%, transparent); background: color-mix(in srgb, var(--up) 8%, transparent); }
.ai-pipe-dot { display: block; width: 7px; height: 7px; border-radius: 50%; margin: 0 auto 5px; background: var(--text-muted); }
.ai-pipe-node.ok .ai-pipe-dot { background: var(--down); }
.ai-pipe-node.running .ai-pipe-dot { background: var(--cyan); animation: aiPulse 1.4s infinite; }
.ai-pipe-node.failed .ai-pipe-dot, .ai-pipe-node.stopped .ai-pipe-dot { background: var(--up); }
@keyframes aiPulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
.ai-pipe-name { display: block; font-size: 12px; color: var(--text-primary); }
.ai-pipe-detail { display: block; margin-top: 3px; font-size: 10px; color: var(--text-muted); line-height: 1.3; word-break: break-all; }
.ai-pipe-note { padding: 6px 13px 11px; font-size: 10.5px; color: var(--text-muted); }

/* ---- 表格 ---- */
.ai-table-wrap { max-height: 320px; overflow: auto; }
.ai-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.ai-table th {
  position: sticky; top: 0; z-index: 1;
  padding: 7px 9px; text-align: left; font-weight: 500;
  color: var(--text-muted); background: var(--bg-dark); border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.ai-table td { padding: 7px 9px; border-bottom: 1px solid var(--border); color: var(--text-secondary); }
.ai-table td.ai-cell-ell { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ai-table tr:hover td { background: rgba(255,255,255,.03); }
.ai-empty { padding: 18px; text-align: center; color: var(--text-muted); font-size: 11.5px; }
.ai-tag { display: inline-block; padding: 1px 6px; border-radius: var(--r-xs); font-size: 10.5px; border: 1px solid var(--border); }
.ai-tag.buy { color: var(--up); border-color: color-mix(in srgb, var(--up) 40%, transparent); background: color-mix(in srgb, var(--up) 8%, transparent); }
.ai-tag.sell { color: var(--down); border-color: color-mix(in srgb, var(--down) 40%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }
.ai-tag.skip { color: var(--text-muted); }

/* ---- 自检清单 ---- */
.ai-checks { list-style: none; margin: 0; padding: 6px 13px 12px; }
.ai-checks li { display: flex; gap: 8px; padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: 11.5px; color: var(--text-secondary); }
.ai-checks li:last-child { border-bottom: none; }
.ai-checks .ic { flex: none; width: 15px; text-align: center; }
.ai-checks li.ok .ic { color: var(--down); }
.ai-checks li.warn .ic { color: var(--gold); }
.ai-checks li.bad .ic { color: var(--up); }

/* ---- 说明条 ---- */
.ai-note {
  padding: 10px 13px; border-radius: var(--r-sm); font-size: 11.5px; line-height: 1.6;
  color: var(--text-secondary); background: color-mix(in srgb, var(--accent) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}
.ai-note b { color: var(--text-primary); }

/* ---- 厂商卡片 ---- */
.ai-providers { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 12px; }
.ai-prov {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-md); padding: 12px 13px;
  display: flex; flex-direction: column; gap: 9px;
}
.ai-prov.verified { border-color: color-mix(in srgb, var(--down) 35%, transparent); }
.ai-prov-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ai-prov-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.ai-prov-vendor { margin-left: 6px; font-size: 10.5px; color: var(--text-muted); font-weight: 400; }
.ai-prov-tags { display: flex; gap: 4px; flex-wrap: wrap; }
.ai-prov-tags span { font-size: 9.5px; padding: 1px 5px; border-radius: var(--r-xs); background: var(--bg-dark); border: 1px solid var(--border); color: var(--text-muted); }
.ai-prov-note { font-size: 10.5px; color: var(--text-muted); }
.ai-field { display: flex; flex-direction: column; gap: 4px; }
.ai-field label { font-size: 10.5px; color: var(--text-muted); }
.ai-input, .ai-select {
  font-family: inherit; font-size: 12px;
  padding: 6px 9px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--bg-dark); color: var(--text-primary);
  width: 100%; box-sizing: border-box;
}
.ai-input:focus, .ai-select:focus { outline: none; border-color: var(--accent); }
.ai-prov-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.ai-prov-status { font-size: 10.5px; margin-left: auto; color: var(--text-muted); }
.ai-prov-status.ok { color: var(--down); }
.ai-prov-status.bad { color: var(--up); }

/* ---- 训练台 ---- */
.ai-grid-train { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 12px; align-items: start; }
.ai-form { padding: 12px 13px; display: flex; flex-direction: column; gap: 10px; }
.ai-form label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; color: var(--text-muted); }
.ai-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.ai-form-actions { display: flex; gap: 7px; margin-top: 2px; }
.ai-vram { font-size: 10.5px; color: var(--text-muted); padding: 6px 9px; border-radius: var(--r-sm); background: var(--bg-dark); border: 1px dashed var(--border); }
.ai-hint-warn { font-size: 10.5px; line-height: 1.5; color: var(--gold); }
.ai-progress { height: 7px; margin: 12px 13px 0; border-radius: 99px; background: var(--bg-dark); overflow: hidden; border: 1px solid var(--border); }
.ai-progress-bar { height: 100%; width: 0%; background: var(--accent); transition: width .4s; }
.ai-stage-row { display: flex; gap: 5px; padding: 9px 13px 0; flex-wrap: wrap; }
.ai-stage-chip { font-size: 10px; padding: 2px 7px; border-radius: 99px; border: 1px solid var(--border); color: var(--text-muted); }
.ai-stage-chip.done { color: var(--down); border-color: color-mix(in srgb, var(--down) 40%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }
.ai-stage-chip.now { color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 50%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ai-loss-wrap { position: relative; padding: 10px 13px 0; }
#aiLossChart, #aiEquityChart { width: 100%; height: auto; display: block; border-radius: var(--r-sm); background: var(--bg-dark); }
.ai-loss-empty { padding: 26px 0; text-align: center; font-size: 11px; color: var(--text-muted); }
.ai-loss-wrap .ai-loss-empty { position: absolute; inset: 10px 13px 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.ai-log {
  margin: 10px 13px 13px; padding: 8px 10px; height: 150px; overflow-y: auto;
  background: var(--bg-dark); border: 1px solid var(--border); border-radius: var(--r-sm);
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 10.5px; line-height: 1.65;
  color: var(--text-secondary);
}
.ai-log .warn { color: var(--gold); }
.ai-log .err { color: var(--up); }
.ai-log .ok { color: var(--down); }

/* ---- 回测 ---- */
.ai-bt-form { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; padding: 12px 13px; }
.ai-bt-form label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; color: var(--text-muted); }
.ai-bt-form .ai-input { width: 130px; }

/* ---- 算法框架 ---- */
.ai-algo { display: flex; flex-direction: column; gap: 10px; }
.ai-algo-group { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.ai-algo-head { display: flex; align-items: center; gap: 8px; padding: 10px 13px; cursor: pointer; background: var(--bg-dark); }
.ai-algo-head h3 { margin: 0; font-size: 12.5px; color: var(--text-primary); }
.ai-algo-head .cnt { margin-left: auto; font-size: 10.5px; color: var(--text-muted); }
.ai-algo-body { display: none; padding: 4px 13px 12px; }
.ai-algo-group.open .ai-algo-body { display: block; }
.ai-algo-item { padding: 9px 0; border-bottom: 1px dashed var(--border); }
.ai-algo-item:last-child { border-bottom: none; }
.ai-algo-name { font-size: 12px; color: var(--text-primary); font-weight: 600; }
.ai-algo-name .state { margin-left: 7px; font-size: 9.5px; font-weight: 500; padding: 1px 6px; border-radius: 99px; border: 1px solid var(--border); color: var(--text-muted); }
.ai-algo-name .state.on { color: var(--down); border-color: color-mix(in srgb, var(--down) 40%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }
.ai-algo-name .state.plan { color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 40%, transparent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.ai-algo-desc { margin-top: 4px; font-size: 11px; line-height: 1.6; color: var(--text-secondary); }
.ai-algo-meta { margin-top: 4px; font-size: 10.5px; color: var(--text-muted); }

/* ---- 手机端 ---- */
@media (max-width: 768px) {
  .ai-panel { padding: 10px 10px 18px; gap: 10px; }
  .ai-head-left h2 { font-size: 15px; }
  .ai-sub { display: none; }
  .ai-head-right { width: 100%; }
  .ai-badge { font-size: 10px; }
  .ai-tabs { width: 100%; }
  .ai-tab { flex: 1 0 auto; padding: 6px 10px; font-size: 12px; }
  .ai-pipe { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ai-grid-2, .ai-grid-train { grid-template-columns: minmax(0, 1fr); }
  .ai-providers { grid-template-columns: minmax(0, 1fr); }
  .ai-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ai-bt-form .ai-input { width: 100%; }
  .ai-bt-form label { flex: 1 1 45%; }
  .ai-table-wrap { max-height: 260px; }
}

/* 2026-10-26 修正: .ai-panel / .ai-view 都是 flex 列容器。
   列方向下子项默认 flex-shrink:1 —— 内容一多就把「页签栏」压成一条 6px 的缝
   (实测手机端整条 5 个页签只剩一条蓝边)。这里显式禁止压缩,
   让 .ai-panel 自己滚动, 而不是压缩子元素。 */
.ai-panel > * { flex: 0 0 auto; }
.ai-view.active > * { flex: 0 0 auto; }
.ai-tabs { flex: none; }

/* 手机端底部栏改为两行后, 页面滚动到底时的最后一段留白由 .main-layout 的
   padding-bottom 提供; 这里再给面板自身补一点, 避免最后一张卡片贴住底栏。 */
@media (max-width: 768px) {
  .ai-panel { padding-bottom: 28px; }
}

/* 模型清单版本戳 + 单模型说明 (2026-10-26)
   目的: 让人一眼看出"这份清单是哪天核对的", 以及当前选中的是哪一档能力。
   .ai-asof 用等宽小字, 不抢 label 的注意力; .ai-model-hint 允许换行。 */
.ai-asof {
  margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs);
  font-size: 9.5px; font-weight: 400; font-family: ui-monospace, Menlo, Consolas, monospace;
  color: var(--text-muted); background: var(--bg-dark); border: 1px solid var(--border);
}
.ai-model-hint {
  font-size: 10px; line-height: 1.45; color: var(--text-muted);
  min-height: 14px;
}
.ai-model-hint:empty { display: none; }
.ai-retire {
  font-size: 10px; line-height: 1.45; color: var(--gold);
  padding: 5px 8px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--gold) 7%, transparent); border: 1px solid color-mix(in srgb, var(--gold) 25%, transparent);
}
.ai-select optgroup { color: var(--text-muted); font-size: 11px; }
.ai-select optgroup option { color: var(--text-primary); }

/* 内存预算告警 (2026-10-26)
   本机 16GB 统一内存: 超预算不是"慢一点", 而是大量换页 + 风扇狂转 + 可能被系统杀掉,
   所以必须显式红/黄标出来, 不能只给一个中性的数字。 */
.ai-vram.over { color: var(--up); border-color: color-mix(in srgb, var(--up) 45%, transparent); background: color-mix(in srgb, var(--up) 7%, transparent); border-style: solid; }
.ai-vram.tight { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 40%, transparent); background: color-mix(in srgb, var(--gold) 6%, transparent); border-style: solid; }

/* 「本机舒适度」百分比条 (2026-10-26)
   本机 16GB 统一内存: 同一个模型"能不能跑"和"跑得舒不舒服"是两件事,
   所以除了红色拦截, 还要一条能一眼比较的百分比条。
   条宽固定 64px: 让它成为可横向对齐的视觉锚点, 不要随卡片宽度伸缩。 */
.ai-comfort {
  display: flex; align-items: center; gap: 6px;
  margin-top: 3px; font-size: 10px; color: var(--text-muted); line-height: 1.4;
}
.ai-comfort-bar {
  flex: none; width: 64px; height: 5px; border-radius: 99px;
  background: var(--bg-dark); border: 1px solid var(--border); overflow: hidden;
}
.ai-comfort-bar > i {
  display: block; height: 100%; border-radius: 99px; background: var(--down);
  transition: width .25s ease;
}
.ai-comfort-bar > i.warn { background: var(--gold); }
.ai-comfort-bar > i.bad { background: var(--up); }
.ai-comfort > b { font-size: 10.5px; font-variant-numeric: tabular-nums; }
.ai-comfort > b.ok { color: var(--down); }
.ai-comfort > b.warn { color: var(--gold); }
.ai-comfort > b.bad { color: var(--up); }
.ai-comfort-txt { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ai-vram-line { display: flex; flex-direction: column; gap: 3px; }
.ai-vram-gb { font-size: 10.5px; }

/* 磁盘预算 (2026-10-28)
   和内存预估同一位置、同一套配色: 两件事都是"开工前必须知道够不够",
   分开摆会让人只看到一个。over = 真拦, tight = 能训但合并导出会不够。 */
.ai-disk { font-size: 10.5px; color: var(--text-muted); padding: 6px 9px; border-radius: var(--r-sm); background: var(--bg-dark); border: 1px dashed var(--border); margin-top: 6px; }
.ai-disk-line { display: flex; flex-direction: column; gap: 3px; }
.ai-disk-gb { font-size: 10.5px; }
.ai-disk-tail { font-size: 10px; line-height: 1.45; opacity: .85; }
.ai-disk.over { color: var(--up); border-color: color-mix(in srgb, var(--up) 45%, transparent); background: color-mix(in srgb, var(--up) 7%, transparent); border-style: solid; }
.ai-disk.tight { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 40%, transparent); background: color-mix(in srgb, var(--gold) 6%, transparent); border-style: solid; }

/* 训练台里的舒适度条允许换行: 说明文字在天花板 320px 的表单里放不下一行,
   截断会把"余量 3.5GB"这类关键信息切掉, 反而不如折两行。 */
.ai-vram .ai-comfort { flex-wrap: wrap; }
.ai-vram .ai-comfort-txt { flex: 1 1 100%; white-space: normal; overflow: visible; }

/* 验证状态第三档 warn：目录通过但推理未验证 (2026-10-26)
   加这一档是因为"绿勾"被误读成"厂家后台能看到调用"——实际只拉了目录。
   黄色明确表示"半验证"，比默默显示绿勾诚实。 */
.ai-prov-status.warn { color: var(--gold); }

/* ---- 盘前/盘中/盘后 分析 ---- */
.np-tab-brief { color: var(--accent); }
.np-brief-card { border-bottom: 1px solid var(--border); }
.np-brief-h { display: flex; align-items: center; gap: 10px; padding: 10px 12px 6px; flex-wrap: wrap; }
.np-brief-t { font-size: 14px; font-weight: 700; color: var(--text-primary); }
.np-brief-meta { display: flex; gap: 10px; font-size: 11px; color: var(--text-muted); flex-wrap: wrap; }
.np-brief-model { color: var(--accent); }
.np-brief-btn { margin-left: auto; padding: 3px 12px; border-radius: var(--r-md); border: 1px solid var(--border-light); background: var(--bg-dark); color: var(--text-secondary); font-size: 11.5px; font-family: inherit; cursor: pointer; }
.np-brief-btn:hover:not([disabled]) { color: var(--accent); border-color: var(--accent); }
.np-brief-btn[disabled] { opacity: .5; cursor: default; }
.np-brief-hint { padding: 0 12px 10px; font-size: 11px; color: var(--text-muted); border-bottom: 1px dashed var(--border); }
.np-brief-md { padding: 8px 14px 18px; font-size: 13px; line-height: 1.75; color: var(--text-secondary); }
.np-md-h { font-weight: 700; color: var(--text-primary); margin: 14px 0 6px; }
.np-md-h2 { font-size: 14.5px; }
.np-md-h3 { font-size: 13.5px; color: var(--accent); }
.np-md-h1 { font-size: 15px; }
.np-md-p { margin: 6px 0; }
.np-md-ul { margin: 6px 0 6px 18px; padding: 0; }
.np-md-ul li { margin: 3px 0; }
.np-md-tablewrap { overflow-x: auto; margin: 8px 0; }
.np-md-table { border-collapse: collapse; font-size: 12px; min-width: 60%; }
.np-md-table th, .np-md-table td { border: 1px solid var(--border); padding: 4px 9px; text-align: left; }
.np-md-table th { background: var(--bg-dark); color: var(--text-muted); font-weight: 500; }
.np-md-pre { background: var(--bg-dark); padding: 8px 10px; border-radius: var(--r-sm); overflow-x: auto; font-size: 11.5px; }
.np-brief-md code { background: var(--bg-dark); padding: 0 4px; border-radius: var(--r-xs); font-size: 12px; }

.np-brief-backfill { color: var(--gold); border: 1px solid color-mix(in srgb, var(--gold) 40%, transparent); border-radius: var(--r-sm); padding: 0 6px; }

.np-brief-err { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: color-mix(in srgb, var(--up) 12%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--up) 35%, transparent); color: var(--up); font-size: 12px; }

/* ---- 盘前/盘中/盘后：日期回看（日历）2026-10-26 ---- */
/* 需求口径：有报告的日期"数字较亮 + 数字下方一个小点"，无报告的日期"数字偏灰暗"。
   所以亮/暗只能由**数字本身的颜色**表达，不能用"整格填充色"——
   否则一眼看上去像两套组件，而它只是一个日历。 */
.np-brief-bar { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.np-brief-date { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 14px;
  border: 1px solid var(--border-light); background: var(--bg-card); color: var(--text-primary);
  font-size: 12.5px; font-family: inherit; cursor: pointer; }
.np-brief-date:hover { border-color: var(--accent); color: var(--accent); }
.np-brief-date-ico { font-size: 12px; }
.np-brief-date-txt { font-weight: 600; letter-spacing: .3px; }
.np-brief-badge { font-size: 10px; padding: 1px 6px; border-radius: var(--r-sm); }
.np-brief-badge.today { color: var(--accent); background: var(--accent-glow); }
.np-brief-badge.past { color: var(--gold); background: color-mix(in srgb, var(--gold) 14%, transparent); }
.np-brief-caret { font-size: 10px; color: var(--text-muted); }
.np-brief-src { font-size: 11px; color: var(--text-muted); }
.np-brief-cov { padding: 6px 12px; font-size: 11px; color: var(--text-muted); border-bottom: 1px dashed var(--border); }
.np-brief-cov b { color: var(--text-secondary); font-weight: 600; }
.np-brief-ro { padding: 7px 12px; font-size: 11.5px; color: var(--gold);
  background: color-mix(in srgb, var(--gold) 8%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--gold) 25%, transparent); }
.np-brief-skip { padding: 7px 12px; font-size: 11.5px; color: var(--text-muted);
  background: var(--bg-dark); border-bottom: 1px solid var(--border); }

.np-cal { margin: 8px 12px 12px; padding: 10px 12px 8px; background: var(--bg-card);
  border: 1px solid var(--border-light); border-radius: var(--r-md); }
.np-cal-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.np-cal-nav { width: 22px; height: 22px; border-radius: var(--r-sm); border: 1px solid var(--border-light);
  background: var(--bg-dark); color: var(--text-secondary); cursor: pointer; font-family: inherit; font-size: 13px; line-height: 1; }
.np-cal-nav:hover:not([disabled]) { color: var(--accent); border-color: var(--accent); }
.np-cal-nav[disabled] { opacity: .35; cursor: default; }
.np-cal-title { font-size: 12.5px; font-weight: 600; color: var(--text-primary); flex: 1; }
.np-cal-loading { font-weight: 400; font-size: 11px; color: var(--text-muted); margin-left: 6px; }
.np-cal-x { margin-left: auto; border: 0; background: transparent; color: var(--text-muted);
  cursor: pointer; font-size: 12px; font-family: inherit; }
.np-cal-x:hover { color: var(--accent); }
.np-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.np-cal-week { margin-bottom: 4px; }
.np-cal-w { text-align: center; font-size: 10.5px; color: var(--text-muted); padding: 2px 0; }
.np-cal-blank { visibility: hidden; }
.np-cal-c { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  height: 34px; border-radius: var(--r-sm); border: 1px solid transparent; background: transparent;
  font-family: inherit; padding: 0; }
.np-cal-n { font-size: 13px; line-height: 1; font-variant-numeric: tabular-nums; }
/* 有报告：数字亮 + 下方小点 */
.np-cal-c.has { cursor: pointer; }
.np-cal-c.has .np-cal-n { color: var(--text-primary); font-weight: 700; }
.np-cal-c.has:hover { background: var(--bg-hover); border-color: var(--border-light); }
.np-cal-dot { width: 4px; height: 4px; border-radius: 50%; background: var(--accent); display: block; }
/* 无报告：数字灰暗，且不可点（灰色同时表达"没有"与"不可选"） */
.np-cal-c.none .np-cal-n { color: var(--text-muted); opacity: .45; }
.np-cal-c.none { cursor: default; }
.np-cal-c.is-today { border-color: color-mix(in srgb, var(--accent) 75%, transparent); }
.np-cal-c.is-sel { background: var(--accent-glow); border-color: var(--accent); }
.np-cal-c.is-sel .np-cal-n { color: #fff; }
.np-cal-foot { display: flex; align-items: center; gap: 12px; margin-top: 8px; padding-top: 7px;
  border-top: 1px dashed var(--border); font-size: 10.5px; color: var(--text-muted); flex-wrap: wrap; }
.np-cal-legend { display: inline-flex; align-items: center; gap: 4px; }
.np-cal-legend .np-cal-dot.dim { background: var(--text-muted); opacity: .45; }
.np-cal-sum { flex: 1; }
.np-cal-today { margin-left: 0; }
.np-cal-err { margin-top: 6px; font-size: 11px; color: var(--up); }
/* 生成被 max_tokens 截断的角标：正文是半截的，必须一眼看得出（红色 = 不可当作完整结论） */
.np-brief-trunc { color: var(--up); border: 1px solid color-mix(in srgb, var(--up) 50%, transparent); border-radius: var(--r-sm); padding: 0 6px; }
/* 缺口声明核对未通过：报告说"没有"、数据库里其实有。红框 = 这段话不可信，正文仍按原文存档 */
.np-brief-gapfail { color: var(--gold); border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent); border-radius: var(--r-sm); padding: 0 6px; cursor: help; }
.np-brief-gapbar {
  margin: 6px 0 10px; padding: 8px 10px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--gold); font-size: 12px; line-height: 1.6;
}
.np-brief-gapbar b { color: var(--gold); }

/* 板块 chip 的涨跌幅（2026-10-26 恢复）：
   · 有行情 → 红涨绿跌（.up/.down 与全站一致）
   · 无行情 → "—" 且更暗：既区别于平盘的 0.00%，也不会被读成"这板块今天没动" */
.f10-tag .tag-pct { margin-left: 1px; }
.tag-pct.na { color: var(--text-muted); opacity: .6; font-weight: 400; }

/* ===== AI 生成任务的接口选择（2026-10-26） =====
   凡是"由 AI 生成内容"的界面都要能选接口，且选择要记住。
   · 顶部按钮常驻：一眼看到"这份是谁写的"，不用点开才知道
   · 展开面板跨整行（flex-basis 由 .np-brief-bar 的 wrap 自然换行）
   · 降级（你选的接口失效）用橙色：绿色会让人以为一切正常 */
.np-ai-btn { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 14px;
  border: 1px solid var(--border-light); background: var(--bg-dark); color: var(--text-secondary);
  font-size: 11.5px; font-family: inherit; cursor: pointer; max-width: 100%; }
.np-ai-btn:hover, .np-ai-btn.open { border-color: var(--accent); color: var(--accent); }
.np-ai-btn.warn { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.np-ai-ico { font-size: 11px; opacity: .8; }
.np-ai-lbl { color: var(--text-muted); }
.np-ai-cur { color: var(--accent); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-ai-btn.warn .np-ai-cur { color: var(--gold); }
.np-ai-tag { color: var(--gold); border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent); border-radius: var(--r-sm); padding: 0 5px; font-size: 10px; white-space: nowrap; }
.np-ai-caret { font-size: 10px; color: var(--text-muted); }
.np-ai-panel { padding: 10px 12px; border-bottom: 1px solid var(--border);
  background: rgba(255,255,255,.02); font-size: 12px; color: var(--text-secondary); }
.np-ai-title { font-size: 12px; color: var(--text-primary); font-weight: 600; margin-bottom: 8px; }
.np-ai-sub { font-weight: 400; color: var(--text-muted); margin-left: 8px; font-size: 11px; }
.np-ai-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.np-ai-k { color: var(--text-muted); font-size: 11px; min-width: 28px; }
.np-ai-sel { padding: 4px 8px; border-radius: var(--r-sm); border: 1px solid var(--border-light); background: var(--bg-dark);
  color: var(--text-primary); font-size: 11.5px; font-family: inherit; max-width: 100%; }
.np-ai-sel:focus { outline: none; border-color: var(--accent); }
.np-ai-sel-m { min-width: 220px; }
.np-ai-auto { color: var(--text-muted); font-size: 11px; }
.np-ai-actions { border-top: 1px dashed var(--border); padding-top: 8px; }
.np-ai-now { color: var(--text-muted); font-size: 11.5px; }
.np-ai-now b { color: var(--accent); font-weight: 600; }
.np-ai-src { color: var(--text-muted); }
.np-ai-save { margin-left: auto; padding: 3px 14px; border-radius: var(--r-md); border: 1px solid var(--accent);
  background: var(--accent-glow); color: var(--accent); font-size: 11.5px; font-family: inherit; cursor: pointer; }
.np-ai-save[disabled] { opacity: .5; cursor: default; }
.np-ai-mini { padding: 3px 10px; border-radius: var(--r-md); border: 1px solid var(--border-light);
  background: transparent; color: var(--text-muted); font-size: 11px; font-family: inherit; cursor: pointer; }
.np-ai-mini:hover { color: var(--accent); border-color: var(--accent); }
.np-ai-mini[disabled] { opacity: .5; cursor: default; }
.np-ai-warnbox { margin-top: 6px; padding: 5px 8px; border-radius: var(--r-sm); background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-left: 2px solid color-mix(in srgb, var(--accent) 60%, transparent); color: var(--gold); font-size: 11.5px; line-height: 1.5; }
.np-ai-saved { margin-top: 6px; color: var(--down); font-size: 11.5px; }
.np-ai-desc { margin-top: 6px; color: var(--text-muted); font-size: 11px; line-height: 1.5; }
.np-ai-err { color: var(--up); }
.np-ai-empty { color: var(--text-muted); font-size: 11.5px; line-height: 1.6; }
.np-ai-empty b { color: var(--text-secondary); }
/* 报告卡片上的"非你设定的接口"：与"已截断""缺口未通过"同一类警示，必须一眼看到 */
.np-brief-routefb { color: var(--gold); border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent); border-radius: var(--r-sm); padding: 0 6px; cursor: help; }

/* ===== 个股 AI 研报 (2026-10-26) =====
   两个使用场景, 两种密度, 同一套颜色:
   ① 面板里的「工具栏 + 历史列表」—— 高度只有 200~300px, 一行一条, 不换行不折行;
   ② 浮层里的「正文阅读器」—— 9 章研报, 必须像正经研报: 章节层级清楚、表格能读、数字对齐。
   ⚠️ 正文样式全部落在 .sr-doc 作用域内, 不复用 .np-md-* 的默认字号 ——
      资讯面板的字号是"刷手机"密度, 研报是"坐下来读"密度, 混用会两头不像。 */
.rating-subtabs {
  display: flex; align-items: center; gap: 4px;
  padding: 0 12px; border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.rating-subtab {
  background: none; border: none; cursor: pointer;
  padding: 5px 10px 6px; font-size: 11.5px; color: var(--text-muted);
  border-bottom: 2px solid transparent; transition: color .15s, border-color .15s;
  display: inline-flex; align-items: center; gap: 5px;
}
.rating-subtab:hover { color: var(--text-primary); }
.rating-subtab.active { color: var(--accent); border-bottom-color: var(--accent); }
.rating-subtab-n {
  font-style: normal; font-size: 10px; min-width: 14px; padding: 0 4px;
  border-radius: var(--r-sm); background: var(--bg-dark); color: var(--text-muted);
}
.rating-subtab-n:empty { display: none; }
.rating-panel.collapsed .sr-body { display: none; }

.sr-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 8px 12px 10px; display: flex; flex-direction: column; gap: 7px;
}
.sr-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sr-mode-sel {
  padding: 3px 8px; border-radius: var(--r-sm); border: 1px solid var(--border-light);
  background: var(--bg-dark); color: var(--text-primary); font-size: 11.5px;
}
.sr-mode-sel:focus { outline: none; border-color: var(--accent); }
.sr-gen-btn {
  padding: 4px 13px; border-radius: var(--r-md); border: 1px solid var(--accent);
  background: transparent; color: var(--accent); font-size: 11.5px; cursor: pointer;
  white-space: nowrap;
}
.sr-gen-btn:hover:not([disabled]) { background: var(--accent-glow); }
.sr-gen-btn[disabled] { opacity: .55; cursor: default; }
.sr-gen-hint { margin-left: 6px; color: var(--text-muted); font-size: 10.5px; font-style: normal; }
.sr-hint { margin-left: auto; color: var(--text-muted); font-size: 11px; white-space: nowrap; }

.sr-dims-head {
  cursor: pointer; user-select: none; font-size: 11px; color: var(--text-muted);
  background: var(--bg-dark); border-radius: var(--r-sm); padding: 5px 9px;
}
.sr-dims-head b { color: var(--text-secondary); font-weight: 600; }
.sr-dims-caret { margin-left: 6px; }
.sr-dims { background: var(--bg-dark); border-radius: var(--r-sm); padding: 6px 9px 8px; }
.sr-dim { display: flex; gap: 8px; font-size: 11px; line-height: 1.6; padding: 2px 0; }
.sr-dim b { color: var(--text-secondary); font-weight: 600; flex: 0 0 auto; }
.sr-dim span { color: var(--text-muted); }
.sr-dims-note { margin-top: 4px; font-size: 10.5px; color: var(--text-muted); line-height: 1.6; }

.sr-list { display: flex; flex-direction: column; gap: 2px; }
.sr-item {
  display: flex; align-items: center; gap: 9px; padding: 5px 8px;
  border-radius: var(--r-sm); cursor: pointer; font-size: 11.5px; line-height: 1.4;
}
.sr-item:hover { background: var(--bg-hover); }
.sr-when { color: var(--text-muted); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.sr-model { color: var(--text-primary); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-mode { color: var(--text-muted); font-size: 10.5px; border: 1px solid var(--border-light); border-radius: var(--r-sm); padding: 0 6px; flex: 0 0 auto; }
.sr-chars { color: var(--text-muted); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.sr-trunc { color: var(--gold); border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent); border-radius: var(--r-sm); padding: 0 5px; font-size: 10px; flex: 0 0 auto; }
.sr-del { color: var(--text-muted); opacity: 0; transition: opacity .15s; flex: 0 0 auto; padding: 0 2px; }
.sr-item:hover .sr-del { opacity: .75; }
.sr-del:hover { color: var(--up); opacity: 1; }
.sr-empty, .sr-loading { color: var(--text-muted); font-size: 11.5px; line-height: 1.7; padding: 8px 4px; }
.sr-err { color: var(--up); font-size: 11.5px; line-height: 1.6; padding: 6px 9px; background: color-mix(in srgb, var(--up) 8%, transparent); border-radius: var(--r-sm); }

/* --- 正文阅读器 --- */
.sr-box {
  width: min(1080px, 94vw); height: 88vh; max-height: 88vh;
  padding: 14px 18px 0; gap: 8px;
}
.sr-modal-title { flex: 1; font-size: 13.5px; color: var(--text-primary); margin: 0 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-meta {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 11px; color: var(--text-muted); padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.sr-warn { color: var(--gold); }
.sr-reader {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 4px 6px 28px; margin-right: -6px;
}

/* 正文排版: 所有 AI 研报共用这一套, 不随模型变 */
.sr-doc { max-width: 82ch; margin: 0 auto; color: var(--text-secondary); font-size: 13px; line-height: 1.85; }
.sr-doc .np-md-h1 {
  font-size: 19px; line-height: 1.4; color: var(--text-primary); font-weight: 700;
  margin: 2px 0 4px; padding-bottom: 8px; border-bottom: 2px solid var(--accent);
  letter-spacing: .01em;
}
.sr-doc .np-md-h2 {
  font-size: 15px; color: var(--text-primary); font-weight: 700;
  margin: 22px 0 10px; padding-left: 9px; border-left: 3px solid var(--accent);
  line-height: 1.5;
}
.sr-doc .np-md-h3 { font-size: 13.5px; color: var(--text-primary); font-weight: 600; margin: 14px 0 6px; }
.sr-doc .np-md-h4 { font-size: 13px; color: var(--text-secondary); font-weight: 600; margin: 12px 0 5px; }
.sr-doc .np-md-p { margin: 7px 0; }
.sr-doc .np-md-ul { margin: 7px 0 7px 20px; padding: 0; }
.sr-doc .np-md-ul li { margin: 4px 0; }
.sr-doc .np-md-tablewrap { margin: 10px 0 14px; }
.sr-doc .np-md-table { width: 100%; border-collapse: collapse; font-size: 12px; line-height: 1.5; }
.sr-doc .np-md-table th, .sr-doc .np-md-table td {
  border: 1px solid var(--border); padding: 6px 10px; text-align: left; vertical-align: top;
}
.sr-doc .np-md-table th { background: var(--bg-dark); color: var(--text-secondary); font-weight: 600; white-space: nowrap; }
.sr-doc .np-md-table tbody tr:nth-child(even) { background: rgba(255,255,255,.015); }
.sr-doc .np-md-table td { font-variant-numeric: tabular-nums; }
/* 封面表(正文第一张表)单独做成卡片: 评级/目标价/现价/上行空间一眼看到 */
.sr-doc .np-md-tablewrap:first-of-type { margin-top: 12px; }
.sr-doc .np-md-tablewrap:first-of-type .np-md-table { font-size: 12.5px; }
.sr-doc .np-md-tablewrap:first-of-type .np-md-table th {
  width: 108px; background: var(--accent-glow); color: var(--accent); font-weight: 600;
}
.sr-doc .np-md-pre {
  background: var(--bg-dark); padding: 10px 12px; border-radius: var(--r-sm);
  overflow-x: auto; font-size: 11.5px; line-height: 1.6;
}
.sr-doc hr { border: none; border-top: 1px solid var(--border); margin: 18px 0; }

/* 引用块: npMd 新增 (2026-10-26)。资讯面板与研报正文共用同一份渲染, 样式按作用域区分 */
.np-md-quote {
  margin: 8px 0; padding: 7px 11px; border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--cyan) 6%, transparent); color: var(--text-secondary);
  font-size: 11.5px; line-height: 1.7; border-radius: 0 6px 6px 0;
}
.sr-doc .np-md-quote {
  margin: 12px 0; padding: 9px 14px; font-size: 12.5px; line-height: 1.75;
  background: color-mix(in srgb, var(--cyan) 5%, transparent);
}

/* 面板内的密度下调: 这块面板只有 ~150px 净高, 工具栏+维度+列表要在一屏里看得完
   (截图实测: 原间距下列表第一行正好被裁在底边, 用户以为"没历史") */
.sr-body { padding: 6px 12px 8px; gap: 5px; }
.sr-dims-head {
  font-size: 10.5px; padding: 3px 8px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.sr-item { padding: 4px 8px; }
.sr-list { gap: 1px; }

/* 维度说明折成工具栏按钮（面板净高 ~150px，一行维度说明会挤掉一条历史记录） */
.sr-dim-btn {
  padding: 3px 9px; border-radius: var(--r-md); border: 1px solid var(--border-light);
  background: transparent; color: var(--text-muted); font-size: 11px; cursor: pointer;
  white-space: nowrap;
}
.sr-dim-btn:hover, .sr-dim-btn.open { color: var(--accent); border-color: var(--accent); }

/* 生成进度：阶段文字放在工具栏右侧（"① 采底稿 → ② 组装提示词 → ③ 调模型 → ④ 落库"） */
.sr-gen-stage {
  max-width: 340px; overflow: hidden; text-overflow: ellipsis;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
@media (max-width: 1280px) { .sr-gen-stage { max-width: 200px; } }

/* ===== 自选「相关资讯」（2026-10-27） =====
   这一段解决的是"资讯跟自选股没关系"：每个条目必须带归属 chip，
   标题点名该股的（强）直接列出，只在长名单里被提到的（弱）折叠。
   · 统计行自证口径：近几天 / 命中几只 / 几家来源 —— 少一家源时要看得出来
   · 弱相关压暗一档，但仍可展开：用户可能就想看"我这只票今天在哪个榜里" */
.wl-news-head { display: flex; align-items: center; gap: 10px; padding: 8px 12px 4px;
  font-size: 11.5px; color: var(--text-muted); flex-wrap: wrap; }
.wl-news-head b { color: var(--accent); font-weight: 600; }
.wl-news-btn { margin-left: auto; padding: 2px 10px; border-radius: var(--r-md); border: 1px solid var(--border-light);
  background: var(--bg-dark); color: var(--text-secondary); font-size: 11px; font-family: inherit; cursor: pointer; }
.wl-news-btn:hover:not([disabled]) { color: var(--accent); border-color: var(--accent); }
.wl-news-btn[disabled] { opacity: .5; cursor: default; }
.wl-news-src { padding: 0 12px 8px; font-size: 10.5px; color: var(--text-muted); opacity: .85;
  border-bottom: 1px dashed var(--border); line-height: 1.5; }
.wl-news-more { display: block; width: calc(100% - 24px); margin: 8px 12px; padding: 6px 10px;
  border-radius: var(--r-sm); border: 1px dashed var(--border); background: transparent;
  color: var(--text-muted); font-size: 11.5px; font-family: inherit; cursor: pointer; text-align: left; }
.wl-news-more:hover { color: var(--accent); border-color: var(--accent); }
.wl-news-weak { border-top: 1px dashed var(--border); }
.wl-news-miss { padding: 8px 12px 12px; font-size: 11px; color: var(--text-muted);
  border-top: 1px dashed var(--border); line-height: 1.6; }
/* 归属 chip：这条资讯属于哪只自选股（"与我的票有关"的唯一凭证） */
.news-wl { color: var(--accent); background: var(--accent-glow); border-radius: var(--r-sm);
  padding: 0 6px; font-size: 10.5px; white-space: nowrap; }
/* 弱相关：只在正文长名单里被提到，压暗但仍可读 */
.news-item.weak { opacity: .72; }
.news-item.weak:hover { opacity: 1; }

/* ================= 资金面面板 (2026-10-27) =================
   布局意图: 一眼先看"市场温度"(涨跌幅分布), 再看两张市场级资金曲线, 最后落到个股榜单。
   颜色一律走 --up(红涨) / --down(绿跌), 与全站口径一致。 */
.funds-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.funds-title-wrap { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.funds-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--text-primary); }
.funds-sub { font-size: 11px; color: var(--text-muted); }
.funds-sub.is-warn { color: var(--gold); }
.funds-refresh {
  flex: none; padding: 4px 10px; border-radius: var(--r-sm); cursor: pointer;
  font-size: 11px; color: var(--text-secondary);
  background: var(--bg-panel); border: 1px solid var(--border);
}
.funds-refresh:hover { color: var(--text-primary); border-color: var(--border-light); }
.funds-refresh[disabled] { opacity: .55; cursor: default; }

.funds-block {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 10px 12px 12px;
  min-width: 0;
}
.funds-block-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 8px; flex-wrap: wrap;
}
.funds-block-head h3 {
  margin: 0; font-size: 12px; font-weight: 600; color: var(--text-primary);
}
.funds-block-sub { font-size: 10.5px; color: var(--text-muted); }
.funds-block-sub.is-warn { color: var(--gold); }

.funds-two-col {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gutter);
}

.funds-note { font-size: 10px; line-height: 1.55; color: var(--text-muted); margin-bottom: 8px; }
.funds-note.is-warn { color: var(--gold); }

/* ---- 涨跌幅分布 ---- */
.funds-dist {
  display: flex; align-items: stretch; gap: 3px;
  height: 132px; padding-top: 2px;
}
.fd-col {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.fd-count {
  font-size: 9.5px; color: var(--text-secondary);
  font-variant-numeric: tabular-nums; line-height: 1;
  white-space: nowrap;
}
.fd-bar-wrap { flex: 1; width: 100%; display: flex; align-items: flex-end; }
.fd-bar { width: 100%; min-height: 2px; border-radius: 2px 2px 0 0; }
.fd-bar.up { background: var(--up); }
.fd-bar.down { background: var(--down); }
.fd-bar.flat { background: var(--text-muted); }
.fd-label {
  font-size: 9px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%; text-align: center; line-height: 1.1;
}

/* ---- 资金曲线 KPI + 迷你柱 ---- */
.funds-kpi {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 0 0 8px;
}
.fk-main {
  font-size: 20px; font-weight: 600; color: var(--text-primary);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.fk-unit { font-size: 11px; color: var(--text-muted); margin-left: 2px; font-weight: 400; }
.fk-chg { font-size: 12px; font-variant-numeric: tabular-nums; }
.fk-chg.up { color: var(--up); }
.fk-chg.down { color: var(--down); }
.fk-chg.flat { color: var(--text-muted); }
.fk-sub { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ⚠️ 容器必须是 align-items:stretch（默认值），不能写 flex-end。
   写法与塌陷机理：.fb-col 的高度由内容决定 → .fb-bar 的 height:X% 相对"高度不确定的父级"失效
   → 柱子退到 min-height:1px → 20 根柱子全变成 1px 细线（北向/两融两块同时"空"）。
   底部对齐交给 .fb-col 自己的 align-items:flex-end 完成，容器只负责给满高度。 */
.funds-bars {
  display: flex; align-items: stretch; gap: 2px;
  height: 58px;
}
.fb-col { flex: 1 1 0; min-width: 0; display: flex; align-items: flex-end; }
.fb-bar { width: 100%; min-height: 1px; background: var(--border-light); border-radius: 1px 1px 0 0; }
.fb-bar.is-last { background: var(--text-secondary); }
.funds-axis {
  display: flex; justify-content: space-between;
  font-size: 9.5px; color: var(--text-muted); margin-top: 5px;
}

.funds-empty {
  padding: 18px 4px; text-align: center;
  font-size: 11px; color: var(--text-muted);
}

/* ---- 龙虎榜 ---- */
.funds-lhb-wrap {
  max-height: 46vh;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.funds-lhb-table {
  width: 100%; border-collapse: separate; border-spacing: 0;
  font-size: 11px;
}
.funds-lhb-table th {
  position: sticky; top: 0; z-index: 1;
  padding: 7px 8px; text-align: left; font-weight: 500;
  color: var(--text-muted); background: var(--bg-card);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.funds-lhb-table td {
  padding: 7px 8px; border-bottom: 1px solid var(--border);
  color: var(--text-secondary); vertical-align: middle;
}
.funds-lhb-table tbody tr:hover td { background: var(--bg-hover); }
.funds-lhb-table tbody tr:last-child td { border-bottom: none; }
.funds-lhb-table .fl-no { width: 34px; color: var(--text-muted); }
.funds-lhb-table .fl-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.funds-lhb-table .fl-reason {
  max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-muted);
}
.fl-up { color: var(--up); }
.fl-down { color: var(--down); }
.fl-flat { color: var(--text-muted); }
.fl-name { color: var(--text-primary); }
.fl-code { color: var(--text-muted); font-size: 10px; margin-left: 5px; }
.fl-sub { color: var(--text-muted); font-size: 10px; }

@media (max-width: 768px) {
  .funds-two-col { grid-template-columns: minmax(0, 1fr); }
  .funds-dist { height: 108px; gap: 2px; }
  .fd-label { font-size: 8px; }
  .fd-count { font-size: 8.5px; }
  /* 手机上优先保留"谁 / 涨跌 / 净买入 / 上榜原因", 买卖明细与 D1 让位 */
  .funds-lhb-table .fl-opt { display: none; }
  .funds-lhb-table .fl-reason { max-width: 150px; }
  .funds-lhb-wrap { max-height: 52vh; }
  .funds-kpi { gap: 8px; }
  .fk-main { font-size: 18px; }
}

/* ===== 人气榜「上榜原因」补齐条 (2026-10-27) =====
   面板宽度有限(TOP10 窄栏), 这一行必须能压缩: 说明文字省略号, 下拉最宽 150px。 */
.pn-reason-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 8px 5px; border-bottom: 1px solid var(--border);
  font-size: 11px; color: var(--text-muted);
}
.pn-reason-info { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pn-reason-sel {
  flex: 0 0 auto; max-width: 150px; padding: 2px 6px; border-radius: var(--r-sm);
  border: 1px solid var(--border-light); background: var(--bg-dark); color: var(--text-primary);
  font-size: 10.5px;
}
.pn-reason-btn {
  flex: 0 0 auto; padding: 2px 9px; border-radius: var(--r-md); cursor: pointer;
  border: 1px solid var(--accent); background: transparent; color: var(--accent); font-size: 10.5px;
}
.pn-reason-btn:hover:not([disabled]) { background: var(--accent-glow); }
.pn-reason-btn[disabled] { opacity: .55; cursor: default; }
/* 行内「AI」角标：一眼分清哪条原因是同花顺给的、哪条是补的 */
.pnr-ai {
  display: inline-block; margin-left: 4px; padding: 0 4px; border-radius: var(--r-sm);
  font-size: 9px; line-height: 14px; color: var(--accent);
  border: 1px solid var(--accent); vertical-align: 1px;
}

/* ---- 热门事件：分档徽标 + 上榜理由（2026-10-28）----
   分档不是装饰：它决定这条能在榜上留多久（S 4天 / A 2天 / B 半天 / C 3小时），
   颜色与「热」标签同族但更克制 —— 榜单里一眼要能分出"这是重磅还是盘面播报"。 */
.np-tier { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs);
  font-size: 10px; font-weight: 700; vertical-align: 1px; letter-spacing: .3px; white-space: nowrap; }
.np-tier.s { color: #121214; background: var(--up); border: 1px solid color-mix(in srgb, var(--up) 60%, transparent); }
.np-tier.a { color: var(--gold); background: color-mix(in srgb, var(--gold) 15%, transparent); border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent); }
.np-tier.b { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }
.np-tier.c { color: var(--text-muted); background: color-mix(in srgb, var(--text-muted) 12%, transparent); border: 1px solid var(--border-light); }
.np-ev-reason { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: var(--r-xs);
  font-size: 10px; color: var(--text-secondary); background: color-mix(in srgb, var(--text-muted) 12%, transparent); }

/* ===== 动效兜底（Hallmark Floor 7 / sloplint 27）=====
   系统开启「减弱动效」时，全站过渡与动画全部停掉。
   本项目的动效只用于状态反馈（hover / 数值变化），停掉不影响任何功能。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===== Apple 视觉细节（2026-10-30 第三版）=====
   这一层只做"观感收口"，不改任何尺寸与间距，避免动到布局。
   依据是 macOS / iOS 的几条固定做法，不是凭感觉调。 */

/* ① 标题靠"字号 + 负字距"立住，不靠加粗。苹果的标题字重很少超过 600。 */
.brand-text { letter-spacing: -0.022em; font-weight: 600; }
.panel-header h3, .hot-rank-title, .hot-stock-title, .np-title,
.modal-title, .np-tp-h, .np-evsrc-title,
.hot-rank-title, .np-card-h, .np-ch-name { letter-spacing: -0.012em; }

/* ② 控件文字统一 500：苹果的按钮/分段控件几乎不用 700，粗体会让界面"喊"。 */
.nav-tab, .bd-tab, .hr-tab, .hs-tab, .np-evsrc-btn,
.filter-btn, .btn-secondary, .back-btn, .pg-btn, .np-days-btn {
  font-weight: 500;
}
/* 图标线条略加粗，与 500 字重匹配（1.4 在细字旁边会显得发虚） */
button .ic, .filter-btn .ic, .nav-tab .ic { stroke-width: 1.6; }

/* ③ 键盘焦点环用系统蓝的柔和描边 —— 苹果只在键盘导航时画框，鼠标点击不出框。
   :focus-visible 正好就是这个语义。 */
:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent);
  outline-offset: 1px;
  border-radius: inherit;
}

/* ④ 滚动条轨道透明，滑块用白色半透明 —— macOS 的覆盖式滚动条就是"悬浮的细条"，
   给轨道上底色会变成 Windows 98 的样子。 */
::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.16);
  border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.28); }

/* ⑤ 数字统一等宽 + 负字距：价格、涨跌幅、成交量纵向对齐（看盘时扫列才快）。
   tabular-nums 已在 body 上开；这里补字距，让"1,234.56"这类不再松散。 */
.chg, .price, .pnr-num, .hs-chg, .bd-price, .ts-change, .idx-chg,
.stock-price, .stock-chg, .np-ch-avg, .np-ch-heat, .np-topic-heat {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ===== 间距体系与圆角分级（2026-10-30 第四版）=====

   用户问「列表这些是否全都改为圆角比较好」。判断是：**不全都改**，
   按「块 / 行 / 容器」三级分开处理。这也是苹果自己的规则，不是为了省事：

     · **连续列表**（自选股、排行、资讯、题材）每行都做真圆角，行与行之间就必须留缝，
       缝才能看出圆角 —— 而缝是纯浪费的垂直空间。看盘界面一屏要装十几行，代价付不起。
       → 行保持贯通，只让「hover 底色带圆角」；行宽、行高都不变。
     · **独立信息块**（指数卡、板块卡、弹层、按钮）本来就有边界 → 用圆角。
     · **容器**（面板、侧栏、主区）是布局骨架 → 保持直角。
       给骨架做圆角会出现「圆角套圆角」，层次反而糊。

   间距方面，全站的「面板间距 / 页面内边距」已经有单一真源 --gutter，
   这里只放宽一档（苹果的节奏是 8/12/16/20，原来 11.5 偏紧），
   卡片之间的 gap 同步从 12 提到 14 —— 让块与块之间真正「分开」，
   而不是靠边框硬切。 */

:root {
  /* 列表行 hover：极淡的白，能感知但不抢眼（苹果侧边栏的选中就是这个量级） */
  --row-hover: rgba(255, 255, 255, 0.045);
}

/* ── ① 主布局间距：放宽一档，仍是同一个变量驱动，不会出现两套口径 ── */
:root { --gutter: clamp(10px, 0.85vw, 15px); }

/* ── ② 块与块之间：卡片 12 → 14 ── */
.card-grid { gap: 14px; }
.index-cards { gap: 14px; }
.panel-stack { gap: 10px; }

/* ── ③ 列表行：只加圆角与 hover 底色，尺寸一律不动（避免撑破零滚动布局） ── */
.watchlist-item,
.news-item,
.np-hot-row,
.np-topic-row,
.np-ch-row {
  border-radius: 8px;
  transition: background-color .12s;
}
.watchlist-item:hover,
.news-item:hover,
.np-hot-row:hover,
.np-topic-row:hover,
.np-ch-row:hover {
  background: var(--row-hover);
}
/* 自选股当前选中的那只：底色也用圆角，否则和 hover 形状不一致 */
.watchlist-item.active,
.watchlist-item.selected {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border-radius: 8px;
}

/* ── ④ 独立块圆角补齐：弹层 18（苹果 sheet 的尺寸）、按钮/输入 10 ── */
.modal-box,
.np-topic-box,
#newsModal .modal-content { border-radius: 18px; }
input, select, textarea { border-radius: var(--r-sm); }

/* ── ⑤ 分组标题与内容之间留一口气：标题下边距 8 → 10 ── */
.np-card-h, .np-evsrc, .hot-rank-head { padding-bottom: 2px; }

/* ── ⑥ 列表行水平内缩：让圆角真正露出来 ──
   只给行加 margin 而不同时改 padding 的话，会直接吃掉 4px 内容宽（左栏本来就只有 188px）。
   这里的做法是「外缩多少、内边距就减多少」：
     .watchlist-item  原 padding 8/14 → margin 0 4px + padding 8/10  → 内容宽 160 = 原 160
     .np-hot-row      原 padding 9/12 → margin 0 4px + padding 9/8
     .news-item       原 padding 8/14 → margin 0 4px + padding 8/10
   内容一个像素都没少，只是行的可视边界往里收了 4px，圆角才看得见。
   垂直 margin 一律为 0 → 行高不变，不会累积出溢出。 */
.watchlist-item { margin: 0 4px; padding-left: 10px; padding-right: 10px; }
.news-item { margin: 0 4px; padding-left: 10px; padding-right: 10px; }
.np-hot-row { margin: 0 4px; padding-left: 8px; padding-right: 8px; }


/* ===== 走势分析历史日历（2026-10-31 第二版）=====
   用户原话：「选择日期以日历的形式显示，不然拉的太长了」「像日历软件一样：
   默认显示当月，也可以调整为选季度、选年，选了之后再细选择」。
   所以是「年 → 季 / 月 → 日」三层下钻，而不是一条 487 项的下拉。
   颜色只用一个语义色（--accent）：有记录 = 淡蓝底 + 可点，选中 = 实心蓝。
   其余全是灰阶 —— 日历里塞多种颜色会看不出哪些是真能点的。 */
.aa-cal-panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  padding: 9px 11px 11px;
  margin: 0 0 10px;
}
.aa-cal-head { display: flex; align-items: center; gap: 4px; margin-bottom: 9px; }
.aa-cal-nav {
  width: 22px; height: 22px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); border-radius: 7px;
  color: var(--text-secondary); font-size: 13px; line-height: 1;
  cursor: pointer; font-family: inherit; padding: 0;
}
.aa-cal-nav:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-light); }
.aa-cal-title {
  font-size: 13px; font-weight: 600; color: var(--text-primary);
  padding: 0 5px; letter-spacing: -0.01em; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.aa-cal-modes {
  display: flex; gap: 1px; margin-left: auto;
  background: var(--bg-dark); border-radius: 7px; padding: 2px;
}
.aa-cal-mode {
  padding: 2px 8px; border: none; background: transparent; border-radius: 5px;
  color: var(--text-muted); font-size: 11.5px; font-family: inherit; cursor: pointer;
  transition: background-color .12s, color .12s;
}
.aa-cal-mode:hover { color: var(--text-secondary); }
.aa-cal-mode.active { background: var(--bg-hover); color: var(--text-primary); font-weight: 600; }
.aa-cal-latest {
  flex: 0 0 auto; padding: 3px 8px; border-radius: 7px;
  border: 1px solid var(--border); background: transparent;
  color: var(--text-secondary); font-size: 11.5px; font-family: inherit; cursor: pointer;
  transition: color .12s, border-color .12s;
}
.aa-cal-latest:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

/* ── 月视图 ── */
.aa-cal-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 2px; }
.aa-cal-week span { text-align: center; font-size: 10px; color: var(--text-muted); }
.aa-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.aa-cal-c {
  display: flex; align-items: center; justify-content: center;
  height: 25px; border-radius: 7px; font-size: 12px;
  color: var(--text-muted); background: transparent; border: none;
  font-family: inherit; font-variant-numeric: tabular-nums; padding: 0;
}
.aa-cal-c.empty { visibility: hidden; }
/* 有分析的那天：可点，底色按**当天评级**上色（2026-10-31 用户要求）。
   红涨绿跌是 A 股惯例，强弱两档对应评级的两端，震荡居中给白 ——
   扫一眼日历就知道这段日子是"连续走强"还是"中间夹着几天反弹"。 */
.aa-cal-c.has { color: var(--text-primary); font-weight: 500; cursor: pointer; }
.aa-cal-c.r-s { background: color-mix(in srgb, var(--up) 34%, transparent); }   /* 强势 · 强红 */
.aa-cal-c.r-a { background: color-mix(in srgb, var(--up) 15%, transparent); }   /* 偏多 · 弱红 */
.aa-cal-c.r-n { background: rgba(255, 255, 255, 0.11); }                        /* 震荡 · 白  */
.aa-cal-c.r-b { background: color-mix(in srgb, var(--down) 15%, transparent); } /* 偏空 · 弱绿 */
.aa-cal-c.r-c { background: color-mix(in srgb, var(--down) 34%, transparent); } /* 弱势 · 强绿 */
.aa-cal-c.r-x { background: rgba(255, 255, 255, 0.055); }                       /* 数据不足 */
/* hover 统一提亮，不改色相（改色相会让人以为换了一天） */
.aa-cal-c.has:hover { filter: brightness(1.3); }
/* 选中：实心蓝压过评级色 —— "我正在看这天"优先于"这天什么评级" */
.aa-cal-c.sel,
.aa-cal-c.sel:hover { background: var(--accent); color: #fff; font-weight: 700; filter: none; }
.aa-cal-legend {
  display: flex; align-items: center; gap: 3px 7px; flex-wrap: wrap;
  margin-top: 7px; font-size: 10px; color: var(--text-muted);
}
.aa-cal-dot { width: 9px; height: 9px; border-radius: 3px; background: color-mix(in srgb, var(--accent) 30%, transparent); }
/* 图例色块必须和格子的颜色**完全一致**，否则用户会以为图例说的是另一回事 */
.aa-cal-lg { width: 9px; height: 9px; border-radius: 3px; display: inline-block; }
.aa-cal-lg.r-s { background: color-mix(in srgb, var(--up) 34%, transparent); }
.aa-cal-lg.r-a { background: color-mix(in srgb, var(--up) 15%, transparent); }
.aa-cal-lg.r-n { background: rgba(255, 255, 255, 0.11); }
.aa-cal-lg.r-b { background: color-mix(in srgb, var(--down) 15%, transparent); }
.aa-cal-lg.r-c { background: color-mix(in srgb, var(--down) 34%, transparent); }
.aa-cal-tip { margin-left: auto; opacity: .7; }
.aa-cal-loading { padding: 14px 2px; font-size: 11.5px; color: var(--text-muted); text-align: center; }

/* ── 年视图（12 个月）/ 季视图（4 个季度）：同一套格子，只是列数不同 ── */
.aa-cal-months { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.aa-cal-quarters { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.aa-cal-mo, .aa-cal-q {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  padding: 8px 3px; border-radius: 8px; border: 1px solid transparent;
  background: var(--bg-dark); color: var(--text-muted);
  font-family: inherit; white-space: nowrap;
}
.aa-cal-mo b, .aa-cal-q b { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.aa-cal-mo span, .aa-cal-q span { font-size: 10px; font-variant-numeric: tabular-nums; }
.aa-cal-mo.has, .aa-cal-q.has {
  color: var(--text-primary); cursor: pointer;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}
.aa-cal-mo.has:hover, .aa-cal-q.has:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }

@media (max-width: 768px) {
  .aa-cal-head { flex-wrap: wrap; row-gap: 6px; }
  .aa-cal-modes { margin-left: 0; }
  .aa-cal-c { height: 28px; font-size: 12.5px; }
  .aa-cal-tip { display: none; }
}

/* ── 回看日历的折叠条（2026-10-31）──
   默认收起，只留一行；展开后与下面的 .aa-cal-panel 拼成一块（上方圆角在条上、下方在面板上）。
   收起态必须带「共 N 个交易日 · 起始日」——否则用户会以为库里只有当月那几十天。 */
.aa-cal-bar {
  display: flex; align-items: center; gap: 7px; width: 100%;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 8px 11px;
  color: var(--text-secondary);
  font-family: inherit; font-size: 12px;
  cursor: pointer; text-align: left;
  transition: background-color .12s, border-color .12s;
  margin: 0 0 10px;
}
.aa-cal-bar:hover { background: var(--bg-hover); border-color: var(--border-light); }
.aa-cal-bar.open {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom-color: transparent;
  margin-bottom: 0;
}
.aa-cal-bar .ic { color: var(--text-muted); flex: 0 0 auto; }
.aa-cal-bar-t { font-weight: 600; color: var(--text-primary); white-space: nowrap; }
.aa-cal-bar-n {
  color: var(--text-muted); font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.aa-cal-bar-v {
  flex: 0 0 auto; font-size: 11px; font-weight: 600;
  color: var(--gold);
  background: color-mix(in srgb, var(--gold) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--gold) 32%, transparent);
  padding: 1px 6px; border-radius: 5px;
  font-variant-numeric: tabular-nums;
}
.aa-cal-bar-a { margin-left: auto; flex: 0 0 auto; color: var(--accent); font-size: 11.5px; white-space: nowrap; }

/* 资讯详情底部的原文说明（2026-10-31） */
.news-foot-note { font-size: 11px; color: var(--text-muted); margin-left: 8px; }

/* ===== 资讯详情：自动补全全文（2026-10-31）=====
   用户原话：「我既然要看了不就是要阅读全文吗」——所以去掉了"在站内读全文"这个二次按钮，
   打开即后台抓全文：抓到替换正文，抓不到保留摘要并说明原因 + 给「查看原文」出口。 */
#newsModalFooter { display: flex; align-items: center; gap: 10px; }
.news-foot-out {
  margin-left: auto;
  font-size: 12px; color: var(--accent);
  text-decoration: none; white-space: nowrap;
}
.news-foot-out:hover { text-decoration: underline; }

/* 抓取中的提示条：细、灰、不抢正文 */
.news-loading {
  font-size: 11px; color: var(--text-muted);
  padding-bottom: 6px; margin-bottom: 6px;
  border-bottom: 1px dashed var(--border);
}
/* 正文：保留原有 pre-line 的换行语义（后端给的是段落数组，这里用 \n\n 分隔） */
.news-body { white-space: pre-line; }
/* 抓取失败说明：如实写清可能原因，并指明出口 */
.news-load-fail {
  margin-top: 10px; padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 11px; line-height: 1.6; color: var(--text-muted);
}

/* ===== F10 董监高（2026-10-31）=====
   侧栏宽 218~292px，一条人两行封顶：第一行 姓名 + 主职务 + 其余职务（省略号），
   第二行 性别/年龄/学历 · 年薪 · 持股 · 任职起始。
   颜色只给「董事长」一处强调（--gold）—— 12 个人全上色会变成一排彩标，
   这正是之前被指"花里胡哨"的那类做法。 */
.f10-mgr-sum {
  font-size: 10.5px; color: var(--text-muted);
  padding: 0 1px 6px; font-variant-numeric: tabular-nums;
}
.f10-mgr { display: flex; flex-direction: column; gap: 1px; }
.f10-mgr-item {
  padding: 5px 6px; border-radius: 7px;
  transition: background-color .12s;
}
.f10-mgr-item:hover { background: var(--row-hover); }
.f10-mgr-top {
  display: flex; align-items: baseline; gap: 5px;
  min-width: 0; line-height: 1.35;
}
.f10-mgr-name {
  font-size: 12.5px; font-weight: 600; color: var(--text-primary);
  flex: 0 0 auto; white-space: nowrap;
}
.f10-mgr-pos {
  font-size: 11px; color: var(--text-secondary);
  flex: 0 0 auto; white-space: nowrap;
}
/* 董事长是全表唯一的强调色：他是谁，决定了这份名单要不要细看 */
.f10-mgr-pos.chair { color: var(--gold); font-weight: 600; }
.f10-mgr-rest-t {
  font-size: 10.5px; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0; flex: 1 1 auto;
}
.f10-mgr-meta {
  font-size: 10.5px; color: var(--text-muted);
  line-height: 1.5; margin-top: 1px;
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 折叠条：只有监事/高管时才出现 */
/* 「更新」按钮：复用 .f10-view-all 的尺寸，只加一个 disabled 态 */
.f10-refresh:disabled { opacity: .55; cursor: default; }
/* 备用源标注：金色描边，与"当前这份不是主源"的分量匹配 */
.f10-src-fb {
  color: var(--gold) !important;
  border-color: color-mix(in srgb, var(--gold) 40%, transparent) !important;
}

/* ⚠️ 折叠必须显式压掉 display:flex —— 作者样式的 `.f10-mgr { display:flex }`
   优先级高于 UA 的 `[hidden] { display:none }`，光加 hidden 属性折不起来
   （实测：「展开监事与高管」点了没反应，12 个人一直占着侧栏 176px）。 */

/* ===== F10 董监高（2026-10-31 第二版：面板只留 2 人 + 弹窗看全部）=====
   用户原话：「不需要默认全部都显示出来，只需要显示一两个，然后剩下的通过点击全部
   然后显示出来一个弹窗页面来全部展示出来」。
   侧栏 218~292px 装 12 个人会把下面的板块/股东挤没 → 面板内只留 2 位，其余进弹窗。 */

/* 面板内的「查看全部 N 人」按钮 */
.f10-mgr-all {
  width: 100%; margin-top: 5px;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 5px 8px;
  color: var(--text-secondary);
  font-size: 11.5px; font-family: inherit;
  cursor: pointer;
  transition: color .12s, border-color .12s, background-color .12s;
}
.f10-mgr-all:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: var(--row-hover);
}
.f10-mgr-all-arrow { color: var(--text-muted); font-size: 14px; line-height: 1; }
.f10-mgr-all:hover .f10-mgr-all-arrow { color: var(--accent); }

/* ── 弹窗 ── */
.f10-mgr-box {
  width: min(780px, 94vw);
  max-height: 82vh;
  padding: 20px 22px 16px;
}
.f10-mgr-sub {
  font-size: 12px; color: var(--text-muted);
  margin-left: 8px; margin-right: auto;
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ⚠️ .modal-content 自带 white-space: pre-line（为纯文本资讯设计的），
   结构化 HTML 会被那些换行符撑出一堆空行 → 这里必须显式改回 normal。 */
#f10MgrContent {
  white-space: normal;
  line-height: 1.5;
  padding-right: 6px;
}
.f10-mgr-foot { font-size: 10.5px; line-height: 1.6; color: var(--text-muted); }

/* 分组：董事 / 监事 / 高级管理人员 */
.f10-mgr-g + .f10-mgr-g { margin-top: 16px; }
.f10-mgr-g-h {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 11.5px; font-weight: 600; color: var(--accent);
  border-left: 2px solid var(--accent);
  padding-left: 7px;
  margin-bottom: 7px;
}
.f10-mgr-g-h em {
  font-style: normal; font-weight: 400;
  font-size: 10.5px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* 每人一块 */
.f10-mgr-r { padding: 8px 9px; border-radius: 8px; transition: background-color .12s; }
.f10-mgr-r:hover { background: var(--row-hover); }
.f10-mgr-r + .f10-mgr-r { border-top: 1px solid var(--border); }
.f10-mgr-r-top {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  min-width: 0;
}
.f10-mgr-r-name {
  font-size: 13.5px; font-weight: 600; color: var(--text-primary);
  white-space: nowrap;
}
.f10-mgr-r-pos { font-size: 12px; color: var(--text-secondary); white-space: nowrap; }
/* 全弹窗唯一的强调色：董事长 */
.f10-mgr-r-pos.chair { color: var(--gold); font-weight: 600; }
.f10-mgr-r-rest {
  font-size: 11.5px; color: var(--text-muted);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.f10-mgr-r-meta {
  font-size: 11px; color: var(--text-muted);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
/* 简历：默认 2 行折叠，点一下展开。展开靠 data-expanded（可被验收断言）。 */
.f10-mgr-r-resume {
  font-size: 11.5px; line-height: 1.55;
  color: var(--text-secondary);
  margin-top: 4px;
  cursor: pointer;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.f10-mgr-r-resume[data-expanded="1"] {
  -webkit-line-clamp: unset;
  display: block;
  overflow: visible;
}
.f10-mgr-empty { padding: 16px 2px; font-size: 12px; color: var(--text-muted); text-align: center; }

/* ── 手机端（2026-10-31 用户追加要求：「同时记得给手机端做好适配」）──
   手机上是**贴底的整宽面板**（像 iOS 的 sheet），不是居中小卡片：
   12 个人 + 简历在小卡片里既看不清也点不准。高度 86vh 留出顶部导航可见，
   让用户知道自己在哪一层。 */
@media (max-width: 768px) {
  #f10MgrModal { align-items: flex-end; }
  #f10MgrModal .f10-mgr-box {
    width: 100vw;
    max-width: 100vw;
    height: 86vh;
    max-height: 86vh;
    padding: 14px 13px calc(10px + env(safe-area-inset-bottom, 0px));
    border-radius: 16px 16px 0 0;
    border-left: none; border-right: none; border-bottom: none;
  }
  #f10MgrModal .f10-mgr-sub { font-size: 11px; }
  /* 手机上姓名与职务换成两行：一行并排时"盛雷鸣 独立董事 提名委员会主任委员"必然挤掉 */
  #f10MgrModal .f10-mgr-r-top { gap: 5px 8px; }
  #f10MgrModal .f10-mgr-r-name { font-size: 14px; }
  #f10MgrModal .f10-mgr-r-rest { white-space: normal; overflow: visible; text-overflow: clip; flex-basis: 100%; }
  /* 屏幕高 → 简历多给一行（桌面 2 行、手机 3 行） */
  #f10MgrModal .f10-mgr-r-resume { -webkit-line-clamp: 3; }
  #f10MgrModal .f10-mgr-foot { font-size: 10px; }
}
/* 极窄屏（320px 一类）：再把字号收一档，否则"年薪113.8万 · 任期 2015-07-13 ~"会换三行 */
@media (max-width: 360px) {
  #f10MgrModal .f10-mgr-r-name { font-size: 13px; }
  #f10MgrModal .f10-mgr-r-meta { font-size: 10.5px; }
}

/* ===== 表头：比内容小一档、灰、微加字距（2026-11-02）=====
   原来表头直接继承正文字号（12~13px），只是换了颜色 —— 结果表头和第一行数据
   看起来一般大，"表头"这个概念靠颜色硬撑。专业行情终端（Wind / 彭博 / TradingView）
   的表头一律比数据小一档并略微加宽字距，扫读时眼睛能立刻把表头和数据分开。
   11px 是中文在这个字号下的下限，再小就糊。 */
.watchlist-table th,
.rank-table th,
.ts-table th,
.market-table th {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--text-muted);
}
/* 板块详情表单独一条：它有独立字号声明（12px），需要一起压下去 */
.board-table th {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--text-muted);
}

/* ===== 数字列右对齐（2026-11-02）=====
   这是"业余 vs 专业"的分水岭之一：数字左对齐时小数点不对齐，
   眼睛无法沿列纵向比较大小，只能一个个读。
   专业行情终端（Wind / TradingView / 券商客户端）的数值列一律右对齐 + 等宽数字。
   两个 .rank-table 实例都是 5 列（# / 名称 / 涨跌 / 热度 / 概念|涨停），
   第 3、4 列是纯数字，可以安全地按列位指定，不必给每个 td 加类。 */
.rank-table th:nth-child(3),
.rank-table td:nth-child(3),
.rank-table th:nth-child(4),
.rank-table td:nth-child(4) { text-align: right; }

.rank-table td { font-variant-numeric: tabular-nums; }

/* 左侧人气榜是 flex 行，涨跌幅靠 margin-left:auto 推到右边。
   给一个最小宽度并右对齐，让 +9.89% 和 -100.00% 这种位数不同的值右边缘也齐。 */
.hr-pct { min-width: 58px; text-align: right; font-variant-numeric: tabular-nums; }

/* ===== 补齐三个"从未定义过"的 token（2026-11-02）=====
   实测 --text / --bg / --bg-elev 在 :root 里**根本没有声明**，却被引用了 35 次
   （集中在自动交易 / AI 训练 / 预设参数三块）。后果不是报错，而是**静默失效**：
     · background: var(--bg)  → 整条声明被丢弃，元素透明，露出父级底色
     · color: var(--text)     → 继承父元素颜色（父级若是 .up 红字，这里就变红）
   所以那几块面板看起来"比其他面板平"，而且个别文字颜色随上下文漂移。
   这里补成别名指向现有语义 token —— 比改 35 处用法更安全（改用法容易漏、且要逐个判断语义），
   补定义则是零风险：原本就是这些名字想表达的意思。 */
:root {
  --text: var(--text-primary);
  --bg: var(--bg-dark);        /* 内凹层：输入框、代码块 */
  --bg-elev: var(--bg-card);   /* 抬升层：表头、卡片 */
}

/* ===== 指数卡片文案整理（2026-11-02）=====
   266px 宽的卡片里原来塞了 5 行：名称+代码徽标+"K线›" / 26px 价格 / 涨跌额+涨跌幅 /
   开高低昨收（4 项 flex-wrap，宽度不够就折成两行但断点不可控）。
   三处整理：
     ① 明细 4 项改成 2×2 定宽网格 —— 开高低收永远两行两列，不再随宽度跳。
     ② 「K线 ›」改成 hover 才出现：卡片本身已是 role=button + cursor:pointer + hover 变底色，
        常显的"K线"和右上角的代码徽标挤在一起，只是噪音。
     ③ 代码去掉徽标边框，退回纯灰字 —— 一个 6 位数字不需要框，框多了整排卡片像表格。 */
.index-card .gi-detail {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px 12px;
  margin-top: 9px;
}
.index-card .gi-detail > span {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}
.index-card .gi-detail b {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.index-card.is-clickable .gi-go {
  opacity: 0;
  transform: translateX(-2px);
  transition: opacity .14s, transform .14s, color .14s;
}
.index-card.is-clickable:hover .gi-go,
.index-card.is-clickable:focus-visible .gi-go {
  opacity: 1;
  transform: translateX(0);
  color: var(--accent);
}
.index-card .gi-currency {
  border: none;
  padding: 0;
  font-size: 10.5px;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

/* 明细区数值降为次级色（2026-11-02）
   开/昨收原本是纯白（--text #f5f5f7），比标签灰跳太多，四格明细整体比价格还亮。
   卡片的主角是价格和涨跌幅，明细只做背景信息 → 降到 --text-secondary；
   「高/低」保留红绿方向色（这是行情软件的通行语义：最高价高于昨收即红）。 */
.index-card .gi-detail b { color: var(--text-secondary); }
.index-card .gi-detail b.up { color: var(--up); }
.index-card .gi-detail b.down { color: var(--down); }

/* ===== 顶部状态区在中等宽度下的取舍（2026-11-02）=====
   1280 视口下 brand(87) + 14 个导航 tab(758) + 状态区(436) = 1281 → 横向滚动条多出 1px，
   而状态区里 266px 是「自动刷新中 · 全球市场交易中 · 下次 59s 后」这三段拼在一起的文字。
   按信息优先级处理：**正常态不占位置，异常态才出现**。
     · .ok      → 隐藏（"正在自动刷新"是常态，心跳点+时钟已足够）
     · .paused  → 显示（切到后台暂停了，用户回来要能看懂）
     · .bad     → 显示（刷新卡住，必须看到，且可点击重试）
   这样窄屏不会横向滚动，异常时又不会漏掉提示。 */
@media (max-width: 1440px) {
  .top-actions { gap: 12px; }
  .top-actions .poll-hb.ok { display: none; }
}

/* ===== 分段控件激活态：实心改淡底（2026-11-02）=====
   .hr-tab 是 flex:1 均分宽度的分段控件。桌面端它待在窄侧栏里，两个 tab 各 ~80px，
   实心蓝看着像个 chip 还好；手机端容器变成整宽，两个 tab 各 172×27，
   一整块实心系统蓝比页面上的任何数据都抢眼 —— 控件的视觉重量超过了它控制的内容。
   改成淡底 + 描边 + 蓝字 + 加粗：同样能看出"选中"，但不再压过行情数字。 */
.hr-tab.active {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--accent);
  font-weight: 600;
}

/* ================= F10 参股控股 (2026-11-02) =================
   侧栏 218~292px，一行只放「序号 + 名称(省略号) + 比例」三样；
   注册资本挪到 hover 提示里，不占首屏宽度。 */
.f10-hold { display: flex; flex-direction: column; gap: 4px; }
.f10-hold-row {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; line-height: 1.4;
}
.f10-hold-idx {
  flex: none; width: 16px; text-align: right;
  color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.f10-hold-name {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-secondary);
}
.f10-hold-ratio {
  flex: none; color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
/* 弹窗表格：比董监高密（一屏可能 100+ 行），表头吸顶 */
.f10-hold-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12px; }
.f10-hold-table th {
  position: sticky; top: 0; z-index: 1;
  padding: 8px 10px; text-align: left; font-weight: 500;
  color: var(--text-muted); background: var(--bg-card);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.f10-hold-table td {
  padding: 7px 10px; border-bottom: 1px solid var(--border);
  color: var(--text-secondary); vertical-align: middle;
}
.f10-hold-table th.num, .f10-hold-table td.num {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.f10-hold-table .f10-hold-no { width: 34px; color: var(--text-muted); }
.f10-hold-table tbody tr:hover td { background: var(--bg-hover); }
.f10-hold-table tbody tr:last-child td { border-bottom: none; }

/* ===== 登录页 (2026-11-03 v2: 独立整页) =====
   上一版是"全屏蒙版 + 居中浮动卡片", 本质还是个弹窗: 背后能看见看板, 卡片靠阴影浮起来。
   这一版把登录做成一张**真正的页面**——没有蒙版, 没有卡片边框, 没有投影:
     · 整个视口就是页面本身(不透明), 左栏是品牌叙事, 右栏是表单, 中间一条发丝线分隔;
     · 层级靠"字体大小 + 留白 + 一条 hairline"建立, 不靠阴影/发光/渐变(全站约定);
     · 显隐只认 body.auth-locked 一个类, 见 index.html 注释。 */
body.auth-locked .app-scale { visibility: hidden; }
body.auth-locked { overflow: hidden; }

.auth-page {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  /* 比应用底(--bg-darkest #121214)再沉一档: 登录页要有自己的"场", 一进来就知道换了个界面 */
  background: #0b0b0d;
  color: var(--text-primary);
  overflow: hidden;
  /* 延迟 180ms 再淡入: 本机免登录/已登录刷新时, 鉴权在 200ms 内就返回并摘掉 auth-locked,
     页面还没开始可见就被 display:none 收走 —— 本地用户不会看到"闪一下登录页"。
     未登录者则多等这 180ms 后淡入, 观感是从暗处浮上来, 不是硬切。 */
  animation: authPageIn 0.5s cubic-bezier(0.22, 0.7, 0.2, 1) 0.18s both;
}
/* 未锁定时整块不参与布局/绘制(而不是 opacity:0 —— 那样登录表单还能被 tab 聚焦到) */
body:not(.auth-locked) .auth-page { display: none; }
@keyframes authPageIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* --- 顶栏: 只有品牌与一句状态, 保持极薄 --- */
.auth-top {
  flex: none;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(20px, 4.4vw, 56px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.auth-brand { display: flex; align-items: baseline; gap: 10px; }
.auth-mark { color: var(--accent); font-size: 13px; line-height: 1; }
.auth-brand-name { font-size: 15px; font-weight: 600; letter-spacing: 0.14em; }
.auth-brand-sub {
  font-size: 11.5px; color: var(--text-muted); letter-spacing: 0.08em;
  padding-left: 11px; border-left: 1px solid rgba(255, 255, 255, 0.12);
}
.auth-top-right {
  display: flex; align-items: center; gap: 7px;
  font-size: 11.5px; color: var(--text-muted); letter-spacing: 0.03em;
}
.auth-top-right .ic { width: 12px; height: 12px; opacity: 0.8; }

/* --- 主体: 左叙事 / 右表单。右栏定宽夹在 360~460, 保证输入框不会宽到难读 --- */
.auth-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(360px, 33vw, 460px);
  overflow: hidden;
}

/* --- 左栏 --- */
.auth-hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(28px, 3.6vw, 64px) clamp(24px, 4.6vw, 80px);
}
.auth-eyebrow {
  font-size: 10.5px;
  letter-spacing: 0.2em;
  color: var(--text-muted);
  text-transform: uppercase;
}
.auth-h1 {
  margin-top: clamp(14px, 1.6vw, 22px);
  /* 字号跟视口走: 1280 宽时约 38px, 1920 宽时 50px —— 始终是页面上唯一的大字 */
  font-size: clamp(28px, 2.9vw, 56px);
  line-height: 1.18;
  font-weight: 600;
  letter-spacing: -0.025em;
  color: #f7f7f9;
}
.auth-lead {
  margin-top: clamp(12px, 1.4vw, 20px);
  max-width: 33em;
  font-size: clamp(12.5px, 0.9vw, 14px);
  line-height: 1.8;
  color: var(--text-secondary);
}
.auth-art {
  margin: clamp(20px, 2.6vw, 40px) 0 0;
  height: clamp(104px, 20vh, 280px);
}
.auth-art svg { display: block; width: 100%; height: 100%; }

/* 规格带: 三列, 顶部一条发丝线。形制取自产品页的 technical specs, 用字形大小分层, 不用框 */
.auth-spec {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 28px);
  margin: clamp(20px, 2.4vw, 36px) 0 0;
  padding-top: clamp(14px, 1.4vw, 20px);
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.auth-spec dt {
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.auth-spec dd {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-secondary);
}

/* --- 右栏: 表单直接坐在页面上, 没有卡片 --- */
.auth-side {
  display: flex;
  align-items: center;
  padding: 0 clamp(24px, 3.2vw, 52px);
  border-left: 1px solid rgba(255, 255, 255, 0.07);
}
.auth-form-wrap { width: 100%; max-width: 340px; margin: 0 auto; }
.auth-h2 { font-size: clamp(20px, 1.5vw, 24px); font-weight: 600; letter-spacing: -0.02em; }
.auth-h2-sub { margin-top: 9px; font-size: 12.5px; line-height: 1.65; color: var(--text-muted); }

.auth-form { margin-top: clamp(20px, 2.2vw, 30px); }
.auth-field + .auth-field { margin-top: 14px; }
.auth-label {
  display: block;
  margin-bottom: 8px;
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.auth-input {
  width: 100%;
  height: 42px;
  padding: 0 13px;
  font-family: inherit;
  font-size: 13.5px;
  color: var(--text-primary);
  /* 输入框底比页面底亮 4%: 靠明度区分可输入区, 不靠描边(苹果暗色表单的做法) */
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 10px;
  outline: none;
  transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease;
}
.auth-input::placeholder { color: #64646b; }
.auth-input:hover { border-color: rgba(255, 255, 255, 0.16); }
.auth-input:focus {
  border-color: rgba(10, 132, 255, 0.85);
  background: rgba(255, 255, 255, 0.065);
  /* 焦点环用外扩 shadow 而非 outline: 输入框高度固定, 不占布局 */
  box-shadow: 0 0 0 3.5px rgba(10, 132, 255, 0.16);
}
.auth-input:focus-visible { outline: none; }

/* 错误行: 常驻占位(避免出现/消失时按钮跳动)。用琥珀而不是红/绿 ——
   本系统里红绿是涨跌语义, 拿来表示"密码错"会串味。 */
.auth-err {
  min-height: 18px;
  margin-top: 10px;
  font-size: 12px;
  line-height: 18px;
  color: var(--gold);
}
.auth-btn {
  width: 100%;
  height: 42px;
  margin-top: 6px;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-indent: 0.16em; /* 抵消字间距造成的视觉左偏 */
  color: var(--on-accent);
  background: var(--accent);
  border: none;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.16s ease, transform 0.1s ease;
}
.auth-btn:hover { background: #2f95ff; }
.auth-btn:active { transform: scale(0.995); }
.auth-btn:disabled { opacity: 0.6; cursor: default; }
.auth-btn:focus-visible { outline: 2px solid rgba(10, 132, 255, 0.9); outline-offset: 3px; }

.auth-foot {
  margin-top: clamp(16px, 1.8vw, 26px);
  padding-top: 14px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 11px;
  line-height: 1.7;
  color: var(--text-muted);
}

/* 页脚细条: 有了它, "分栏"才是贯穿整页的结构(竖线到页脚为止), 而不是浮在半空的两块内容。
   同时把大屏底部那块空白收住 —— 否则 1920 高屏下半页看着像没做完。 */
.auth-bottombar {
  flex: none;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(20px, 4.4vw, 56px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: #6b6b72;
}

@media (prefers-reduced-motion: reduce) {
  .auth-page { animation: none; }
}

/* --- 窄屏(平板竖屏 / 手机): 折成单列。左栏只留"标题 + 一行说明", 走势图与规格带隐藏 --- */
@media (max-width: 900px) {
  .auth-page { animation-duration: 0.32s; }
  .auth-top { height: 54px; padding: 0 20px; }
  .auth-top-right { display: none; }
  .auth-body {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .auth-hero {
    padding: 26px 22px 0;
    justify-content: flex-start;
  }
  .auth-h1 {
    margin-top: 12px;
    font-size: clamp(24px, 6.6vw, 30px);
    line-height: 1.24;
  }
  .auth-lead { margin-top: 10px; font-size: 12.5px; line-height: 1.7; }
  .auth-lead br { display: none; } /* 手机上按容器宽度自然折行, 不吃固定断点 */
  /* 手机上保留一小段走势图: 纯文字的首屏太像"表单页", 一条线就能把品牌感立住 */
  .auth-art { height: 76px; margin-top: 16px; opacity: 0.9; }
  .auth-spec { display: none; }
  .auth-side {
    /* safe center: 空间够就居中(不在首屏底部留一大块空), 不够就退回顶端对齐, 顶部不会被裁 */
    align-items: safe center;
    border-left: none;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
    margin-top: 22px;
    padding: 24px 22px calc(28px + env(safe-area-inset-bottom));
  }
  .auth-form-wrap { max-width: 420px; }
  .auth-form { margin-top: 18px; }
  /* 手机键盘弹起时视口高度会缩, 输入框 16px 可避免 iOS 自动放大 */
  .auth-input { height: 46px; font-size: 16px; }
  .auth-btn { height: 46px; font-size: 15px; }
  .auth-bottombar {
    height: calc(36px + env(safe-area-inset-bottom));
    padding: 0 20px calc(env(safe-area-inset-bottom));
    font-size: 10px;
    letter-spacing: 0.02em;
  }
}
/* 矮屏(SE 级 667 及以下): 首屏必须能看见「登录」按钮。
   按重要性依次让位 —— 先撤装饰走势图, 再收紧间距, 最后缩小说明字。
   (实测 375x667: 不处理时按钮底边落在 668, 比首屏多出 37px, 必须滚一下才看得见。) */
@media (max-width: 900px) and (max-height: 700px) {
  .auth-hero { padding-top: 20px; }
  .auth-art { display: none; }
  .auth-side { margin-top: 12px; padding-top: 16px; }
  .auth-lead { font-size: 12px; line-height: 1.65; }
  .auth-foot { margin-top: 12px; font-size: 10.5px; }
  .auth-bottombar { height: calc(34px + env(safe-area-inset-bottom)); }
}
/* 极端矮屏(横屏手机): 左栏压到最小, 保证表单在首屏内 */
@media (max-width: 900px) and (max-height: 560px) {
  .auth-lead { display: none; }
  .auth-hero { padding-top: 16px; }
  .auth-side { margin-top: 10px; padding-top: 14px; }
}
.auth-user { display: inline-flex; align-items: center; gap: 8px; }
.auth-uname { font-size: 12px; color: var(--text-secondary); }
.auth-admin-link { font-size: 12px; color: var(--accent); text-decoration: none; }
.auth-admin-link:hover { text-decoration: underline; }
.auth-logout {
  font-size: 12px;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  padding: 3px 8px;
  cursor: pointer;
  font-family: inherit;
}
.auth-logout:hover { color: var(--down); border-color: var(--down); }

/* 手机端: 用户区收窄(顶栏空间紧) */
@media (max-width: 1280px) {
  .auth-uname { max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
