/* StockSentry · 浅色专业金融主题（A股习惯：红涨绿跌） */
:root{
  --bg:#f4f5f7; --card:#ffffff; --line:#e5e7eb; --line-2:#f0f1f3;
  --ink:#15171c; --ink-2:#3d434d; --muted:#7a828f;
  --up:#d0342c; --up-bg:#fdeceb; --down:#12855a; --down-bg:#e9f6f0;
  --accent:#2450a4; --accent-bg:#eef2fb;
  --warn:#b4740a; --warn-bg:#fdf5e6;
  --radius:12px; --shadow:0 1px 2px rgba(16,24,40,.05),0 1px 3px rgba(16,24,40,.06);
}
*{box-sizing:border-box}
[hidden]{display:none !important}
html,body{margin:0;height:100%}
body{
  background:var(--bg); color:var(--ink); font:14px/1.6 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  -webkit-font-smoothing:antialiased;
}
button{font-family:inherit;cursor:pointer}
h1,h2,h3,h4{margin:0}
b,strong{font-weight:600}
.up{color:var(--up)} .down{color:var(--down)} .flat{color:var(--muted)}

/* ---------- 顶栏 ---------- */
.topbar{
  height:60px;display:flex;align-items:center;justify-content:space-between;
  padding:0 22px;background:#fff;border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:50;
}
.brand{display:flex;align-items:center;gap:12px}
.logo{
  width:34px;height:34px;border-radius:9px;background:linear-gradient(135deg,#2450a4,#3f7ad6);
  color:#fff;display:grid;place-items:center;font-weight:700;font-size:17px;
}
.brand h1{font-size:16px;letter-spacing:.2px}
.brand p{font-size:11.5px;color:var(--muted);margin:1px 0 0}
.topbar-right{display:flex;align-items:center;gap:14px}
.clock{text-align:right;line-height:1.25}
.clock span{font-variant-numeric:tabular-nums;font-weight:600;font-size:14px}
.clock small{display:block;font-size:11px;color:var(--muted)}
.switch{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--ink-2);cursor:pointer;user-select:none}
.switch input{accent-color:var(--accent)}
.switch b{color:var(--accent)}

/* ---------- 按钮 ---------- */
.btn{
  border:1px solid var(--line);background:#fff;color:var(--ink-2);
  padding:6px 13px;border-radius:8px;font-size:12.5px;transition:.15s;
}
.btn:hover{background:#f7f8fa;border-color:#d6d9de}
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.primary:hover{background:#1d4289}
.btn.ghost:disabled{opacity:.45;cursor:not-allowed}
.btn.tiny{padding:3px 8px;font-size:11.5px;border-radius:6px}

/* ---------- 布局 ---------- */
.layout{display:flex;height:calc(100vh - 60px);overflow:hidden}
.sidebar{
  width:270px;flex:0 0 270px;border-right:1px solid var(--line);background:#fff;
  display:flex;flex-direction:column;overflow:hidden;
}
.side-block{padding:14px;border-bottom:1px solid var(--line-2)}
.side-block.grow{flex:1;overflow:auto;border-bottom:0}
.side-title{font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.4px;margin-bottom:9px;display:flex;align-items:center;gap:7px}
.pill{background:var(--accent-bg);color:var(--accent);border-radius:99px;padding:0 7px;font-size:11px;font-weight:600}
.search-row{display:flex;gap:6px}
.search-row input{
  flex:1;min-width:0;border:1px solid var(--line);border-radius:8px;padding:7px 10px;font-size:12.5px;
  outline:none;background:#fbfbfc;color:var(--ink);
}
.search-row input:focus{border-color:var(--accent);background:#fff}
.search-results{margin-top:8px;display:flex;flex-direction:column;gap:4px;max-height:190px;overflow:auto}
.sr-item{
  display:flex;justify-content:space-between;align-items:center;padding:7px 10px;border-radius:8px;
  background:#fafbfc;border:1px solid var(--line-2);font-size:12.5px;
}
.sr-item:hover{background:var(--accent-bg);border-color:#d5ddf2}
.sr-item .sr-name{font-weight:600}
.sr-item .sr-meta{font-size:11px;color:var(--muted)}

.watchlist{display:flex;flex-direction:column;gap:6px}
.wl-item{
  border:1px solid var(--line);border-radius:10px;padding:9px 11px;cursor:pointer;background:#fff;transition:.15s;
  border-left:3px solid transparent;
}
.wl-item:hover{background:#fafbfc}
.wl-item.active{border-left-color:var(--accent);background:var(--accent-bg);border-color:#d5ddf2}
.wl-row1{display:flex;justify-content:space-between;align-items:baseline}
.wl-name{font-weight:600;font-size:13px}
.wl-code{font-size:11px;color:var(--muted)}
.wl-row2{display:flex;justify-content:space-between;align-items:baseline;margin-top:3px}
.wl-price{font-variant-numeric:tabular-nums;font-weight:600;font-size:14.5px}
.wl-chg{font-variant-numeric:tabular-nums;font-size:12.5px}
.wl-del{opacity:0;font-size:11px;color:var(--muted);border:0;background:none;padding:0 2px}
.wl-item:hover .wl-del{opacity:1}
.loading,.empty-hint{color:var(--muted);font-size:12.5px;padding:10px 2px}

/* ---------- 内容 ---------- */
.content{flex:1;overflow:auto;padding:18px 22px 60px}
.empty{display:grid;place-items:center;height:100%;text-align:center;color:var(--muted)}
.empty h2{font-size:17px;color:var(--ink-2);margin-bottom:6px}
.empty p{font-size:13px;max-width:430px}
.empty-icon{font-size:44px;color:#c9cfda;margin-bottom:10px}

/* ---------- 失败诊断面板 ---------- */
/* 静态版没有后端可查日志，失败必须「自己说话」：把原因与环境事实直接摊在页面上 */
.build-tag{font-size:10px;color:var(--muted);background:var(--line-2);border-radius:4px;padding:1px 5px;margin-left:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.empty-diag{max-width:820px}
.diag{background:var(--card);border:1px solid #f0cfcb;border-left:4px solid var(--up);border-radius:var(--radius);box-shadow:var(--shadow);padding:16px 18px;text-align:left}
.diag h3{font-size:14.5px;color:var(--up);margin-bottom:8px}
.diag-cause{background:var(--up-bg);border:1px solid #f6d5d2;border-radius:8px;padding:10px 12px;font-size:13px;color:#7d2b25;margin:0 0 12px;line-height:1.65}
.diag-cause code{background:rgba(255,255,255,.7)}
.diag-tb{width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed}
.diag-tb td{border-top:1px solid var(--line-2);padding:7px 8px;vertical-align:top;word-break:break-all}
.diag-tb tr:first-child td{border-top:0}
.diag-tb td:first-child{width:132px;color:var(--muted);white-space:nowrap}
.diag-tb code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;color:var(--ink-2)}
.diag-sub{font-size:12.5px;font-weight:600;color:var(--ink-2);margin:16px 0 6px}
.diag-actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0 0}
.diag-out{margin-top:10px}
.diag-row{display:flex;gap:10px;justify-content:space-between;align-items:flex-start;font-size:12px;padding:6px 9px;border-radius:7px;background:var(--line-2);margin-bottom:5px;word-break:break-all}
.diag-row span{color:var(--muted);flex:0 0 auto}
.diag-row b{font-weight:500;color:var(--ink-2);text-align:right}
.diag-row b.bad{color:var(--up)}
.diag-note{font-size:11.5px;color:var(--muted);margin:10px 0 0}

.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:16px 18px;margin-bottom:14px}
.card-title{font-size:13px;font-weight:600;color:var(--ink-2);margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.sub-title{font-size:12px;color:var(--muted);font-weight:600;margin:12px 0 7px}
.hint{color:var(--muted);font-size:12.5px}

/* 标的头部 */
.stock-head{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}
.sh-name{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.sh-name h2{font-size:20px}
.code{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.tags{display:flex;gap:5px;flex-wrap:wrap}
.tag{background:var(--accent-bg);color:var(--accent);font-size:11px;padding:1px 8px;border-radius:99px}
.sh-price{display:flex;align-items:baseline;gap:10px;margin-top:6px}
.price{font-size:30px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.5px}
.change{font-size:14px;font-weight:600;font-variant-numeric:tabular-nums}
.sh-time{font-size:11.5px;color:var(--muted);margin-top:2px}
.sh-stats{display:grid;grid-template-columns:repeat(4,minmax(96px,auto));gap:8px 22px;align-content:center}
.stat{font-size:12px}
.stat span{display:block;color:var(--muted);font-size:11px}
.stat b{font-variant-numeric:tabular-nums;font-weight:600}

/* 结论卡 */
.grid-2{display:grid;grid-template-columns:1.05fr .95fr;gap:14px}
@media (max-width:1200px){.grid-2{grid-template-columns:1fr}}
.verdict-main{display:flex;gap:18px;align-items:center}
.gauge{position:relative;width:108px;height:108px;flex:0 0 108px}
.gauge svg{width:100%;height:100%;transform:rotate(-90deg)}
.gauge-bg{fill:none;stroke:#eef0f3;stroke-width:9}
.gauge-fg{fill:none;stroke:var(--accent);stroke-width:9;stroke-linecap:round;stroke-dasharray:327;stroke-dashoffset:327;transition:stroke-dashoffset .7s ease,stroke .3s}
.gauge-num{position:absolute;inset:0;display:grid;place-content:center;text-align:center}
.gauge-num b{font-size:26px;font-variant-numeric:tabular-nums;line-height:1}
.gauge-num small{font-size:10.5px;color:var(--muted);display:block;margin-top:2px}
.verdict-body{flex:1;min-width:0}
.action-label{font-size:22px;font-weight:700;letter-spacing:.5px}
.action-desc{font-size:12.5px;color:var(--muted);margin:4px 0 12px}
.score-bars{display:flex;flex-direction:column;gap:6px}
.sb{display:grid;grid-template-columns:52px 1fr 30px;align-items:center;gap:8px;font-size:11.5px;color:var(--muted)}
.sb .bar{height:6px;background:#eef0f3;border-radius:99px;overflow:hidden}
.sb .bar i{display:block;height:100%;width:0;background:var(--accent);border-radius:99px;transition:width .6s ease}
.sb b{font-variant-numeric:tabular-nums;color:var(--ink-2);text-align:right}
.reasons{margin:14px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px;max-height:230px;overflow:auto}
.reasons li{font-size:12.5px;color:var(--ink-2);padding:7px 11px;background:#fafbfc;border-radius:8px;border-left:3px solid var(--line)}
.reasons li.bull{border-left-color:var(--up);background:var(--up-bg)}
.reasons li.bear{border-left-color:var(--down);background:var(--down-bg)}

/* 计划卡 */
.plan-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
.pg-item{background:#fafbfc;border:1px solid var(--line-2);border-radius:9px;padding:8px 10px}
.pg-item span{display:block;font-size:11px;color:var(--muted)}
.pg-item b{font-size:14px;font-variant-numeric:tabular-nums}
/* P3 价位口径披露徽标：区分研报给定 / ATR反推 / 引擎推导 */
.lv-badge{display:inline-block;margin-left:5px;padding:0 5px;border-radius:5px;font-size:9.5px;font-style:normal;line-height:15px;vertical-align:1px}
.lv-report{background:#eaf3ff;color:#2563eb;border:1px solid #cfe0ff}
.lv-auto{background:#fff4e0;color:#b9700a;border:1px solid #f4dca0}
.lv-engine{background:#eef1f4;color:#5b6672;border:1px solid #dde3e9}
.mini-table{width:100%;border-collapse:collapse;font-size:12px}
.mini-table th,.mini-table td{border-bottom:1px solid var(--line-2);padding:5px 6px;text-align:left}
.mini-table th{color:var(--muted);font-weight:600;font-size:11px}
.level-list{display:flex;flex-direction:column;gap:4px}
.level-row{display:flex;justify-content:space-between;font-size:12px;padding:4px 8px;border-radius:6px;background:#fafbfc}
.level-row.res{border-left:3px solid var(--down)}
.level-row.sup{border-left:3px solid var(--up)}

/* 图表 */
.chart-card{padding-bottom:8px}
canvas{width:100%;display:block}
.chart-legend{font-size:11px;color:var(--muted);display:flex;align-items:center;gap:9px;font-weight:400;flex-wrap:wrap}
/* 每个图例项必须是一个不可拆分的整体。
   原来图例是「<i> + 裸文本 + <i> + 裸文本」混排，Flex 会把裸文本当成匿名 flex item，
   窄屏下能被压到 min-content = 一个字宽 —— 于是标题区出现「上/轨」「下/轨」这种竖排单字，
   把卡片标题彻底挤变形。包一层 .lg 并禁止内部换行，问题从根上没有了。 */
.chart-legend .lg{display:inline-flex;align-items:center;white-space:nowrap}
.chart-legend i{display:inline-block;width:9px;height:3px;border-radius:2px;margin-right:3px;vertical-align:middle;flex:0 0 auto}
.lg-price{background:#2450a4}.lg-avg{background:#e6a23c}
.lg-ma5{background:#e6a23c}.lg-ma10{background:#2450a4}.lg-ma20{background:#8e44ad}.lg-ma60{background:#12855a}

/* 信号 */
.tabs{display:flex;gap:4px}
.tab{border:1px solid var(--line);background:#fff;color:var(--muted);padding:4px 11px;border-radius:7px;font-size:12px}
.tab.active{background:var(--accent);border-color:var(--accent);color:#fff}
.tab b{font-variant-numeric:tabular-nums;font-weight:600}
.signal-list{display:flex;flex-direction:column;gap:8px}
.sig{border:1px solid var(--line-2);border-left:4px solid var(--line);border-radius:9px;padding:10px 13px;background:#fff;transition:.15s}
.sig:hover{background:#fafbfc}
.sig.bull{border-left-color:var(--up)}
.sig.bear{border-left-color:var(--down)}
.sig-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.sig-name{font-weight:600;font-size:13.5px}
.sig-dim{font-size:11px;color:var(--muted);background:#f4f5f7;padding:1px 7px;border-radius:99px}
.sig-stars{color:#e6a23c;font-size:11px;letter-spacing:1px}
.sig-side{font-size:11px;font-weight:600;padding:1px 8px;border-radius:99px}
.sig-side.bull{background:var(--up-bg);color:var(--up)}
.sig-side.bear{background:var(--down-bg);color:var(--down)}
.sig-side.neutral{background:#f4f5f7;color:var(--muted)}
.sig-text{font-size:12.5px;color:var(--ink-2);margin-top:5px}
.sig-evi{font-size:11.5px;color:var(--muted);margin-top:4px;font-variant-numeric:tabular-nums}

/* 表格 */
table.data{width:100%;border-collapse:collapse;font-size:12.5px}
table.data th,table.data td{border-bottom:1px solid var(--line-2);padding:8px 10px;text-align:left;vertical-align:top}
table.data th{color:var(--muted);font-weight:600;font-size:11.5px;background:#fafbfc}
table.data tbody tr:hover{background:#fafbfc}

/* 画像 */
.profile-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:10px;margin-top:4px}
.pf-box{background:#fafbfc;border:1px solid var(--line-2);border-radius:9px;padding:10px 12px}
.pf-box h4{font-size:12px;color:var(--muted);margin-bottom:5px}
.pf-box p{font-size:12.5px;color:var(--ink-2);margin:0}
.thesis{font-size:13px;color:var(--ink-2);background:var(--accent-bg);border-radius:9px;padding:11px 13px;margin-bottom:10px;border-left:3px solid var(--accent)}

/* 报告 */
.report-actions{display:flex;gap:7px}
.report-body{border-top:1px solid var(--line-2);padding-top:14px;max-height:760px;overflow:auto}
.report-body h1{font-size:20px;margin:0 0 12px;padding-bottom:10px;border-bottom:2px solid var(--up)}
.report-body h2{font-size:16px;margin:24px 0 10px;padding-left:10px;border-left:4px solid var(--accent)}
.report-body h3{font-size:14px;margin:16px 0 8px;color:var(--ink-2)}
.report-body h4{font-size:13px;margin:12px 0 6px}
.report-body table{width:100%;border-collapse:collapse;font-size:12.5px;margin:10px 0}
.report-body th,.report-body td{border:1px solid var(--line);padding:7px 9px;text-align:left;vertical-align:top}
.report-body th{background:#fafbfc;font-weight:600;font-size:11.5px;color:var(--muted)}
.report-body blockquote{margin:10px 0;padding:9px 14px;background:#fafbfc;border-left:3px solid var(--line);color:var(--ink-2);font-size:12.5px}
.report-body blockquote p{margin:3px 0}
.report-body ul{margin:8px 0;padding-left:20px}
.report-body li{font-size:13px;margin:4px 0}
.report-body hr{border:0;border-top:1px solid var(--line);margin:22px 0}
.report-body code{background:#f4f5f7;padding:1px 5px;border-radius:4px;font-size:12px}
.report-body .badge{display:inline-block;background:var(--accent-bg);color:var(--accent);padding:1px 9px;border-radius:99px;font-size:11.5px}
.report-body p{font-size:13px;margin:8px 0}

/* 轨道研判 —— 整张卡片走「按可用宽度分栏」的横向布局，
   而不是「小于某宽度就一律竖排」。实测：横屏手机 852px、平板 820px 本来放得下三列，
   被一刀切压成一列后，每个格子 790px 宽里只有百来字，右侧约 590px 全是空白
   （用户报的「内容挤在左、右边大片留白」）。 */
.chapter-note{font-size:11px;font-weight:400;color:var(--muted)}
/* 研判结论条：宽屏「徽章 + 建议」并排铺满整宽；窄屏建议独占整行。
   原来是 flex+wrap，而移动端覆盖块里的 .ch-advice{min-width:0} 允许它缩到 min-content ——
   393px 竖屏实测只剩 87px 宽 / 286px 高，一句观望建议被压成一条竖缝。 */
.ch-zone-row{display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px 14px;align-items:start;margin-bottom:12px}
/* 「观望 / 中部位」这类结论必须一眼可见：前置圆点用 currentColor，自动跟随语义色。
   width:max-content + justify-self:start 是必要的：单列网格下 grid item 会被 blockify
   并拉满整行宽度，徽章会变成一条横幅而不是胶囊。 */
.ch-zone{justify-self:start;width:max-content;display:inline-flex;align-items:center;gap:8px;font-size:17px;font-weight:700;padding:8px 16px;border-radius:10px;background:#f4f5f7;white-space:nowrap}
.ch-zone::before{content:'';width:9px;height:9px;border-radius:50%;background:currentColor;flex:0 0 auto}
.ch-advice{min-width:0;font-size:12.5px;color:var(--ink-2);background:#fafbfc;border-left:4px solid var(--line);border-radius:8px;padding:9px 13px;line-height:1.7}
/* 建议由 app.js 按句拆开渲染：窄屏逐句成行（层次清晰、不再挤成竖缝），
   宽屏横向流式铺满整行 —— 横向空间被真正用起来，右侧不留白。 */
.ch-advice .ad-seg{display:block}
@media (min-width:620px){
  .ch-advice{display:flex;flex-wrap:wrap;align-items:baseline;gap:1px 16px}
  .ch-advice .ad-seg{display:inline}
}
/* 窄屏必须退成单列：徽章是 nowrap 的 245px 宽，两列布局下留给建议的只剩几十像素，
   建议会被压成一条竖缝（实测 393px 竖屏：宽 72px / 高 401px，每行 3 个字）。
   单列后建议拿到整行宽度，逐句成行 —— 这才是「观望提示醒目易读」。 */
@media (max-width:619px){
  .ch-zone-row{grid-template-columns:minmax(0,1fr)}
}
/* 三块指标按可用宽度自适应列数。230px 是最小可读宽度：
   393px 竖屏只排得下 1 列；852px 横屏、820px 平板、桌面都排 3 列。 */
.channel-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:9px;margin-bottom:14px}
.ch-item{background:#fafbfc;border:1px solid var(--line-2);border-radius:9px;padding:9px 11px}
.ch-item h4{font-size:11.5px;color:var(--muted);font-weight:600;margin-bottom:5px}
.ch-item .ch-vals{font-size:12.5px;font-variant-numeric:tabular-nums;line-height:1.7}
.ch-item .ch-vals em{font-style:normal;color:var(--muted);font-size:11px}
.rail-viz{display:flex;flex-direction:column;gap:13px;padding:4px 2px 2px}
.rv-row{display:grid;grid-template-columns:104px 1fr 76px;align-items:center;gap:12px;font-size:11.5px}
.rv-label{color:var(--muted);font-weight:600}
.rv-track{position:relative;height:22px;background:#f4f5f7;border-radius:6px;border:1px solid var(--line-2);overflow:visible}
.rv-zone{position:absolute;top:0;bottom:0;border-radius:5px}
.rv-mark{position:absolute;top:-3px;bottom:-3px;width:3px;border-radius:2px;background:#15171c;box-shadow:0 0 0 2px #fff}
.rv-mark::after{content:'';position:absolute;left:50%;top:-7px;transform:translateX(-50%);border:5px solid transparent;border-top-color:#15171c}
.rv-val{font-variant-numeric:tabular-nums;font-weight:600;text-align:right}
.rv-ticks{position:relative;height:14px;margin-top:-6px}
.rv-tick{position:absolute;transform:translateX(-50%);font-size:10px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
/* 首尾刻度改成贴边对齐。原来三个刻度统一 translateX(-50%)，
   而 `left:100%` 那个会向右溢出一半字宽、撞进右侧数值列 ——
   实测横屏下「15.49」与「区间 18.4%」直接叠在一起。 */
.rv-ticks .rv-tick:first-child{transform:translateX(0)}
.rv-ticks .rv-tick:last-child{transform:translateX(-100%)}

/* 轨道数据不可用时的占位行：整行必须还在，只是改成"说明它为什么没有"。
   原因见 app.js railRowEmpty 的注释 —— 静默丢行会让用户以为本来就只有两条。 */
.rv-row-empty .rv-track-empty{background:repeating-linear-gradient(45deg,#f4f5f7 0 6px,#e9ecf1 6px 12px);border-style:dashed}
.rv-row-empty .rv-val{font-weight:400;color:var(--muted)}
.rv-row-empty .rv-val em{font-style:normal;font-size:10.5px}
.rv-empty-hint{font-size:11.5px;color:var(--muted);background:#fafbfc;border:1px dashed var(--line);border-radius:8px;padding:10px 12px}

/* 图表空态 / 降级说明：用 DOM 而不是画在 canvas 上（画布 0 宽时画不出字，
   而"为什么空"恰恰要在那一刻说清楚） */
.chart-note{margin-top:8px;font-size:11.5px;line-height:1.6;color:#8a5a00;
  background:#fff8e1;border:1px solid #ffe1a0;border-radius:8px;padding:8px 11px}
/* 出现说明时要给折叠体留出高度，否则说明本身会被 max-height 裁掉 */
.chart-card.has-note{--chart-h:560px}
.chart-toggles{display:flex;gap:16px;font-size:11.5px;color:var(--ink-2);margin-bottom:8px;flex-wrap:wrap}
.chart-toggles label{display:flex;align-items:center;gap:5px;cursor:pointer;user-select:none}
.chart-toggles input{accent-color:var(--accent)}
.lg-bollu{background:#e91e63}.lg-bolld{background:#00acc1}.lg-rail{background:#ff9800}

/* 免责声明 */
.disclaimer{font-size:11.5px;color:var(--muted);line-height:1.75;background:#fafbfc;border:1px dashed var(--line);border-radius:10px;padding:12px 15px;margin-bottom:20px}
.disclaimer b{color:var(--ink-2)}

/* 监控清单来源标记 */
.src-badge{
  display:inline-block;margin-left:8px;padding:2px 9px;border-radius:20px;
  font-size:11px;font-weight:500;vertical-align:middle;line-height:1.6;
}
.src-badge.profile{background:#eef4ff;color:#2450a4;border:1px solid #d3e0f7}
.src-badge.generic{background:#fff6e8;color:#a86504;border:1px solid #f2ddb8}
.mon-now{font-size:12px;color:var(--muted);min-width:150px}
.mon-note{margin-top:4px;line-height:1.55;color:var(--ink-2);font-size:11.5px}
/* 监控清单是 7 列表格（维度 / 指标 / 窗口 / 利好 / 利空 / 状态 / 权重），
   手机上它的最小内容宽度必然超过屏宽。不给自己的横向滚动容器，
   它就会把整个文档撑宽 —— 表现为「页面能左右晃」，而且所有卡片都被拖着一起晃。
   实测修前 document.scrollWidth 515 vs 视口 393。 */
#monitorTableWrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* 清单项状态徽标 */
.st-badge{
  display:inline-block;padding:1px 8px;border-radius:6px;
  font-size:11.5px;font-weight:600;line-height:1.7;white-space:nowrap;
}
.st-badge.bull{background:var(--up-bg);color:var(--up);border:1px solid #f5cfcb}
.st-badge.bear{background:var(--down-bg);color:var(--down);border:1px solid #c9e8db}
.st-badge.neutral{background:#fff7e6;color:#b4740a;border:1px solid #f0dfb4}
.st-badge.muted{background:#f2f4f7;color:#6b7280;border:1px solid #e3e6eb}

/* 已触发的清单项：整行加重，一眼能看出哪几项在起作用 */
tr.mon-hit td{background:#fffdfa}
tr.mon-hit td:first-child{box-shadow:inset 3px 0 0 var(--up)}
tr.mon-hit:has(.st-badge.bear) td:first-child{box-shadow:inset 3px 0 0 var(--down)}

/* 清单结论行 */
.mon-sum{
  background:#fafbfc;border:1px solid var(--line);border-left:3px solid var(--up);
  border-radius:8px;padding:10px 14px;margin-bottom:12px;font-size:13px;line-height:1.7;
}
.mon-sum .mon-sub{color:var(--muted);font-size:12px;margin-left:6px}
.mon-sum .mon-gap{color:#a86504;font-size:12px;margin-top:4px}

/* 自动画像提示：必须醒目，不能让用户误以为是投研结论 */
.auto-note{
  background:#fff8ec;border:1px solid #f2ddb8;border-left:3px solid #d99a2b;
  border-radius:8px;padding:11px 15px;margin-bottom:12px;
  font-size:12.5px;line-height:1.75;color:#8a5b06;
}
.auto-note b{color:#7a4f04}

/* toast */
.toast{
  position:fixed;bottom:26px;left:50%;transform:translateX(-50%) translateY(20px);
  background:#15171c;color:#fff;padding:9px 18px;border-radius:9px;font-size:12.5px;
  opacity:0;pointer-events:none;transition:.25s;z-index:99;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

/* 移动端专用 / 桌面专用：靠 CSS 切显隐，JS 只渲染一份结构，避免按视口分支渲染 */
.m-only{display:none}

/* ==========================================================================
   方案 E · 顶部胶囊（切换）+ 内容横滑换股 + 底部全屏清单（管理）
   --------------------------------------------------------------------------
   职责分离：胶囊条只做「切换」，底部全屏清单只做「管理」（排序 / 搜索 / 删除 / 添加）。
   顺带修掉四个平台问题：
     ① 触屏删除按钮（横滑期误触 + 与手势打架）→ 删除收进全屏清单
     ② 100dvh（iOS 动态工具栏下 100vh 会算高，导致底部被裁）
     ③ 输入框字号 >=16px（否则 iOS 聚焦时整页放大）
     ④ 图表可折叠（K 线 380px 在手机上把详情顶到很远）
   另补 iPhone 底部安全区 env(safe-area-inset-bottom)。
   ========================================================================== */

/* ---------- 全局：新组件 ---------- */

/* 图表可折叠。
   展开高度按卡片用 --chart-h 声明：原型里写死 240px，但本项目 K 线画布高 380px，
   沿用 240 会把 K 线裁掉一截。
   默认态做成「CSS 优先」：桌面默认展开（JS 没跑完也不会闪一下空白），
   手机默认折叠（进页面就能看到详情正文，不被 380px 的 K 线挤下去）。
   ——折叠态用 .collapsed，展开态在手机上用 .open，两者由 JS 按视口宽度切换。 */
.chart-body{ max-height:var(--chart-h,240px); overflow:hidden; transition:max-height .26s ease; }
.chart-card.collapsed .chart-body{ max-height:0; }
/* 每张图的展开高度：分时画布 220px；K线画布 380px + 上方三个开关约 30px */
.chart-minute{ --chart-h:240px; }
.chart-kline{ --chart-h:430px; }
.chart-card .card-title{ display:flex; align-items:center; gap:10px; }
.chart-toggle{ margin-left:auto; display:inline-flex; align-items:center; gap:4px;
  border:1px solid var(--line); background:#fff; color:var(--muted);
  border-radius:99px; font-size:11.5px; padding:4px 11px; cursor:pointer;
  font-family:inherit; white-space:nowrap; }
.chart-toggle svg{ transition:transform .2s ease; }
/* 箭头方向跟随展开状态；两种形态的「展开」判定不同，所以各自放在对应断点里 */
@media (min-width:861px){
  .chart-card:not(.collapsed) .chart-toggle svg{ transform:rotate(180deg); }
}
@media (max-width:860px){
  .chart-body{ max-height:0; }
  .chart-card.open .chart-body{ max-height:var(--chart-h,240px); }
  .chart-card.open .chart-toggle svg{ transform:rotate(180deg); }
}

/* 胶囊条末尾的「清单」入口（移动端专用，桌面隐藏） */
.chip-all{ display:none; }

/* ---------- 底部全屏自选清单（管理态） ---------- */
.as-mask{ position:fixed; inset:0; background:rgba(16,24,40,.34); z-index:89;
  opacity:0; pointer-events:none; transition:opacity .26s ease; }
.as-mask.open{ opacity:1; pointer-events:auto; }

.as-panel{ position:fixed; left:0; right:0; bottom:0; z-index:90; background:#fff;
  height:92vh; height:92dvh; display:flex; flex-direction:column;
  border-radius:18px 18px 0 0; box-shadow:0 -10px 34px rgba(16,24,40,.18);
  transform:translateY(101%); transition:transform .26s ease; }
.as-panel.open{ transform:translateY(0); }

.as-grip{ flex:0 0 22px; height:22px; display:flex; align-items:center; justify-content:center; }
.as-grip i{ width:40px; height:4px; border-radius:99px; background:#d3d1c7; display:block; }

.as-head{ display:flex; align-items:center; gap:10px; padding:2px 14px 10px; }
.as-head h3{ margin:0; font-size:16px; }
.as-head .as-cnt{ font-size:11.5px; color:var(--muted); }
.as-x{ margin-left:auto; width:44px; height:44px; border:0; background:none; color:var(--muted);
  display:flex; align-items:center; justify-content:center; cursor:pointer; border-radius:10px; font:inherit; }
.as-x:active{ background:#f4f5f7; }

.as-tools{ padding:0 12px 8px; display:flex; flex-direction:column; gap:8px; }
.as-tools input{ width:100%; box-sizing:border-box; border:1px solid var(--line);
  border-radius:9px; padding:10px 12px; font-size:16px; background:#fbfbfc;
  color:var(--ink); outline:none; font-family:inherit; }
.as-tools input:focus{ border-color:#c9d4ee; }

.sorts{ display:flex; gap:6px; overflow-x:auto; padding-bottom:2px; -webkit-overflow-scrolling:touch; }
.sorts button{ flex:0 0 auto; border:1px solid var(--line); background:#fff; color:var(--muted);
  border-radius:99px; font-size:12px; padding:7px 13px; cursor:pointer; font-family:inherit; }
.sorts button.active{ background:var(--accent-bg); border-color:#d5ddf2; color:var(--accent); font-weight:600; }

.as-list{ flex:1; min-height:0; overflow:auto; padding:4px 12px 12px; -webkit-overflow-scrolling:touch; }
.as-empty{ text-align:center; color:var(--muted); font-size:12.5px; padding:34px 0; }
/* 按名称/拼音搜索时的提示行（手机端没有桌面那块搜索框，由这里接管） */
.as-note{ display:flex; align-items:center; gap:8px; font-size:12px; color:var(--muted); padding:0 2px 8px; }
.as-note button{ margin-left:auto; border:1px solid var(--line); background:#fff; color:var(--muted);
  border-radius:99px; padding:4px 10px; font-size:11.5px; cursor:pointer; font-family:inherit; }

.al-row{ display:flex; align-items:center; gap:10px; border:1px solid var(--line);
  border-radius:11px; padding:10px 11px; margin-bottom:8px; background:#fff; }
.al-row.active{ border-color:#d5ddf2; background:var(--accent-bg); }
.al-main{ flex:1; min-width:0; cursor:pointer; }
.al-t1{ display:flex; align-items:baseline; gap:8px; }
.al-nm{ font-weight:600; font-size:14.5px; }
.al-cd{ font-size:11.5px; color:var(--muted); font-family:ui-monospace,Menlo,monospace; }
.al-t2{ display:flex; align-items:center; flex-wrap:wrap; gap:8px; margin-top:5px; font-size:12.5px; }
.al-sc{ font-variant-numeric:tabular-nums; color:var(--muted); }
.al-chg{ font-variant-numeric:tabular-nums; font-weight:600; }
.al-chg.up{ color:var(--up); }
.al-chg.down{ color:var(--down); }
.al-side{ font-size:11px; font-weight:600; padding:1px 8px; border-radius:99px;
  background:#f4f5f7; color:var(--muted); }
.al-side.bull{ background:var(--up-bg); color:var(--up); }
.al-side.bear{ background:var(--down-bg); color:var(--down); }
.al-add{ flex:0 0 auto; border:1px solid #d5ddf2; background:var(--accent-bg); color:var(--accent);
  border-radius:9px; padding:8px 12px; font-size:12px; font-weight:600; cursor:pointer; font-family:inherit; }
.al-del{ flex:0 0 auto; width:44px; height:44px; border:1px solid var(--line); background:#fff;
  border-radius:10px; color:var(--muted); cursor:pointer;
  display:flex; align-items:center; justify-content:center; }
.al-del:active{ background:#fdf2f1; border-color:#f2c6c2; color:var(--down); }

.as-add{ display:flex; gap:8px; padding:10px 12px; border-top:1px solid var(--line-2);
  padding-bottom:calc(10px + env(safe-area-inset-bottom, 0px)); }
.as-add input{ flex:1; min-width:0; border:1px solid var(--line); border-radius:9px;
  padding:11px 12px; font-size:16px; background:#fbfbfc; color:var(--ink);
  outline:none; font-family:inherit; }

/* ---------- 移动端基础布局：侧栏 → 顶部吸顶胶囊条 ----------
   顺序是硬约束：这两段是「基础移动布局」，方案 E 的移动端覆盖块必须排在它们之后。
   同为 (max-width:860px) 且特异度相同时，CSS 按下标决胜 ——
   基础块里的 .wl-item{flex:0 0 132px} / .content{padding:12px 12px 48px}
   必须让位给方案 E 的 136px 胶囊与带安全区的内边距。顺序反了就会静默丢掉这些修正。 */
@media (max-width:860px){
  .topbar{position:static;height:auto;padding:8px 12px;gap:8px;flex-wrap:nowrap}
  .brand p{display:none}
  .brand h1{font-size:15px}
  .topbar-right{gap:8px;margin-left:auto;flex-wrap:nowrap}
  .clock span{font-size:13px}
  .switch span{font-size:11.5px}
  /* 原型用的是 .refresh-all 类，本项目是 #refreshAll 这个 id，两个都写上 */
  .refresh-all,#refreshAll{display:none}
  .btn{border-radius:9px;font-size:12px;padding:6px 10px}
  .content,.sidebar{min-width:0}
  /* .channel-grid 已从这条「一律一列」里摘出去：它现在按可用宽度自适应列数，
     横屏手机（852px）与平板（820px）能排满 3 列。留在这一组里会被
     !important 压死成一列 —— 那正是「右边大片留白」的来源。 */
  .grid-2,.plan-grid,.profile-grid{grid-template-columns:1fr !important}
  .sh-stats{grid-template-columns:repeat(2,1fr) !important;gap:8px 14px}
  .verdict-main{flex-direction:column;align-items:flex-start;gap:14px}
  /* 数值列 62px 装不下「带内中上位置」这类 6 字标签（会折成两行、很难看）。
     560~860px 这段（含 852px 横屏）横向宽度够，给到 84px。
     比这更窄的走下面 @media (max-width:560px) 的两段式。 */
  .rv-row{grid-template-columns:96px 1fr 84px;gap:8px}
  .wl-chg{flex:0 0 auto}
  .report-actions{flex-wrap:wrap;gap:6px}
}

@media (max-width:860px){
  .layout{display:block;height:auto;overflow:visible}
  .sidebar{width:auto;border-right:0;background:#fff;border-bottom:1px solid var(--line);
    position:sticky;top:0;z-index:40;display:block;padding:8px 10px 6px}
  .side-block{margin:0}
  .side-block.grow{margin:0;overflow:visible}
  .side-title{display:none}
  .add-block{display:none}
  #searchResults{display:none}
  .search-row{margin-bottom:0}
  .watchlist{flex-direction:row;overflow-x:auto;gap:8px;padding-bottom:2px}
  .wl-item{flex:0 0 132px;padding:7px 9px;border-left:0;border-radius:9px;
    border-bottom:2px solid transparent}
  .wl-item.active{border-bottom-color:var(--accent);background:var(--accent-bg);border-color:#e5e7eb}
  .wl-del{opacity:1;font-size:11px;border:1px solid var(--line);border-radius:5px;padding:0 5px}
  .wl-row2{justify-content:space-between;align-items:center}
  .content{overflow:visible;padding:12px 12px 48px}
}

/* ---------- 桌面（>=861px） ---------- */
@media (min-width:861px){
  /* 平台修复 ①：改用 100dvh，避免 iOS 动态工具栏下算高 */
  .layout{ height:calc(100vh - 60px); height:calc(100dvh - 60px); }
  /* 全屏清单是移动端的管理态；桌面沿用侧栏 hover 删除，固定层必须彻底隐藏 */
  .as-panel,.as-mask,.chip-all{ display:none !important; }
}

/* ---------- 移动端（<=860px）覆盖：方案 E 的核心几何 ----------
   必须排在「基础移动布局」两段之后（同为 max-width:860px，靠下标决胜）。 */
@media (max-width:860px){

  /* 平台修复 ②：输入框字号 >=16px，避免 iOS 聚焦时整页放大 */
  .search-row input{ font-size:16px; }
  /* 平台修复 ③：底部安全区（iPhone 手势条） */
  .content{ padding:12px 12px calc(46px + env(safe-area-inset-bottom, 0px)); }
  .watchlist{ padding-bottom:2px; }
  /* 平台修复 ④：触控目标不小于 44px */
  .btn{ min-height:44px; }
  .tab{ min-height:40px; padding:9px 12px; }
  .chip-all{ min-height:64px; }

  /* 胶囊 = 纯切换入口：加大、加高、显示评分（本产品核心信息） */
  .watchlist{ gap:9px; scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch; }
  /* 宽度必须显式钉死，不能只给 flex-basis。
     实测：只写 flex:0 0 136px 时，Safari 会按 .wl-item 的 min-width:auto
     （= 内容最小尺寸）把它撑到 163px —— flex-shrink 已是 0，压不回去，
     于是胶囊比设计宽 27px，一屏少显示近半只标的。宽度 + min-width:0 + max-width
     三者一起给，才真正等于「136px，且不许被内容左右」。 */
  .wl-item{ flex:0 0 136px; width:136px; min-width:0; max-width:136px;
    min-height:64px; padding:9px 11px; scroll-snap-align:start;
    display:flex; flex-direction:column; justify-content:center; gap:3px; cursor:pointer; }
  .wl-item.active{ border-color:#d5ddf2; background:var(--accent-bg); border-bottom-color:var(--accent); }
  .wl-row1,.wl-row2{ min-width:0; }
  .wl-row1{ gap:6px; }
  .wl-name{ font-size:13.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:1 1 auto; min-width:0; }
  .wl-chg{ font-size:12.5px; }
  .wl-row2{ justify-content:flex-start; gap:7px; margin-top:0; align-items:center; }
  .wl-code{ font-size:11px; }
  /* 把评分放回胶囊：只看一眼就能判断该不该点进去 */
  .wl-score{ display:inline-block; font-size:11px; color:var(--muted);
    background:#f4f5f7; border-radius:99px; padding:1px 7px; white-space:nowrap; }
  /* 关键改动：删除按钮不再放在胶囊上（触屏易误触 + 与横滑手势打架），
     删除统一收进「清单」管理态 */
  .wl-del{ display:none !important; }

  /* 「清单」固定在胶囊条右端：无论横滑到哪儿都点得到 */
  .chip-all{ flex:0 0 74px; position:sticky; right:0; z-index:2;
    border:1px solid #d5ddf2; background:var(--accent-bg);
    border-radius:11px; color:var(--accent); font-size:12px; font-weight:600; gap:2px;
    align-items:center; justify-content:center; cursor:pointer;
    box-shadow:-10px 0 10px -4px #fff, -5px 0 6px -2px #fff;
    display:flex; flex-direction:column; line-height:1.25; font-family:inherit; }

  /* 移动端专用显隐 */
  .m-only{ display:inline-block !important; }
  .d-only,.wl-q{ display:none !important; }
}

/* ---------- 图表卡片标题：窄屏不能被图例挤爆 ----------
   实测（iPhone 15 视口）：K 线卡片标题里「图表名 + 7 项图例 + 展开按钮」同处一行时，
   legend 的文本被 Flex 压到 min-content，出现「上/轨」「通/道」这样的竖排单字，
   标题被撑到四行，图表本体被推到屏幕之外 —— 看上去就像「这张图是空的」。
   手机端让图表名独占一行，图例另起一行并逐项不折行。 */
@media (max-width:860px){
  .chart-card .card-title{ row-gap:6px; }
  .chart-card .chart-name{ flex:1 1 100%; font-size:12.5px; min-width:0;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .chart-card .chart-legend{ flex:1 1 auto; min-width:0; gap:6px 10px; font-size:10.5px; }
  .chart-card .chart-toggle{ flex:0 0 auto; margin-left:auto; }
}

/* ---------- 轨道卡片：窄屏把「标签 + 数值」提到同一行，轨道条占满整宽 ----------
   三段式（标签 88px / 轨道 / 数值 62px）在 393px 竖屏下只给轨道留下 161px，
   刻度 31.85 / 33.21 / 34.57 挤成一团，而标签列白白吃掉左侧四分之一宽度。
   改成两行网格后轨道宽度约翻倍（331px），横向空间才真的被用上。 */
@media (max-width:560px){
  .rv-row{ grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:'label val' 'track track'; gap:2px 10px; align-items:end; }
  .rv-label{ grid-area:label; }
  .rv-row > div:nth-child(2){ grid-area:track; }
  .rv-val{ grid-area:val; text-align:right; }
}

/* ---------- 横屏（矮视口）刻意收紧纵向留白 ----------
   852×393 这类横屏视口高度只有 393px，而卡片此前高 652px —— 要滚近两屏才看得完。
   改成分栏后高度已明显下降，这里再把卡片内边距与行距收紧，尽量一屏读完。 */
@media (orientation:landscape) and (max-height:560px){
  .channel-card{ padding-top:11px; padding-bottom:11px; }
  .channel-card .card-title{ margin-bottom:7px; }
  .ch-zone-row{ margin-bottom:8px; }
  .channel-grid{ margin-bottom:9px; }
  .rail-viz{ gap:9px; padding:2px 2px 0; }
}
