/* ============================================================================
   TradingQuant · 共享 UI 层（设计令牌 + 通用组件）
   ============================================================================
   为什么要有这个文件:
   蓝图 §0 点名的前端隐患是「5 个互相独立的静态 HTML、无构建、**无组件层**」——
   每加一个页面就把配色/卡片/表格/徽标再抄一遍。这个文件就是那个缺失的层次:
   **令牌只定义一次, 组件只写一遍, 页面只放自己的结构。**

   用法: 页面里 `<link rel="stylesheet" href="/static/tq_ui.css">`, 然后直接用下面的类。
   没有构建步骤 —— 原生 CSS 变量 + 类名, 与"纯 Web、后期 Capacitor 包壳"的路线一致。

   ⚠️ 两条**产品约定**, 改动前先看 docs/reference_3commas.md §5.5:
     1. 主色是**金色**(--gold), 不是 3Commas 的青绿 —— 换掉品牌感就没了
     2. 涨跌是**红涨绿跌**(--up 红 / --down 绿), 与监控页 K 线一致; 3Commas 是绿涨, 不跟

   命名: 前缀 `tq-` 留给本文件自有的组件; 布局骨架类(.app/.side/.main/.topbar)不带前缀,
   因为它们是单例。
   ========================================================================== */

/* ---------------------------------------------------------------- 令牌 */
:root{
  /* ⭐ **侧栏宽 = 唯一出处**（2026-10-05）。在它之前这个 180 在 `.tq-side` 里写了两遍
     （`flex:0 0 180px` 与 `width:180px`），而**首屏遮罩也要知道它**——
     遮罩盖的是 `.tq-main` 那一块，不该盖侧栏（用户 2026-10-05 报「登录时整页黑屏、
     左侧功能栏被挡住看不见」）。
     ⚠️ 遮罩在 `_shell.html` 里读的是 `--tq-mask-left`（带兜底 `var(…,0px)`）：这张表万一没加载上，
         退回"整窗盖"（= 旧行为），**不会**留一条空带。
     ☠️ **2026-10-06 更正：这里曾经在抽屉态把 `--tq-side-w` 本身置 0 —— 那是错的**：
         它把**侧栏自己的宽度**也变成 0 ⇒ ① `transform:translateX(-100%)` 移一个 0 宽的盒子
         = **没移开**（实测只移了 −1px）② 0 宽的盒子里**文字溢出可见** ⇒ 手机上侧栏糊在页面上。
         ⇒ 拆成两个变量：**`--tq-side-w` = 布局宽度（永不变）** ·
            **`--tq-mask-left` = 遮罩要让开多少**（抽屉态才覆盖成 0）。 */
  --tq-side-w:180px;
  /*: 首屏遮罩的左边距。桌面 = 让开侧栏；抽屉态（≤1280px）覆盖成 0（整窗盖）。
      ⚠️ 默认值**引用** `--tq-side-w`，所以宽度仍然只有一处出处。 */
  --tq-mask-left:var(--tq-side-w);
  /* 底色与面 */
  --bg:#0e1116;          /* 页面底 */
  --panel:#161b24;       /* 卡片/侧栏 */
  --panel2:#1c2330;      /* 卡内分区、输入框、hover */
  --line:#252e3d;        /* 描边 */
  --line-soft:rgba(37,46,61,.6);

  /* 文字 */
  --text:#dfe6ee;
  --dim:#8a94a6;

  /* 主色(品牌) */
  --gold:#f0c75e;
  --gold-2:#d9a63a;                       /* 渐变收尾 */
  --gold-line:rgba(240,199,94,.22);
  --gold-soft:rgba(240,199,94,.08);
  --gold-fade:linear-gradient(90deg,rgba(240,199,94,.15),rgba(240,199,94,.02));

  /* 语义色 —— 注意是**红涨绿跌** */
  --up:#ff5252;
  --down:#3ddc84;
  --blue:#5aa9ff;
  --warn:#e0a35c;

  /* 形状 */
  --r:14px;              /* 卡片 */
  --r-sm:10px;           /* 按钮/输入 */
  --r-pill:20px;         /* 徽标 */
  --shadow:0 8px 30px rgba(0,0,0,.35);
  /* 开关宽度 —— ⭐ **一处定义**, `.tq-sw` 与需要"同宽占位"的页面(如
     `paper_manual.html` 的 `.pm-ghost-sw`)都取它。⚠️ 占位与开关各写一个数必然漂:
     那个页面为这类事栽过(2026-09-26 差 38px), 所以宽度不许在页面里再写一遍。 */
  --tq-sw-w:38px;

  /* 间距(8 的倍数为主, 便于对齐) */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:22px; --s6:30px;

  /* 字号 */
  --fs-xs:11.5px; --fs-sm:12.5px; --fs:13px; --fs-md:14px; --fs-lg:16px;
  --fs-hero:38px;

  --font:"Segoe UI","Microsoft YaHei",system-ui,sans-serif;
  --font-num:var(--font);   /* 数字用等宽数字特性即可, 见 .tq-num */
}

/* ---------------------------------------------------------------- 基础 */
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);font-family:var(--font);font-size:var(--fs-md)}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}
h1{font-size:20px;margin:0;font-weight:600;letter-spacing:.5px}
/* ⚠️ 滚动条的样式**搬去 `static/tq_scroll.js` 了**(2026-09-28) —— 那边**自注入**, 因为有的页面
   (旧一代的 `/dashboard` `/optimize`)**不加载本文件**, 写在这里它们就没有样式。
   ⇒ 滚动条 + "按住内容拖"两件事都在那个共享件里,**一处定义**。⛔ 别在这里再写一份。 */

/* 数字对齐: 表格与卡片里的数值务必加这个类, 否则字宽跳动很难读 */
.tq-num{font-variant-numeric:tabular-nums}
.tq-pos{color:var(--up)}      /* 红涨 */
.tq-neg{color:var(--down)}    /* 绿跌 */
.tq-dim{color:var(--dim)}

/* ---------------------------------------------------------------- 骨架 */
.tq-app{display:flex;min-height:100vh}
.tq-main{flex:1;min-width:0;display:flex;flex-direction:column}

/* 侧栏 —— ⭐ 宽度是**量出来的，不是估的**(用户 2026-09-26: "右边的空白区域有点多")。
   实测(真 Chrome 读 DOM, 把侧栏临时设成 `max-content`): **自然宽度 = 165px** ——
   卡住它的**不是导航项**(最宽 148px/英文)，而是品牌名「TradingQuant」那行(164px)。
   中文界面只要 160px。⇒ 取 **180px** = 自然宽 + 15px 余量。
   ⚠️ **别凭感觉再压**: 压到 165 以下，换台机器字体回退一变就折行; 也别随手调大(那正是本次的问题)。
   ⇒ 要改先按上面那个办法**重新量一次**。窄屏抽屉共用这个宽度(见下面 1280 断点)。 */
.tq-side{flex:0 0 var(--tq-side-w);width:var(--tq-side-w);background:var(--panel);
     border-right:1px solid var(--line);
     position:sticky;top:0;height:100vh;display:flex;flex-direction:column;padding:14px 0 10px;
     /* ☠️ **必须能滚**（2026-10-06 实测补的）：侧栏是**固定满高**的，
        导航项一多就装不下 ⇒ 装不下的那几项**永远够不着**（不是"看不见"，是没法滚到）。
        实测：375×667 的视口下内容高 **855**，`overflow` 是默认的 `visible` ⇒
        `设置`（以及加过一项之后的 `FAQ`）在折叠线以下且**滚不到**。
        ⚠️ 光靠"少加一项"治不了 —— 导航只会越加越多，这个洞下次还会咬。
        `overscroll-behavior:contain` 是防"滚到头之后把后面那一页也滚了"。 */
     overflow-y:auto;overscroll-behavior:contain}
.tq-brand{display:flex;align-items:center;gap:9px;padding:2px 16px 16px;font-weight:600;
     letter-spacing:.3px;color:var(--gold);font-size:15px}
.tq-brand .mark{width:22px;height:22px;border-radius:6px;flex:0 0 22px;
     background:linear-gradient(135deg,var(--gold),#c7912a);color:#151515;
     display:grid;place-items:center;font-size:12px;font-weight:800}
/* 分组标题 —— 现在是个 <button>(可以点: 打开该组第一页), 所以要重置按钮默认样式。
   ⚠️ 这条**不是**新增而是改既有规则, 安全: `.tq-grp` 只被外壳用(老首页不加载 tq_ui.css;
      2026-09-24 起第一屏就是外壳页, 所以它**现在真的会影响线上** —— 但仍然只影响侧栏)。 */
.tq-grp{display:block;width:100%;text-align:left;background:none;border:0;
     font-family:inherit;padding:12px 16px 6px;font-size:var(--fs-xs);
     color:var(--dim);letter-spacing:.8px;cursor:default}
.tq-grp.link{cursor:pointer}
.tq-grp.link:hover{color:var(--text)}
.tq-grp.on{color:var(--gold)}
.tq-nav{display:flex;flex-direction:column;gap:2px;padding:0 8px}
/* ⭐ **不画分组标题的那一组**(`grp.noLabel`, 见 `tq_shell.js` 的 NAV)补一点上边距 ——
   否则第一项会贴着品牌名(原先那点空隙有一半是标题的 `padding` 给的)。
   ⚠️ 这是**给那一组**的, 不是给"第一个 .tq-nav"的 —— 别改成 `:first-child` 之类的结构选择器。 */
.tq-nav.first-plain{margin-top:14px}
.tq-nav a{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--r-sm);
     font-size:13.5px;transition:.15s}
.tq-nav a svg{width:17px;height:17px;flex:0 0 17px;opacity:.75}
.tq-nav a:hover{background:var(--panel2)}
.tq-nav a.on{color:var(--gold);background:var(--gold-fade);box-shadow:inset 2px 0 0 var(--gold)}
.tq-nav a.on svg{opacity:1}
.tq-side .foot{margin-top:auto;padding:10px 16px 0;border-top:1px solid var(--line);
     display:flex;align-items:center;gap:8px;font-size:var(--fs-xs);color:var(--dim)}

/* 通栏公告 */
.tq-notice{background:linear-gradient(90deg,var(--gold),var(--gold-2));color:#151515;
     font-size:var(--fs-sm);padding:7px 16px;display:flex;align-items:center;
     justify-content:center;gap:8px}
.tq-notice a{text-decoration:underline;font-weight:600}
/* ⭐ **公告通栏**（2026-10-08 批 5）—— 上面那条金色通栏就是 `info` 语气；
   `warn` 换成**提醒色**（与涨跌无关，理由同下面 `.tq-authlost` 那条）。
   ⚠️ 与静态的 `body[data-notice]` 复用同一条通栏样式：它们是**同一个位置**的东西。 */
.tq-notice.warn{background:var(--warn,#e8a33d)}
.tq-notice b{font-weight:700;white-space:nowrap}
.tq-notice span.tq-notice-body{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
     max-width:52vw}
/* 「知道了」= 标已读（幂等）⇒ 下次不再弹。手机上没有 hover，所以它**常驻**（⛔ 不藏） */
.tq-notice .tq-notice-x{margin-left:auto;flex:0 0 auto;background:none;border:0;cursor:pointer;
     color:inherit;font:inherit;font-weight:600;text-decoration:underline;padding:0 2px}

/* ⚠️ **「登录已失效」常驻提示**（2026-10-05）—— 与上面那条通栏公告同一层、但**更该被看见**:
   它解释「为什么这一页的数字全是 —」, 并在原地给一个重新登录的入口。
   ⚠️ 配色用 `--warn`（**提醒色**, 与涨跌无关）—— 它既不是「成功」也不是「错误」,
      而是「你需要做一件事」; 哪天改涨跌配色, 这里**不该**跟着变。 */
.tq-authlost{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:10px 16px;font-size:var(--fs-sm);line-height:1.5;
  color:var(--warn,#e0a35c);background:rgba(224,163,92,.10);
  border-bottom:1px solid rgba(224,163,92,.32)}
.tq-authlost .tx{flex:1;min-width:0}
.tq-authlost .go{flex:none;cursor:pointer;font:inherit;font-size:var(--fs-sm);
  padding:6px 14px;border-radius:8px;
  color:var(--warn,#e0a35c);background:transparent;border:1px solid rgba(224,163,92,.45)}
.tq-authlost .go:hover{background:rgba(224,163,92,.14)}

/* 顶栏 */
.tq-topbar{display:flex;align-items:center;gap:12px;padding:16px var(--s5) 4px}
.tq-topbar .sp{flex:1}

/* 整宽页面容器(监控这类不分成两栏的页用) */
.tq-page{padding:var(--s4) var(--s5) var(--s6);display:flex;flex-direction:column;gap:var(--s3);
  /* ⭐ **把这个容器自己的左右内边距"告诉"共享的 tab 排**(`tq_monitor_tabs.js`)——
     它要用它**往两边外扩**, 好让那条分割线**前后占满**(用户 2026-10-01 在手动交易页也报了一次:
     监控页修了、这页没修, 因为它走的是 `.tq-page` 而不是 `.wrap`)。
     ⭐ 写在这儿 = **所有走 `.tq-page` 的页面一起生效**(策略/指标/总仪表盘/手动交易/设置/回测…),
     不必逐页抄一行。⛔ 共享件里不许写死 22px(那是把某一个页面的内边距抄进公共件)。 */
  --tq-gutter: var(--s5)}

/* ⭐ **手机上的页面左右留白 = 唯一出处**(用户 2026-10-01: 「监控页留白也改为 11,
   以后新页面都是一样统一」)⇒ 22px 的一半。**是"留白少一点", 不是"贴边"**。
   ⚠️ **所有骨架一起覆盖**(单栏/两栏/监控页那两套旧容器) —— 少一个就会出现
      "这页 11、那页 18", 而**没人说得出为什么**(本仓在"日期格式有 11 份"上栽过)。
   ⇒ **新页面不用写任何东西**: 只要用 `.tq-page` / `.tq-wrap` 就自动是这个值。
   ⚠️ **桌面一律不动** —— 22px 在宽屏上是合适的, 用户是在手机上提的。
   ☠️ **`--tq-gutter` 必须跟着一起改**: 它是"告诉共享的 tab 排这个容器的内边距是多少",
      让它**往两边外扩**画出那条占满的分割线。**只改 padding 不改它 ⇒ 线会往外多扩
      (22−11)=11px ⇒ 整页横向溢出、能左右拖** —— 两处其实说的是**同一个值**。
   ⚠️ 这条**必须排在所有既有媒体查询之后**(同断点下靠后的赢) —— 上面 443 行那条
      `.tq-wrap{padding:16px}` 已随之删除, 别再写回来。 */
@media (max-width:760px){
  .tq-page,.tq-wrap,.wrap,.wrap2{
    padding-left:calc(var(--s5)/2);padding-right:calc(var(--s5)/2);
    --tq-gutter:calc(var(--s5)/2)}
}

/* 产品/报价条 */
.tq-quote{display:flex;align-items:baseline;gap:var(--s4);flex-wrap:wrap;
     background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
     padding:var(--s3) var(--s4)}
.tq-quote .sym{font-size:17px;font-weight:700;color:var(--gold);letter-spacing:.5px}
.tq-quote .px{font-size:26px;font-weight:600;font-variant-numeric:tabular-nums}
.tq-quote .chg{font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
.tq-quote .kv{display:flex;gap:5px;font-size:var(--fs-sm);color:var(--dim);align-items:baseline}
.tq-quote .kv b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}
.tq-quote .sp{flex:1}
.tq-quote select{background:var(--panel2);border:1px solid var(--line);color:var(--text);
     border-radius:var(--r-sm);padding:6px 10px;font-family:inherit;font-size:var(--fs-sm)}

/* 两栏内容区 */
.tq-wrap{display:grid;grid-template-columns:minmax(270px,330px) 1fr;gap:var(--s4);
     padding:var(--s4) var(--s5) var(--s6);align-items:start}
.tq-promos{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4);padding:var(--s4) var(--s5) 0}

/* ⚠️ grid/flex 子项默认 min-width:auto —— 内容(尤其宽表格)的 min-content 宽度会把
   轨道**撑出容器**, 表现为**整页**横向滚动条, 而不是让内部滚动条生效。必须显式归零。
   这是本项目加宽表格时最容易踩的一个坑, 所以放在共享层而不是各页面各写一遍。 */
.tq-wrap > *, .tq-promos > *{min-width:0}

/* ☠️ **`margin:0 auto` 的容器放进 flex 主轴列 = 整页被内容撑破** —— 2026-09-16 实测:
   「监控记录」那张 11 列表把**整页**撑变形(手机上右侧被切、能左右拖)。

   量出来的证据(临时探针页, iframe 390px):
       viewport clientWidth = 380  但  documentElement.scrollWidth = 621
       .wrap w=621 ← .tq-main(flex 列) 的子项
       而那张 table w=583 **小于** 它的滚动容器 .tqrec-wrap w=585 ⇒ **表格没溢出**

   根因: `.wrap{max-width:…; margin:0 auto}` —— **横向 `auto` 边距会取消 flex 的 `stretch`**
   ⇒ `.wrap` 不再被拉成容器宽, 改成按**内容**定尺寸(fit-content) ⇒ 它的 min-content 就是
   里面那张宽表的 min-content ⇒ 621。
   ⛔ **不是 `min-width:auto` 的锅**(我第一版就是这么误诊的, 还写了条 `.tq-main > *{min-width:0}`,
      那是**空转** —— 在**列**方向容器里, 交叉轴的 `min-width:auto` 本来就等于 0)。
   ⛔ 也不是"给表格容器加 `overflow:auto`"能治的 —— 那只管**自己**, 管不了祖先的**尺寸来源**。

   ⇒ 修法: 在**新外壳里**把内容容器的宽度钉成 100%。
   ⚠️ 只加在 `.tq-main > .wrap` 上, **别动 `.wrap` 自己那条 `margin:0 auto`** ——
      没外壳时 `.wrap` 是普通块, 那条 `auto` 是用来**居中**的, 动它会跑偏。
   ⭐ **2026-09-24 起这是生产依赖, 不再是过渡兜底**: 监控页(`static/monitor.html`,
   `/app/monitor`)整页用的是从老首页带来的 `.wrap`, 而它**住在外壳里** ⇒ 少了这条,
   手机上那张 11 列的宽表会把整页撑破(见上面那段实测)。⛔ 别删。 */
.tq-main > .wrap{width:100%}

/* --------------------------------------------- 兼容旧类名(迁移期用)
   从老首页原样搬过来的功能块(周期选择/指标开关/搜索产品/提醒记录)内部用的是
   老类名。**不给它们各写一套样式**, 而是让老类名映射到新设计系统 —— 这样搬来的模块
   自动跟上新皮肤, 且将来它们内部换类名时只需删掉这一段。
   迁移完成后, 这一节应该清空。 */
.shbtn{background:var(--panel2);border:1px solid var(--line);color:var(--text);
       border-radius:var(--r-sm);padding:6px 12px;cursor:pointer;font-family:inherit;
       font-size:var(--fs-sm);transition:.15s}
.shbtn:hover{border-color:#3a466a}
.shbtn[disabled]{opacity:.45;cursor:not-allowed;filter:none}
.dim{color:var(--dim)}

/* ---------------------------------------------------------------- 组件 */

/* 卡片 */
.tq-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r)}
.tq-card > h2{font-size:var(--fs);margin:0;padding:14px 16px 10px;font-weight:600}

/* 按钮 */
.tq-btn{background:var(--panel);border:1px solid var(--line);color:var(--text);
     border-radius:var(--r-sm);padding:7px 12px;font-size:var(--fs-sm);
     display:inline-flex;align-items:center;gap:7px}
.tq-btn:hover{border-color:#3a466a}
.tq-btn-gold{background:linear-gradient(135deg,var(--gold),var(--gold-2));color:#151515;
     border:0;border-radius:var(--r-sm);padding:10px 16px;font-weight:600;
     font-size:var(--fs);white-space:nowrap}
.tq-btn-gold:hover{filter:brightness(1.06)}
/* ⭐ **2026-10-03**: 置灰态以前**没有样式** ⇒ 一颗金色的按钮看着能按、按下去没反应
   (本仓把"点了没反应"当缺陷)。回测交易页的「开始回测」现在**默认就是置灰的**
   (策略未选, 用户 2026-10-03 要求进页面时策略是"未选") ⇒ 再不画出来就天天看得见。
   ⚠️ 与 `.shbtn[disabled]`(上面那条)同一档观感: 变淡 + 光标说不能点 + 去掉悬停高亮。 */
.tq-btn-gold[disabled],.tq-btn-mini[disabled],.tq-btn[disabled]{
     opacity:.45;cursor:not-allowed;filter:none}
.tq-btn-mini{background:var(--panel2);border:1px solid var(--line);color:var(--text);
     border-radius:8px;padding:5px 10px;font-size:var(--fs-sm)}
.tq-btn-mini:hover{border-color:var(--gold);color:var(--gold)}

/* 状态点 */
.tq-dot{width:7px;height:7px;border-radius:50%;background:var(--down);
     box-shadow:0 0 0 3px rgba(61,220,132,.16)}
.tq-dot.warn{background:var(--warn);box-shadow:0 0 0 3px rgba(224,163,92,.16)}
.tq-dot.off{background:var(--dim);box-shadow:none}

/* 头像 */
.tq-ava{width:30px;height:30px;border-radius:50%;
     background:linear-gradient(135deg,var(--gold),#c7912a);color:#151515;
     display:grid;place-items:center;font-weight:700;font-size:var(--fs)}

/* 引导卡 */
.tq-promo{background:linear-gradient(135deg,#1b2231,#141922);border:1px solid var(--line);
     border-radius:var(--r);padding:18px;display:flex;align-items:center;gap:var(--s4);
     overflow:hidden;position:relative}
.tq-promo::after{content:"";position:absolute;right:-40px;top:-40px;width:150px;height:150px;
     border-radius:50%;background:radial-gradient(circle,var(--gold-soft),transparent 70%)}
.tq-promo .tx{flex:1;min-width:0}
.tq-promo .tt{font-size:var(--fs-lg);font-weight:600;margin-bottom:6px}
.tq-promo .ds{font-size:var(--fs-sm);color:var(--dim);line-height:1.6}

/* 大数卡(总权益/关键指标) */
.tq-stat{margin:var(--s4) var(--s4) 0;padding:var(--s4);border-radius:var(--r);
     border:1px solid var(--gold-line);
     background:linear-gradient(150deg,rgba(240,199,94,.20),rgba(240,199,94,.05) 52%,transparent)}
.tq-stat .hd{display:flex;align-items:center;color:var(--dim);font-size:var(--fs-sm)}
.tq-stat .hd .sp{flex:1}
.tq-hero{font-size:var(--fs-hero);font-weight:300;letter-spacing:-1px;margin:8px 0 2px;
     font-variant-numeric:tabular-nums}
.tq-stat .sub{display:flex;gap:14px;font-size:var(--fs-sm);color:var(--dim);margin-top:8px;flex-wrap:wrap}
.tq-stat .sub b{color:var(--text);font-weight:600}

/* KPI 磁贴行 —— 一排关键数字。窄屏自动折行 */
.tq-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
     gap:var(--s3);padding:var(--s3) var(--s4)}
.tq-kpi{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r-sm);
     padding:11px 13px}
.tq-kpi .k{color:var(--dim);font-size:var(--fs-xs);letter-spacing:.3px}
.tq-kpi .v{font-size:21px;font-weight:500;margin-top:5px;font-variant-numeric:tabular-nums}
.tq-kpi .d{font-size:var(--fs-xs);color:var(--dim);margin-top:3px}
/* ⭐ 子行也吃涨跌色(用户 2026-09-24)。规则**只能写在这里**: `.tq-kpi .d` 是 (0,2,0),
   子行上单挂一个 `.tq-pos` 是 (0,1,0) —— **压不过**, 表现是"代码看着上了色、屏幕上一片灰"。 */
.tq-kpi .d.tq-pos{color:var(--up)}
.tq-kpi .d.tq-neg{color:var(--down)}
/* ⭐ 数字后面那个百分比要**跟着数字上色**（用户 2026-09-26 看图指出「百分比没有上色」）。
   ☠️ 为什么必须写在这里: `.tq-tfs` 自带 `color:var(--dim)`（0,1,0）, 而涨跌色挂在**父级**
      `.tq-kpi .v` 上 ⇒ 子 span 照旧是灰的; 在页面里给 span 单挂一个 `.tq-pos` 是 (0,1,0),
      **同分看先后** ⇒ 多半还是灰的(与上面 `.tq-kpi .d` 那条是同一个坑)。
   ⚠️ 只钉 `.tq-kpi .v` 里面的那一个（0,3,0）, **不动 `.tq-tfs` 本体** —— 它在优化记录页的
      表格、页脚是通用的"小灰字", 染色会把那些地方一起改掉。 */
.tq-kpi .v .tq-tfs{color:inherit}

/* 图表占位/容器 —— 高度由使用方给, 这里只管边框与内边距 */
.tq-chart{border-top:1px solid var(--line);padding:var(--s3) var(--s4)}
.tq-chart .cap{color:var(--dim);font-size:var(--fs-xs);margin-top:6px}

/* 设置项的一行(标签 + 控件), 窄屏折行 */
.tq-form{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s4);padding:var(--s3) var(--s4);align-items:center}
.tq-form label{display:flex;align-items:center;gap:7px;color:var(--dim);font-size:var(--fs-sm)}
.tq-form input[type=text],.tq-form input[type=number],.tq-form select{
     background:var(--panel2);border:1px solid var(--line);color:var(--text);
     border-radius:9px;padding:7px 11px;font-family:inherit;font-size:var(--fs-sm)}
.tq-form input:focus,.tq-form select:focus{outline:none;border-color:var(--gold)}
.tq-chk{accent-color:var(--gold)}
/* ⭐ **表单行尾的图标按钮**(＋ 加一条 / － 删一条) —— 2026-09-29 从交易策略页抽上来,
   因为「创建指标组合」也要用同一套(用户那天要求两处版式一致)。
   ⚠️ 图标义挂 `title`; 认按钮**必须按类名**(`.tq-add`/`.tq-del`), **不许按文字** ——
      图标化之后文字是 `＋`/`－`, 按文字找会静默找不到(策略页改这一版时踩过:
      "只剩一条不许删"那条判断因此失效)。 */
.tq-ico{min-width:30px;padding:5px 7px;line-height:1;font-size:13px}
.tq-rowbtns{display:inline-flex;gap:6px;flex:1;justify-content:flex-end}
/* ⭐ **开关**(toggle) —— 全站**唯一一份**(2026-09-29 从 `paper_manual.html` 的 `.pm-sw`
   搬上来: 那里原有全仓唯一一份实现, 而交易策略页也要用 ⇒ 抄第二份必然漂)。

   用法: `<label class="tq-sw"><input type="checkbox"><i></i></label>`
   ⚠️ `[hidden]` 要显式 `display:none` —— 本文件里 `display:flex` 一类的规则会盖掉
      UA 自带的 `[hidden]`(本仓栽过一次, 记在 `paper_manual.html` 那条教训里)。
   ⚠️ 承载它的行若用 `label` 做文字标签, 选择器必须写 `:not(.tq-sw)` —— 开关本身也是
      `<label>`, 不加这条会被当文字标签撑宽(`paper_manual.html` 为这个栽过一次)。 */
.tq-sw{position:relative;flex:none;display:inline-block;width:var(--tq-sw-w,38px);height:22px;
  border-radius:999px;background:var(--panel2);border:1px solid var(--line);cursor:pointer}
.tq-sw input{position:absolute;opacity:0;width:0;height:0}
.tq-sw i{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;
  background:var(--dim);transition:.15s}
.tq-sw input:checked + i{left:18px;background:var(--gold)}
.tq-sw[hidden]{display:none}
.tq-form .wide{flex:1;min-width:220px}
.tq-form .wide input{width:100%}
.tq-hint{color:var(--dim);font-size:var(--fs-sm);padding:0 var(--s4) var(--s3);line-height:1.6}

/* 键值对列表(小表格, 无竖线) */
.tq-kv{display:grid;grid-template-columns:1fr auto;gap:6px 12px;padding:14px 16px;
     font-size:var(--fs-sm)}
.tq-kv .k{color:var(--dim)}
.tq-kv .v{text-align:right;font-variant-numeric:tabular-nums}
.tq-kv.flush{padding-left:0;padding-right:0}

/* 标签页 */
.tq-tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);padding:0 10px}
.tq-tabs button{background:none;border:0;border-bottom:2px solid transparent;color:var(--dim);
     padding:11px 12px;font-size:var(--fs);margin-bottom:-1px}
.tq-tabs button.on{color:var(--gold);border-bottom-color:var(--gold)}
.tq-tabs button:hover{color:var(--text)}
.tq-tabs.sm button{padding:9px 11px;font-size:var(--fs-sm)}

/* 筛选条 */
.tq-filters{display:flex;gap:10px;padding:14px 16px;flex-wrap:wrap;align-items:center}
/* ⭐ 「订单历史」筛选行**右端**那个时间段(`tq_paper_manage.js` 建的)靠这条隔板推到右边。
   ⛔ 不用 `margin-left:auto`: 有 auto 边距的 flex 子项**不再被拉伸** ⇒ 容器会按内容定尺寸
      (本仓有成文教训 + 守卫 `test_page_skeleton.py`)。 */
.tq-filters .sp{flex:1}
.tq-sel{background:var(--panel2);border:1px solid var(--line);color:var(--text);
     border-radius:9px;padding:7px 28px 7px 11px;font-size:var(--fs-sm);appearance:none;
     background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),
                      linear-gradient(135deg,var(--dim) 50%,transparent 50%);
     background-position:calc(100% - 15px) 15px,calc(100% - 11px) 15px;
     background-size:4px 4px,4px 4px;background-repeat:no-repeat}
.tq-inp{background:var(--panel2);border:1px solid var(--line);color:var(--text);
     border-radius:9px;padding:7px 11px;font-size:var(--fs-sm)}
.tq-inp:focus{outline:none;border-color:var(--gold)}

/* 数据表
   ⚠️ 窄屏必须用 .tq-table-wrap 包一层 —— 表头 white-space:nowrap, 6 列在手机上
   最小宽度远超屏宽, 不包会把**整页**撑出横向滚动条(而不是只滚表格)。 */
.tq-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.tq-table{width:100%;border-collapse:collapse;font-size:var(--fs)}
.tq-table thead th{text-align:left;color:var(--dim);font-weight:500;font-size:var(--fs-xs);
     letter-spacing:.4px;padding:9px 14px;border-bottom:1px solid var(--line);white-space:nowrap}
.tq-table tbody td{padding:12px 14px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
.tq-table tbody tr:hover{background:var(--panel2)}
.tq-table tbody tr:last-child td{border-bottom:0}
.tq-table .r{text-align:right}

/* 徽标 */
.tq-bdg{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-xs);padding:3px 9px;
     border-radius:var(--r-pill);border:1px solid var(--line);color:var(--dim);white-space:nowrap}
.tq-bdg.gold{color:var(--gold);border-color:rgba(240,199,94,.35);background:var(--gold-soft)}
.tq-bdg.up{color:var(--up);border-color:rgba(255,82,82,.3);background:rgba(255,82,82,.08)}
.tq-bdg.down{color:var(--down);border-color:rgba(61,220,132,.3);background:rgba(61,220,132,.08)}
.tq-bdg.warn{color:var(--warn);border-color:rgba(224,163,92,.35);background:rgba(224,163,92,.08)}
.tq-bdg.blue{color:var(--blue);border-color:rgba(90,169,255,.3);background:rgba(90,169,255,.08)}

/* 小字辅助 */
.tq-tfs{color:var(--dim);font-size:var(--fs-sm);letter-spacing:.3px}

/* 空状态 */
/* ⭐ 用户 2026-09-29：「当列表是空的时候，都改为图2的空白高度……改善空列表填数时突然变大的不适感」。
   ⚠️ **高度在这里定死（一处）** —— 只有标题行时是 131px、带提示行时是 157px，
      差 21px ⇒ 光统一"用哪个类"还不够，要连"一行还是两行"的差也抹平。
      `min-height` + 居中布局 ⇒ 两种内容都占**同一个高度**，列表填上数据时不会突然变大。
   ⛔ 别再给某处单独写高度（那就是把这条规则又抄散了）。 */
.tq-empty{padding:20px 20px;min-height:157px;text-align:center;color:var(--dim);
  display:flex;flex-direction:column;align-items:center;justify-content:center}
.tq-empty svg{opacity:.5}
.tq-empty .it{font-size:15px;color:var(--text);margin:0 0 6px}
.tq-empty .is{font-size:var(--fs-sm);line-height:1.7}

/* ⭐ **K 线卡片的「指标监控」徽标行**（用户 2026-09-29 定版）——
   ⚠️ **放这儿而不是 `tq_kline.js`**：那支文件是"涨跌红绿"的主场，而本行里那对
      绿勾/红叉是**成功与错误**语义（不是涨跌）⇒ 必须是**字面值**，否则用户一翻配色，
      「成立」的勾会变成红的（那就成了"改 A 坏 B"）。
      `test_time_display_is_shared::test_up_down_colours_come_from_one_place` 扫的是
      `.js`/`.html` 两处**字面值**，它们放在**样式表**里才是对的位置（与 `--up/--down`
      自己一样）。同一条理由见 `tq_notice.js` 那条白名单说明。 */
/* ⭐ 2026-09-29 用户定版：这一行**字号提到 13px（与卡片头的「1分钟」同大）**、文字**蓝色**、
   触发状态**用图标**（绿勾 ✓ / 红叉 ✗）而不是文字，鼠标悬停给「触发 / 未触发」。
   ⚠️ 状态色**写字面值，不跟涨跌配色翻** —— 勾/叉说的是"成立没成立"，不是涨跌
      （同 tq_boot.js 里那条"成功绿/报错红不跟着翻"的规矩）。
   ☠️ **本段在模板字符串里 —— 注释里绝不许出现反引号**（会提前截断模板串，整页崩）。
      2026-09-29 我就是这么写坏的，被 test_chart_smoke 当场逮住（同本文件上面那段的老教训）。 */
.monrow{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin:2px 0 6px;min-height:19px;
  font-size:13px}
.monrow .monlb{color:var(--dim,#8a94a6);font-size:13px}
.monbdg{font-size:13px;padding:2px 8px;border-radius:999px;border:1px solid var(--line,#252e3d);
  display:inline-flex;align-items:center;gap:6px;color:var(--blue,#5aa9ff);
  white-space:nowrap;background:var(--panel2,#1c2330)}
/* ⚠️ 成立/不成立**不再靠底色区分**（那是"文字说状态"时代的做法）——状态由右面那颗勾/叉说，
   文字一律蓝（用户 2026-09-29：「颜色变蓝」）。 */
.monbdg .st{font-size:13px;line-height:1;font-weight:700}
.monbdg .st.ok{color:#3ddc84}
.monbdg .st.no{color:#ff5252}
/* ⭐ **三态里的"灰"**(用户 2026-10-03): 到过、现在落回去了 —— 灰勾 + 整颗淡一点。
   ⚠️ 灰的是"**已失效**"(那个价位已经回落下去了), 不是"未知" —— 别拿它去表达取数失败。
   ⚠️ 徽标现在是**可点的**(点一下 = 我知道了 ⇒ 回红 ✗), 所以要 pointer 光标。 */
.monbdg{cursor:pointer}
.monbdg.seen{opacity:.72}
.monbdg .st.seen{color:var(--dim,#8a94a6)}
/* ⭐ **鼠标移入胶囊 ⇒ 右上角显示删除按钮**(用户 2026-10-03)。
   ⚠️ `.monbdg` 要 `position:relative` 才能让那个 ✕ 贴着**它自己**的右上角
      (它不是行里的一个独立元素, 是**骑在胶囊角上**的)。
   ⚠️ 按钮**一直在 DOM 里**, 只是 `display:none` —— 别改成 hover 时才创建节点:
      那样每次进出都动 DOM, 而且**会吃掉正落在它上面的那一下点击**。
   ⚠️ 红用 `--bad`(**错误色**, 不跟涨跌配色走 —— 删掉是"错误/危险"语义, 不是"跌")。 */
.monbdg{position:relative}
.monbdg .mx{position:absolute;right:-7px;top:-7px;width:15px;height:15px;padding:0;
  border-radius:50%;border:1px solid var(--line,#252e3d);background:var(--panel,#161b24);
  color:var(--dim,#8a94a6);font-size:9px;line-height:1;font-family:inherit;
  display:none;align-items:center;justify-content:center;cursor:pointer}
.monbdg:hover .mx{display:flex}
.monbdg .mx:hover{color:var(--bad,#ff5252);border-color:var(--bad,#ff5252)}
/* ⚠️ **触摸屏没有 hover**（`hover:none`）⇒ 那里**常显**那个 ✕,
   否则手机上永远够不到它（点胶囊又只做"刷新状态"）。
   ⛔ 别把这条删掉当成"多余" —— 它是手机端唯一的移除入口。 */
@media (hover:none){ .monbdg .mx{display:flex} }
.monnone{font-size:13px;color:var(--dim,#8a94a6);opacity:.7}

/* 移动端汉堡 + 遮罩 */
.tq-burger{display:none;background:var(--panel);border:1px solid var(--line);color:var(--text);
     border-radius:var(--r-sm);padding:7px 10px}
.tq-scrim{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:40}

/* ---------------------------------------------------------------- 响应式
   断点取 1280px —— 与 3Commas 一致(docs/reference_3commas.md §5) */
@media (max-width:1280px){
  /* ⭐ 抽屉态: 侧栏**移出文档流**（fixed + translateX(-100%)，在屏幕外）⇒ `.tq-main` 占满全宽
     ⇒ 首屏遮罩**本来就该整窗盖**。所以这里**只覆盖遮罩那个变量**（`_shell.html` 读它）。
     ☠️ **⛔ 不要在这里动 `--tq-side-w`** —— 它同时也是**侧栏自己的宽度**，置 0 会让
        `translateX(-100%)` 移不动、且文字溢出（2026-10-06 真机报的"左侧功能栏崩了"就是这个）。 */
  :root{--tq-mask-left:0px}
  .tq-side{position:fixed;z-index:50;left:0;top:0;transform:translateX(-100%);
       transition:transform .18s ease}
  .tq-side.open{transform:none;box-shadow:0 0 40px rgba(0,0,0,.5)}
  .tq-scrim.show{display:block}
  .tq-burger{display:flex}
  .tq-wrap{grid-template-columns:1fr}
}
@media (max-width:760px){
  :root{--fs-hero:30px}
  .tq-promos{grid-template-columns:1fr}
  /* 顶栏: 不换行会在手机上把整页撑宽(标题+四个控件+头像)
     —— 允许折行, 并把内边距收窄 */
  .tq-topbar{flex-wrap:wrap;gap:8px;padding:12px 16px 2px}
  .tq-topbar h1{font-size:18px}
  /* ⭐ 头像**永远贴最右**(2026-09-16 用户实测报的)。
     ⚠️ 折行之后头像会被挤到第二行**最左**, 而用户菜单是 `.tq-menu{right:0}` **相对它**定位的
        ⇒ 菜单整个往左展开, 被屏幕左边缘切掉(截图见该次反馈: 邮箱/菜单项只露出右半截)。
     `margin-left:auto` 把头像推到**它所在那一行的最右** ⇒ 菜单也回到屏幕里。
     ⚠️ 只在窄屏加 —— 宽屏由 `.sp{flex:1}` 顶着, 不会折行; 那儿再写一条是多余的第二份机制。 */
  .tq-user{margin-left:auto}
  /* ⚠️ 这里原来有一条 `.tq-wrap{padding-left/right:16px}` —— 2026-10-01 删掉:
     手机上所有骨架的左右留白现在**统一**由上面那条 `.tq-page,.tq-wrap,.wrap,.wrap2`
     的媒体规则给(同一个值), 留着它就是**第二个出处**(而且因为它靠后还会赢)。 */
  .tq-filters{padding:12px 16px}
  /* 引导卡: 按钮 white-space:nowrap 撑不回去, 窄屏改成竖排 */
  .tq-promo{flex-direction:column;align-items:stretch;gap:12px}
  .tq-promo .tq-btn-gold{text-align:center}
  /* 大数卡在窄屏少占一点边距 */
  .tq-stat{margin:16px 16px 0}
}

/* ============================================================================
   外壳组件（2026-09-14 批）—— **追加区**
   ============================================================================
   改动纪律: 本批只**新增**, 上面既有规则与令牌值**一字未动**。
   理由: 那时 tq_ui.css 与老首页的内联副本并存(后者不加载本文件),
        此时改令牌必然让两处不一致。⚠️ **2026-09-24 老首页已退役** ⇒
        这条限制**解除了**(现在加载旧副本的只剩监控页那一段, 且它加载 tq_ui.css)。

   z-index 层级表(**别再各写各的**, 冲突过一次: 提示被弹窗盖住):
     40  .tq-scrim      移动端抽屉遮罩
     45  .tq-menu       顶栏用户菜单
     46  .tq-live-tip  顶栏「实时」Tips 浮层(2026-09-16 加) —— 高于用户菜单,
                       但**低于**移动端抽屉: 抽屉拉出来时该盖住它
     50  .tq-side       移动端抽屉本身
     60  .tq-modal      登录/注册弹窗
     80  .tq-toast-wrap 提示 —— 必须最高, 否则弹窗/抽屉一开就看不见提示
   ========================================================================== */

/* 危险/告警语义 —— ⚠️ 当前与 --up(涨=红)**同值**, 但语义无关:
   涨跌说的是行情, 这里说的是"出错了"。将来若要分离只改这一行;
   用 --up 表达告警的地方都是错的(会让人以为跟涨跌有关)。 */
:root{ --bad:#ff5252 }

/* 模态框 */
.tq-modal{display:none;position:fixed;inset:0;z-index:60;background:rgba(4,6,10,.72);
     align-items:center;justify-content:center;padding:16px}
.tq-modal.on{display:flex}
.tq-modal .box{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
     width:380px;max-width:100%;max-height:90vh;overflow:auto;padding:20px;position:relative}
.tq-modal .box h3{margin:0 0 16px;font-size:var(--fs-lg);color:var(--gold)}
.tq-modal .close{position:absolute;right:10px;top:10px;background:none;border:0;
     color:var(--dim);font-size:18px;line-height:1;padding:4px 6px}
.tq-modal .close:hover{color:var(--text)}
.tq-modal .ft{display:flex;gap:10px;justify-content:flex-end;margin-top:18px}
/* ⚠️ 手机上弹窗**顶部对齐** —— 默认是垂直居中, 而**软键盘弹起来会盖住下半截**:
   输入框和按钮正好在下面 ⇒ 用户报「显示不全, 没法输入账号密码」(2026-09-16)。
   顶到上面去, 键盘就压不到它; 高度再留出 24px, 免得顶到屏幕外。 */
@media (max-width:760px){
  .tq-modal{align-items:flex-start;padding:12px}
  .tq-modal .box{max-height:calc(100vh - 24px)}
}

/* 弹窗里的竖排字段 —— .tq-inp 是筛选条的固定宽度, 这里要占满 */
.tq-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}
.tq-field label{color:var(--dim);font-size:var(--fs-sm)}
.tq-field .tq-inp{width:100%;box-sizing:border-box}

/* 行内提示条。**内容为空时自动消失** —— 用 :empty 而不是类切换:
   少一个状态, 就少一处"忘了同步"的地方(把 textContent 设成 '' 即隐藏)。 */
.tq-alert{border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;
     font-size:var(--fs-sm);line-height:1.6;margin:8px 0}
.tq-alert:empty{display:none}
/* ⚠️ .ok 用绿 = --down(跌)。这是"成功"的通用约定与"绿跌"的碰撞, 只在**非行情**语境用 */
.tq-alert.ok{color:var(--down);border-color:rgba(61,220,132,.35);background:rgba(61,220,132,.08)}
.tq-alert.warn{color:var(--warn);border-color:rgba(224,163,92,.35);background:rgba(224,163,92,.08)}
.tq-alert.bad{color:var(--bad);border-color:rgba(255,82,82,.35);background:rgba(255,82,82,.08)}
.tq-alert.info{color:var(--blue);border-color:rgba(90,169,255,.3);background:rgba(90,169,255,.08)}

/* 提醒状态 —— 「一次提醒 × N 个通道 × 各自结果」里**结果那一格**。
   ⚠️ 用户 2026-09-16 定: 结果**不写文字**, 成功=绿勾 ✗失败=红叉; **通道名保留**
      (不写就看不出是哪个通道挂了)。「已发送」也按**成功**算 —— 只留两态。
   ⚠️ **两处复用**(总仪表盘的警报记录 + 实盘监控▸仪表盘的监控记录) ⇒ 放共享样式。
      各页再写一份的话, 用户改口时就会只改一处(本仓对"两份实现"有成文教训)。
   ⚠️ 绿用 `--down`(跌)、红用 `--bad` —— 与上面 `.tq-alert.ok` 同一条理由:
      这是"成功/失败"的通用约定与"红涨绿跌"的碰撞, 只在**非行情**语境用。
   ⚠️ 标签之间**不要留空白**(JS 里 join('') 或 HTML 里挨着写) —— 一换行就会多出一个
      匿名文本节点, 通道之间凭空多 4px, 看起来像间距写歪了。 */
.tq-ch{display:inline-flex;align-items:baseline;gap:4px;font-size:var(--fs-xs);
     color:var(--dim);margin:1px 10px 1px 0;white-space:nowrap}
.tq-ch b{font-weight:600;color:var(--text)}
.tq-ch i{font-style:normal;font-weight:700}
.tq-ch.ok i{color:var(--down)}
.tq-ch.bad i{color:var(--bad)}

/* 缺 tq_auth.js 时的红条 —— 贴边通栏 */
#tqMissing{margin:0;border-radius:0;border-left:0;border-right:0}

/* 提示(toast) —— z-index 见文件头层级表 */
.tq-toast-wrap{position:fixed;right:16px;bottom:16px;z-index:80;display:flex;
     flex-direction:column;gap:8px;align-items:flex-end;pointer-events:none}
.tq-toast{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);
     padding:10px 14px;font-size:var(--fs-sm);box-shadow:var(--shadow);max-width:320px;
     animation:tq-toast-in .16s ease}
.tq-toast.warn{border-color:rgba(224,163,92,.5);color:var(--warn)}
.tq-toast.bad{border-color:rgba(255,82,82,.5);color:var(--bad)}
@keyframes tq-toast-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* 顶栏用户区(访客 / 已登录) */
.tq-user{position:relative}
/* ⭐ 语言切换（2026-10-08 改三态）—— 它复用 `.tq-menu` 那套浮层样式，
   而 `.tq-menu{position:absolute;right:0;top:calc(100%+8px)}` **需要一个定位祖先**才落在按钮下面。
   ⚠️ `.tq-user` 那条 `position:relative` 是给用户菜单用的；语言按钮是**另一个** span，
   所以这一条不能省 —— 少了它浮层会跑到最近的上层定位块去（而且**不报错**，只是位置不对）。 */
.tq-lang{position:relative;display:inline-block}
.tq-u-trigger{display:flex;align-items:center;gap:8px;background:none;border:0;padding:0;
     color:var(--text);font-family:inherit;font-size:var(--fs-sm);cursor:pointer}
.tq-ava.guest{background:var(--panel2);background-image:none;color:var(--dim);
     border:1px solid var(--line)}
.tq-menu{display:none;position:absolute;right:0;top:calc(100% + 8px);z-index:45;min-width:190px;
     background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
     box-shadow:var(--shadow);padding:6px}
.tq-menu.on{display:block}
.tq-menu .hd{padding:8px 10px 4px;color:var(--dim);font-size:var(--fs-xs);
     max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tq-menu .sep{height:1px;background:var(--line);margin:6px 4px}
.tq-menu .it{display:block;width:100%;text-align:left;background:none;border:0;color:var(--text);
     padding:8px 10px;border-radius:var(--r-sm);font-family:inherit;font-size:var(--fs-sm);cursor:pointer}
.tq-menu .it:hover{background:var(--panel2);color:var(--gold)}

/* 还没开工的导航项 —— 灰显、点不动。
   ⚠️ 占位**不能再假装跳转**: 之前 6 项都指向仪表盘预览稿, 点"回测"跳出一个仪表盘 */
.tq-nav a.soon{opacity:.45;cursor:not-allowed}
.tq-nav a.soon:hover{background:none}

/* ---------- 三级导航: 「节」与它的子列表(用户 2026-09-15) ----------
   结构: 分组标题(交易/工具) → 一级条目 → 二级条目。
   一级里"自己有下级页面"的那些叫**「节」**(实盘监控 / 交易/监控策略 / 模拟交易) ——
   它们自己不是一个页面, 点它打开这一节排第一的页面。 */

/* 「节」的行 —— 视觉上与普通条目一样(图标 + 文字), 只是它是个 <button> */
.tq-sec{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
     background:none;border:0;color:var(--text);font-family:inherit;
     font-size:13.5px;padding:9px 10px;border-radius:var(--r-sm);
     cursor:pointer;transition:.15s}
.tq-sec svg{width:17px;height:17px;flex:0 0 17px;opacity:.75}
.tq-sec:hover{background:var(--panel2)}
.tq-sec.on{color:var(--gold);background:var(--gold-fade);box-shadow:inset 2px 0 0 var(--gold)}
.tq-sec.on svg{opacity:1}

/* 二级子列表 —— ⚠️ **只靠缩进**与一级区分, 字号**刻意不缩小**
   (用户 2026-09-15 明确要求: "二级子项名字体不要调小"; 早先那版调成 --fs-xs 是错的)。
   字号由上面的 `.tq-nav a`(13.5px)带下来, 这里**一个字都没改** —— 改了就是又缩回去了。 */
.tq-sublist{display:flex;flex-direction:column;gap:2px}
/* ⭐ **子项的选中态短一截**(用户 2026-09-28: 「选中侧栏的功能主项和子项, 选中状态没有区分开来,
   改为把**子项的选中状态缩短些**来区分」)。
   ⚠️ 原先节头(`.tq-sec.on`)与子项(`.tq-nav a.on`)是**同一套**样式: 同宽 + 同色 + 同一条左侧金条
      ⇒ 光看高亮分不出"我在这一节"还是"我在这一页"。
   ⚠️ 左右各让一点, 并把 `padding-left` 同步减 10 ⇒ **文字位置一个字没动**(8+34 = 10+24),
      变的只有药丸的宽度与左侧金条的位置(金条往右挪 ⇒ 顺带成了"更内层"的提示)。 */
.tq-sublist a{padding-left:24px;margin-left:10px;margin-right:14px}

/* ============================================================================
   仪表盘组件（2026-09-15 批 · 总仪表盘）—— **追加区**
   ============================================================================
   为什么放共享层而不是写进 dash_preview.html:
   用户已定「总仪表盘 = 域盘的只读缩略, **同一批组件两处复用**」⇒ 三个域仪表盘
   (实盘监控▸仪表盘 / 交易监控策略▸仪表盘 / 模拟交易▸仪表盘) 会把这些区块与卡片
   原样再用一遍。写进页面 = 抄四份, 改一处漏三处。

   改动纪律: 同上一批 —— **只新增**。上面既有的规则与令牌**一字未动**
   (那时老首页还挂着自己那份内联副本, 动令牌会让两处不一致;
    ⚠️ **2026-09-24 老首页已退役** ⇒ 这条限制解除)。

   ⚠️ 栅格一律 `repeat(auto-fit, minmax(min(<最小宽>,100%), 1fr))` ——
   **不写死列数**(CLAUDE.md 前端布局铁律 ②: `repeat(2,…)` 在大屏上就是两侧留空的直接原因)。
   且 `min(…,100%)` **不能省**: 只写 `minmax(420px,1fr)` 时, 容器窄于 420(手机竖屏)
   会让**轨道最小宽度撑破容器** ⇒ 横向溢出、整页能左右拖(铁律 ② 的括号里那句)。
   ========================================================================== */

/* 区块 —— 总仪表盘自上而下: 模拟交易 → 实盘监控 → 交易策略/技术指标 → 回测域
   (顺序是用户 2026-09-15 定的) */
.tq-region{display:flex;flex-direction:column;gap:var(--s3)}
.tq-region-hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:0 2px}
.tq-region-hd h2{margin:0;font-size:var(--fs-lg);font-weight:600}
.tq-region-hd .sp{flex:1}
.tq-region-hd .sub{color:var(--dim);font-size:var(--fs-sm)}

/* 卡片栅格 —— 宽的自动并排(手动交易|交易策略交易), 窄的自动落成一行一张。
   实盘监控/警报记录那两张表列数多 ⇒ 走 .wide, 最小宽更大, 更早落行。 */
.tq-cards{display:grid;gap:var(--s4);
     grid-template-columns:repeat(auto-fit,minmax(min(420px,100%),1fr))}
.tq-cards.wide{grid-template-columns:repeat(auto-fit,minmax(min(560px,100%),1fr))}
/* ⭐ **左窄右宽**: 左边那张是**表单卡**(创建订单 / 创建策略执行), 右边是**宽表格卡**。
   表单的控件本来就不该拉满, 而右边那张表列多(持仓 11 列) ⇒ 1:1 分栏时最右几列会被切掉。
   用户 2026-09-27 定的: 手动交易的「创建订单」就是这个比例, 然后要求**策略交易的
   「创建策略执行」卡与它同宽** ⇒ 收成这一条, 两页共用(⛔ 别再在某一页里另写一份 ——
   那样两页会各是各的宽度, 而没人说得出为什么)。
   ⚠️ 只挂在 `min-width:1100px` 上: 窄屏(手机/平板)照旧走上面那条 auto-fit
      (铁律② —— 不给窄屏新增写死列数的规则: 手机竖屏两列并排会挤成一条)。
   ⚠️ `minmax(0,…)` 的 0 是**故意的** —— 轨道最小宽为 0 ⇒ 容器比内容窄也不会撑破,
      与铁律②那条 `min(…,100%)` 同一个作用。
   ⚠️ **2026-09-28: 「订单历史」现在比容器宽 76px（要横向滚）—— 这是用户拍板的，别当成 bug**。
      原因: 那一档新增了「实际盈亏」列(+116px)、时间列又要精确到秒(+24px) ⇒ 表宽 698 → 838,
      而挂 1.6 时容器只有 762。实测过「加宽到 2.1 就不用滚」(表单卡 478→401, 两页都看过,
      无换行/溢出), **用户明确选择维持现状 (让它滚)**。⇒ ⛔ 别顺手把 1.6 调大 —— 那是**改过
      两页的表单卡宽度**, 是用户拍过板的取舍 (见 `docs/decisions/2026-09-28-订单实际盈亏…`)。 */
@media (min-width:1100px){
  .tq-cards.form-left{grid-template-columns:minmax(0,1fr) minmax(0,1.6fr)}
}
/* ⚠️ 与 .tq-wrap 同一个坑: grid 子项默认 min-width:auto ⇒ 宽表格的 min-content
   会把轨道**撑出容器**(整页横向滚动条), 而不是让 .tq-table-wrap 的内部滚动条生效 */
.tq-cards > *{min-width:0}

/* 卡片标题行 —— 比 `.tq-card > h2` 多一个右侧副信息位(如「当前持仓 21」)。
   刻意**新起一个类**而不去改 `.tq-card > h2`: 那条被另三个预览稿用着,
   为一行副信息改公共规则, 是"改动越滚越大"的典型起点。 */
.tq-card-hd{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;padding:14px 16px 10px}
/* ⚠️ 标题**不许被压扁**(`flex:none` = 保持自身宽度, 而不是被 flex 分摊掉)。
   没有它, 窄屏上「手动交易」会被摊成「手动交」「易」两行 —— 2026-09-27 实测:
   总仪表盘两张卡的卡头各加了第二个数(可用余额 + 持仓资金)之后就是这样。
   配合上面的 `flex-wrap`, 放不下时右侧那几个数**整体换到下一行**, 标题始终完整。 */
.tq-card-hd h2{margin:0;font-size:var(--fs);font-weight:600;flex:none}
.tq-card-hd .side{color:var(--dim);font-size:var(--fs-sm)}
.tq-card-hd .sp{flex:1}

/* 时间范围切换条 —— ⭐ 用户 2026-09-15 明确: 手动交易与交易策略交易**共用一个**
   ⇒ 它挂在区块头上, 不挂进任何一张卡里。挂进卡里就等于各一个了。 */
.tq-range{display:flex;gap:2px;flex-wrap:wrap}
.tq-range button{background:none;border:0;border-bottom:2px solid transparent;
     color:var(--dim);font-family:inherit;font-size:var(--fs-sm);
     padding:5px 9px;cursor:pointer;transition:.15s;border-radius:var(--r-sm) var(--r-sm) 0 0}
.tq-range button:hover{color:var(--text);background:var(--panel2)}
.tq-range button.on{color:var(--gold);border-bottom-color:var(--gold)}

/* 品种列表框 —— 用户 2026-09-15: "单独做一个列表框来固定展示区域的范围尺寸,
   如果超出则按盈亏排序"。⇒ **框高固定, 超出在框内滚**, 不许把卡片撑高(否则两张
   卡的底部对不齐, 并排时很难看)。排序是数据的事, 这里只管高度与对齐。 */
.tq-plist{max-height:132px;overflow-y:auto;border-top:1px solid var(--line-soft);
     padding:8px 16px 12px}
/* ⚠️ 表头与数据行**共用同一套列宽** —— 所以用 grid 而不是 flex: flex 里各写各的宽度,
   一旦某列内容变宽, 表头就跟数据行对不齐, 而且**看不出是坏了**。
   四列 = 名称(自适应) · 方向 · 金额(右) · 收益%(右)。 */
.tq-plist .hd,.tq-plist .row{display:grid;
     grid-template-columns:minmax(0,1fr) 46px 72px 58px;gap:8px;align-items:baseline}
.tq-plist .hd{color:var(--dim);font-size:var(--fs-xs);padding:0 0 4px;
     border-bottom:1px solid var(--line-soft);margin-bottom:4px}
/* 表头 3 格 vs 数据行 4 列: 「收益」**跨后面两列**(金额+百分比), 「方向」正好落在第 2 列。
   这样两边共用同一组列宽, 表头必然对齐 —— 不是靠调 margin 凑出来的。 */
.tq-plist .hd .col-dir{grid-column:2;text-align:center}
.tq-plist .hd .col-pnl{grid-column:3 / span 2;text-align:right}
.tq-plist .row{font-size:var(--fs-sm);padding:3px 0}
.tq-plist .row .nm{color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tq-plist .row .dir{color:var(--dim);text-align:center}
.tq-plist .row .amt{font-variant-numeric:tabular-nums;text-align:right}
.tq-plist .row .pct{color:var(--dim);font-variant-numeric:tabular-nums;text-align:right}

/* ---- 收益曲线（控件：static/tq_curve.js） ----
   用户 2026-09-15: 「这个控件以后其他页面也会用到」 ⇒ 样式也放共享层, 别各页各写。 */
.tq-curve{position:relative;width:100%}
/* ⚠️ `touch-action:pan-y` 而不是 `none`: 横向的拖动归我们(平移曲线), 但**竖向滑动
   要留给页面** —— 写 `none` 的话, 手指落在图上就**滚不动页面**了, 而这张图是整屏宽的。 */
.tq-curve canvas{display:block;width:100%;touch-action:pan-y;cursor:crosshair}
/* tooltip —— 深色卡片风格(用户 2026-09-15 选的), 三行: 时间 · 收益额 · 收益率。
   ⚠️ `pointer-events:none` 必须有: 否则鼠标移到提示框上会**打断拖动/悬停**, 表现为
      "线一到提示框下面就没了"。 */
.tq-curve-tip{display:none;position:absolute;top:2px;transform:translateX(-50%);
     background:var(--panel);border:1px solid var(--line);border-radius:var(--r-sm);
     padding:7px 10px;font-size:var(--fs-xs);color:var(--text);
     white-space:nowrap;pointer-events:none;z-index:2;box-shadow:var(--shadow,0 6px 18px rgba(0,0,0,.35))}
.tq-curve-tip .r-t{color:var(--dim);margin-bottom:4px;font-variant-numeric:tabular-nums}
.tq-curve-tip .r-v{display:flex;gap:10px;line-height:1.7}
.tq-curve-tip .r-v .k{color:var(--dim)}
.tq-curve-tip .r-v .v{margin-left:auto;font-variant-numeric:tabular-nums;font-weight:600}
/* 「回到最新」—— **只在用户拖走之后**才出现(贴右端时它没有任何用处)。
   ⚠️ `top` **由 JS 动态给**(摆到读数框下面, 免得挡住它的内容) —— 这里不写死,
      写死会在某个宽度下压住读数框, 而且是**静默**的。 */
.tq-curve-back{display:none;position:absolute;right:6px;top:2px;z-index:3;
     background:var(--panel2);border:1px solid var(--gold);color:var(--gold);
     font-family:inherit;font-size:var(--fs-xs);padding:3px 9px;
     border-radius:var(--r-pill);cursor:pointer;white-space:nowrap}
.tq-curve-back:hover{background:var(--gold-soft)}
.tq-curve-title{color:var(--dim);font-size:var(--fs-sm);padding:0 16px 4px}

/* 持有资金卡：标题行 = **标签 + 大字数字 + 单位** 同一行(用户 2026-09-15 定) */
.tq-stat-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.tq-stat-hd .lb{font-size:var(--fs-lg);font-weight:700}
.tq-stat-hd .unit{font-size:var(--fs-lg);color:var(--dim);font-weight:600}
.tq-stat-hd .sp{flex:1}
/* ⚠️ 复用 `.tq-hero` 的字号, 但**清掉它的上下外边距** —— 那个是给"单独一行"写的,
   放进 flex 行里会把基线顶歪 */
.tq-stat-hd .tq-hero{margin:0;line-height:1.1}

/* 时间范围条 —— 用户 2026-09-15: 移到**持有资金卡下方**、紧贴两张统计卡。
   两张卡**共用一个**(挂在这里, 不挂进任何一张卡里)。 */
.tq-range-row{padding:0 2px;margin:-6px 0 -2px}

/* ---- 既有组件的"进区块后"微调 ----
   `.tq-stat` 与 `.tq-kpis` 原本是为**直接摆在页面里**写的, 各带自己的外边距/内边距;
   放进 `.tq-region` / `.tq-card` 后会与区块、卡片头的留白叠加。下面三条**只在新区块
   结构内生效**(选择器带了 `.tq-region`/`.tq-card` 前缀), 不改变它们在别处的表现。 */
/* 持有资金卡: 去掉左右外边距 —— 否则它比同一区块里的卡片窄一圈, 左边缘对不齐 */
.tq-region > .tq-stat{margin:0}
/* 卡片内的 KPI 行: 首行紧贴卡片头(卡头已经有下边距), 后续行才要上间距 */
.tq-card .tq-kpis{padding-top:0}
.tq-card .tq-kpis + .tq-kpis{padding-top:var(--s3)}
/* 持有资金卡里的 KPI 行: 卡片本身已有 --s4 内边距, KPI 行再留一份就双份了 */
.tq-stat .tq-kpis{padding:0;margin-top:var(--s3)}

/* ============================================================================
   监控页「多 Tab」条（2026-09-15 批）—— **追加区**
   ============================================================================
   形态: 顶部一行「正在监控品类：N 个」+ 下面一排 Tab, 一个 Tab 一个品类;
   末尾是「＋ 创建新的监控品类」。
   ⚠️ 这一行**故意没有「监控」两个字** —— 页面标题由外壳顶栏按 `data-title` 渲染
      (tq_shell.js 的 renderTop), 再写一个就是**两个「监控」**(用户 2026-09-15 截图指出)。
   DOM 由 `static/tq_monitor_tabs.js` **自己建并插进 `.wrap` 开头** ——
   ⚠️ 刻意不让生成器往页面里塞标记: 标记一旦进了生成物, 改版式就要同时改生成器与模板。
   ========================================================================== */
.tq-monitor-tabs{margin:0 0 var(--s3)}
.tq-mt-head{padding:0 2px 10px}
.tq-mt-head .cnt{color:var(--dim);font-size:var(--fs-sm)}

/* Tab 行 —— flex + wrap, **不写死列数**(铁律②); 窄屏自动换行, 不横向撑破
   ⚠️ **2026-10-01 去掉整排的卡片背景**(用户给图指的正是这排的空白处):
      原先 `background:var(--panel)` + `border` + 圆角 ⇒ 一排 tab 外面还套一层卡片,
      而这排**只有一行内容**, 看着像"卡片里孤零零几个标签"。
      ⇒ 去掉背景/描边/圆角, 让 tab **直接落在页面底上**(与下面那几块内容同一个底面);
      `padding` 也从 `8px 10px` 收到 `4px 0`(没有卡片之后那圈内边距是多余的)。
      ⚠️ **它的使用方有两处**: 监控页 与 模拟盘▸策略交易页(轻量模式) ⇒ 改了两边一起变。 */
.tq-mt-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center;
     margin:0 calc(-1 * var(--tq-gutter, 0px));
     padding:4px var(--tq-gutter, 0px) 10px;
     border-bottom:1px solid var(--line)}
     /* ⭐ **2026-10-01 加这条底线**(用户给图): 那排 tab 下方画一根横线,
        语义是"**下面的内容都属于当前这个产品**"。
        ⚠️ **同日又改**: 用户报"横线前后都留有空, 要前后占满" —— 根因是**宿主容器的内边距**
        (监控页 `.wrap{padding:18px}`) 把整排(连同它的边框)一起内缩了。
        ⇒ 那排**往两边各外扩**，边框就顶到容器边缘; 同时用等量 `padding-left/right` 补回来,
        **里面的 tab 位置一点不变**。
        ⭐ **`--tq-gutter` 由宿主给**(它才知道自己的内边距是多少), 默认 `0px` ⇒
        没设这个变量的宿主(如模拟盘▸策略交易页)**行为与改动前逐位相同**。
        ⛔ 别在这里写死 18px —— 那是把某一个页面的内边距抄进共享件(本仓最忌的"第二个出处")。 */
.tq-mt-tab{display:inline-flex;align-items:center;gap:7px;background:var(--panel2);
     border:1px solid var(--line);color:var(--dim);font-family:inherit;
     font-size:var(--fs-sm);padding:6px 10px;border-radius:0;
     cursor:pointer;transition:.15s;white-space:nowrap}
     /* ⚠️ **圆角 2026-10-01 去掉了**(用户: "改为长方形不要带圆弧") —— 原为 `var(--r-pill)`。
        ⛔ 别顺手把它"统一"回去: 这是**刻意的版式选择**(方角看起来更像"页签"而不是"标签")。
        ⚠️ 只改了**产品名**那个 `.tq-mt-tab`;「＋创建新的监控品类」(`.tq-mt-add`)**仍是胶囊** ——
           用户这句只点了"产品名的卡片", 没点它。要一起改说一声(一行)。 */
.tq-mt-tab:hover{color:var(--text);border-color:#3a466a}
.tq-mt-tab.on{color:var(--gold);border-color:var(--gold);background:var(--gold-soft)}
/* 「这个品种不能关」的气泡 —— 在**鼠标位置**弹, 3 秒自动收(用户 2026-09-27)。
   ⚠️ `pointer-events:none`: 它不该吃掉点击(否则连点两下时第二下落在气泡上)。
   ⚠️ 宽度夹住: 手机上鼠标位置靠右时, 长句会顶出屏幕。 */
.tq-mt-bub{position:fixed;z-index:80;max-width:min(260px,78vw);padding:7px 10px;
  border-radius:var(--r-sm,8px);border:1px solid var(--line,#252e3d);
  background:var(--panel,#161b24);color:var(--text,#dfe6ee);font-size:var(--fs-xs,12px);
  line-height:1.5;box-shadow:0 6px 18px rgba(0,0,0,.45);pointer-events:none}
.tq-mt-tab .nm{font-weight:600}
/* ✕ —— 只有**多于一个 Tab** 时才由 JS 建出来(用户定: 最后一个的关闭不生效, 也不提示) */
.tq-mt-tab .x{opacity:.55;font-size:11px;line-height:1;padding:2px 3px;border-radius:50%}
.tq-mt-tab .x:hover{opacity:1;color:var(--bad);background:rgba(255,82,82,.12)}
.tq-mt-add{background:none;border:1px dashed var(--line);color:var(--dim);
     font-family:inherit;font-size:var(--fs-sm);padding:6px 12px;
     border-radius:0;cursor:pointer;transition:.15s;white-space:nowrap}
     /* ⚠️ **圆角 2026-10-01 去掉了**(用户: "把创建新监控的胶囊改为长方形") ——
        原为 `var(--r-pill)`。⭐ 与产品名那个 `.tq-mt-tab` 同步了(那一轮先改的它),
        现在**这一排三种元素都是方角**: 产品 tab · 「＋新监控」 · (它们外层的行)。
        ⛔ 别只把其中一个"顺手统一"回胶囊 —— 并排的两块形状不一致最难解释。 */
.tq-mt-add:hover{color:var(--gold);border-color:var(--gold)}
/* 到上限 —— 灰掉但**仍可点**: 点了要弹一句"为什么不能开"(静默无反应会被当成坏了) */
.tq-mt-add.full{opacity:.45;border-style:solid}
.tq-mt-add.full:hover{color:var(--dim);border-color:var(--line)}

/* ============================================================================
   桌面端侧栏开合（2026-09-15 用户要的）—— **追加区**
   ============================================================================
   用户原话: 「电脑端实现左边功能栏可以展开和缩进的功能, 缩进后可以能让页面内容展示更多」。
   形态他选的是**整条隐藏(0px)** —— 另两个备选(图标窄条 / 窄条+悬停浮层)他没选。

   ⚠️ **断点这个数在三处出现, 改一处必须改三处**(JS 里也有一个, 决定 ☰ 是"开合侧栏"
      还是"拉出抽屉") ⇒ 有断言盯着它们一致:
      `tests/test_shell_ui.py::test_side_toggle_breakpoint_matches_css`。
      这是本仓栽过的那类病(同一个事实写两遍, 漂了没人知道), 所以不靠自觉。

   ⚠️ 收起态**只作用于 ≥1281px**: 窄屏那边侧栏本来就是抽屉(默认在屏幕外),
      ☰ 的语义在那里是"拉出来"而不是"收起来" —— 两段规则各管一段, 不会打架。
      ⇒ 从窄屏拖宽时, 抽屉的 `.open`/`.show` 自动失效(它们只写在窄屏那段里);
        反向拖窄时, `body.tq-side-min` 也自动失效(只写在这里)。
   ========================================================================== */
@media (min-width:1281px){
  /* 桌面端也要看得见 ☰ —— 它就是开合开关(基础规则里它只为窄屏的抽屉而存在) */
  .tq-burger{display:flex}
  /* 收起: 整条让出宽度。用 display:none 而**不是** width:0 —— 后者还要同时处理
     flex-basis / padding / min-width / overflow, 少写一样就留下一条侧栏宽的空白带,
     而且**看起来只是"没对齐"**, 很难归因。 */
  body.tq-side-min .tq-side{display:none}
}

/* ============================================================================
   手机端底部快捷栏（2026-09-15 用户要的）—— **追加区**
   ============================================================================
   用户给的图上 4 格: 总仪表盘 | 实盘监控 | 模拟交易 | 回测系统。
   ⚠️ 这 4 格是**精选**, 不是侧栏全集(交易组有 5 个一级条目) —— 名单在
      `tq_shell.js` 的 `TABBAR` 里, **只此一处**, 别往页面里抄。
   ⚠️ **只在手机宽的屏幕显示**(用户 2026-09-15 定): 电脑端侧栏一直在旁边, 底栏是重复的。

   z-index 30 —— 必须**低于**遮罩(40)/弹窗(60)/提示(80), 见本文件头的层级表。
   ⚠️ 反过来会出现"侧栏抽屉拉开时底栏浮在遮罩之上点得动"这种怪事。

   ⚠️ `env(safe-area-inset-bottom)` 在 **iPhone 上要页面写了 `viewport-fit=cover` 才非 0**
      —— 现有页面的 viewport meta 都没写。这里先带上(值是 0 时无害), 但不等于已经处理了
      刘海屏: 真要处理得改每个页面的 meta(含生成器 gen_monitor_preview.py), 是另一批的事。
   ========================================================================== */
.tq-tabbar{display:none}      /* 基础不显示 —— 只在下面那段窄屏媒体查询里露出来 */

/* ⚠️ 这是**第二段** `@media (max-width:760px)`(上面还有一段) —— 追加区不改既有那段,
   两段都生效; 同断点下靠后的规则优先。读代码时**两段都要看**, 别只看第一段。 */

@media (max-width:760px){
  .tq-tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:30;
       background:var(--panel);border-top:1px solid var(--line);
       padding-bottom:env(safe-area-inset-bottom,0px)}
  .tq-tb{position:relative;flex:1;min-width:0;display:flex;flex-direction:column;
       align-items:center;gap:3px;background:none;border:0;color:var(--dim);
       font-family:inherit;font-size:var(--fs-xs);padding:9px 4px 8px;
       cursor:pointer;transition:.15s}
  .tq-tb svg{width:19px;height:19px;opacity:.8}
  /* ⚠️ 名字最长的是「总仪表盘」(4 字) —— 再长就必须截断, 否则窄屏上四个格子会互相挤
     (`min-width:0` + `flex:1` 让每格等宽, 不写的话长名字那格会把别的挤扁) */
  .tq-tb .lb{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .tq-tb.on{color:var(--gold)}
  .tq-tb.on svg{opacity:1}
  .tq-tb.on::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
       width:26px;height:2px;background:var(--gold);border-radius:0 0 2px 2px}

  /* 别让底栏盖住最后一块内容。
     ⚠️ 挂在**外壳骨架 `.tq-main`** 上, 而不是各个内容容器(`.tq-page` / `.tq-wrap` / …):
        容器类名是**各页自己挑的**, 列名单就一定会漏 —— 而这事**真的发生了**:
        监控页用的是从老首页带来的 `.wrap`, 不在这类名单里,
        是规则写完、逐页比对容器时才发现的(手机上表现为"滚到底有几个按钮点不到")。
        `.tq-main` 每页都有 ⇒ **一处就够**, 也不怕将来新页面挑新容器名。
     ⚠️ 不会因此多出滚动条: `.tq-app` 是 `min-height:100vh`, 这点内边距被吃在容器高度里。 */
  body.tq-has-tabbar .tq-main{padding-bottom:calc(54px + env(safe-area-inset-bottom,0px))}
}

/* ============================================================================
   顶栏「实时」状态 chip + Tips 浮层（2026-09-16 批）—— 又一段**追加区**, 只新增
   ============================================================================
   背景: 顶栏那个 `● 实时` 原本是**纯装饰** —— 建完就没人再碰它, 永远绿、永远写「实时」,
   行情死了也不变; 而底栏那个是**真的**。一个界面两个「实时」且互相矛盾(用户截图指出)。
   这批把它做成真的, 并让底栏去掉重复的「实时」二字。

   状态契约(由页面通过 `tq:live` 事件上报, 见 tq_shell.js):
     ok   绿    取数成功
     err  红    取数失败
     slow 黄闪  取数变慢(⚠️ **不是每次轮询都黄** —— 6 秒一拍, 每次闪就是不停抖)
     idle 灰    这一页从未上报过(默认态 = 不撒谎)

   ⚠️ **颜色不许借涨跌令牌**: 本文件的 `--up` 是红(涨)、`--down` 是绿(跌),
      拿它们表达"成功/失败"会让人以为跟行情涨跌有关 —— 与下面 `--bad` 那条注释同源。
   z-index 取 **46**: 高于用户菜单(45)、低于移动端抽屉(50), 见上面层级表。
   ========================================================================== */
:root{ --ok:#3ddc84 }

.tq-dot.ok{background:var(--ok);box-shadow:0 0 0 3px rgba(61,220,132,.16)}
.tq-dot.err{background:var(--bad);box-shadow:0 0 0 3px rgba(255,82,82,.16)}
.tq-dot.slow{background:var(--warn);box-shadow:0 0 0 3px rgba(224,163,92,.16);
     animation:tq-blink 1s ease-in-out infinite}
/* 全文件**第二条** keyframes(第一条是 tq-toast-in, 见上) */
@keyframes tq-blink{0%,100%{opacity:1}50%{opacity:.22}}
/* 对动效敏感的人: 不闪, 点仍然留着 —— 状态看得见, 只是不呼吸 */
@media (prefers-reduced-motion:reduce){ .tq-dot.slow{animation:none} }

/* chip 现在是个**可点的控件**(手机上是它开合 Tips), 不再是纯展示的 span */
#tqLive{cursor:pointer}
#tqLive:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

/* Tips 浮层 —— ⚠️ **挂在 body 上、position:fixed**, 刻意不放进顶栏:
   顶栏在窄屏是 `flex-wrap:wrap`(见上面第一段 760 媒体查询), 挂在里面的浮层会跟着折行、
   被挤出屏幕(用户菜单 `.tq-menu` 在这上面踩过坑, 见那段注释)。
   位置每次显示时按 chip 的 getBoundingClientRect() 现算。 */
/* ⚠️ 显隐用 **visibility/opacity**, **不是 display** —— 两个理由, 都不是洁癖:
   ① 元素**始终参与布局** ⇒ 藏着的也能量到 `offsetWidth`, 于是可以先摆好位置再显示
      (display:none 时量到的是 0, 只能先显示再定位 ⇒ 会看到它跳一下);
   ② 实测(2026-09-16, headless Chrome): `display:none→block` 翻转出来的固定定位元素
      **不下笔**，而同 class 的新元素正常 —— 换成 visibility 就正常了。
      (诚实的边界: 那台 headless 上的确切机理**没查清**; 这条改法本身独立成立, 见 ①。) */
.tq-live-tip{position:fixed;z-index:46;visibility:hidden;opacity:0;
     max-width:min(320px,calc(100vw - 24px));
     background:var(--panel2);border:1px solid var(--line);border-radius:var(--r-sm);
     padding:8px 11px;font-size:var(--fs-xs);color:var(--text);line-height:1.5;
     /* ⚠️ `pre-line`: Tips 现在**可能是两行**(第一行全局连通性 / 第二行本页精确信息),
        靠 `\n` 分隔。少了它换行会被折成空格, 两行糊成一坨。 */
     white-space:pre-line;
     box-shadow:0 8px 24px rgba(0,0,0,.45);word-break:break-word}
.tq-live-tip.on{visibility:visible;opacity:1}

/* ============================================================================
   紧凑磁贴行（2026-09-26 · 模拟交易 ▸ 手动交易）
   ============================================================================
   用户原话:「这 6 个磁贴要做小一点, 排成一排」。
   ⚠️ 只加**修饰类**, **不动** `.tq-kpis` 本体 —— 别处（总仪表盘 / 实盘仪表盘 /
      回测页）的磁贴行照旧; 想变小的地方自己加 `.compact`。
   ⚠️ 列数**不写死 6**: `auto-fit` + `min(150px,100%)` —— 铁律②(写死列数在大屏上就是
      两侧留空的根源), 且 `min(…,100%)` 不能省(手机竖屏容器比 150 还窄 ⇒ 轨道撑破容器)。
   ⚠️ 每个磁贴的**最小宽**同时决定了"一排最多放几个": 1240 宽的卡片里 6 个正好;
      手机竖屏会自动折成 2~3 个一行 —— 那是**要的**, 不是退让。
   ========================================================================== */
.tq-kpis.compact{grid-template-columns:repeat(auto-fit,minmax(min(150px,100%),1fr));
     gap:var(--s2);padding:var(--s2) var(--s4)}
.tq-kpis.compact .tq-kpi{padding:9px 11px}
.tq-kpis.compact .tq-kpi .k{font-size:var(--fs-xs)}
.tq-kpis.compact .tq-kpi .v{font-size:17px;margin-top:4px}

/* ----------------------------------------------------------------------------
   四格一行（2026-09-26 建为「三格」· 2026-09-28 加「持仓资金」⇒ 扩成四格）
   ----------------------------------------------------------------------------
   用户原话(09-26):「把持有资金的 3 个磁条也做成一行」—— 手机上也要一行。
   用户 09-28:「增加一栏持仓资金统计」⇒ 三格变四格（字段本来就有: `positionValue`）。
   ⚠️ 手机竖屏(390)减去页面与卡片内边距**总共只剩 ~325px** ⇒ 四格一行每格才 ~81px,
      连 "94,777.85" 都放不下(更别说 "+52.84 (+0.1%)")。
      **所以最小宽取 120px, 让它落成 2×2** —— 每格 ~158px, 舒展开。
      ☠️ 别照搬三格那时的 96px: 那会排成 **3+1**, 最后一行单格只占 1/3 宽、
        右边空出两大格 ⇒ 那正是铁律②要防的"两侧留空"的观感。
   ⚠️ 仍然走 `auto-fit`(铁律②: 不写死列数) —— 320 的屏同样落 2×2, 不会撑破。
   ⚠️ 只加**修饰类**, 不动 `.tq-kpis` 本体。
   -------------------------------------------------------------------------- */
.tq-kpis.four{grid-template-columns:repeat(auto-fit,minmax(min(120px,100%),1fr));gap:var(--s2)}
.tq-kpis.four .tq-kpi{padding:10px 11px}
@media (max-width:560px){
  .tq-kpis.four .tq-kpi{padding:8px 9px}
  .tq-kpis.four .tq-kpi .v{font-size:15px}
}

/* ============================================================================
   外壳容器与 iframe 保活（2026-09-28 · `_shell.html`）
   ============================================================================
   这一段**只有"被嵌那一侧"**（`body.tq-embed`，即 iframe 里的那些页）。
   ⚠️ 容器那一侧（`body.tq-host`）的规则在 `_shell.html` 自己的 `<style>` 里 ——
      只有一个文件用得到，放那里更内聚，也少一次"两处各写一份"。

   为什么被嵌页要收掉骨架：被嵌的那一页**仍然**加载 `tq_shell.js`（页面要用它的
   工具 API），只是 **host 模式会跳过外壳渲染** ⇒ `.tq-side` / `#tqTopbar` 是**空**的。
   不收掉就是白占一条 180px 的侧栏宽（而内容区被迫窄掉）。

   ⚠️ `display:none` 靠**选择器权重**压过 `.tq-side{display:flex}` ——
      两个类 > 一个类，**不需要 `!important`**。
   ⚠️ `padding-bottom:0` 是防御：底栏在容器那边画，被嵌页**不该**再留那 54px
      （`body.tq-has-tabbar .tq-main` 那条与它同权重，靠**在后面**胜出）。
   ========================================================================== */
body.tq-embed .tq-side,
body.tq-embed .tq-scrim,
body.tq-embed #tqTopbar,
body.tq-embed .tq-tabbar{display:none}
body.tq-embed .tq-app{display:block;min-height:0}
body.tq-embed .tq-main{display:block;padding-bottom:0}
