/* 量化交易终端 —— 外壳与新组件
   配色/变量沿用 style.css（深色交易终端风格），这里只加布局与业务组件。

   两份样式表的分工（**同一个选择器不要在两边各定义一遍**）：
     style.css  基础层：设计令牌（:root 的色彩/字体/圆角）、reset、html/body 基础、
                顶栏与侧栏骨架、按钮 / 表单 / 表格 / 标签等通用组件
     本文件      外壳与业务层：应用布局骨架、各页特有的块、新增组件
   加载顺序：index.html 里 style.css 在前、本文件在后（因此本层可覆盖基础层）。 */

/* ============================================================= 布局 */
/* html / body 的高度规则在 style.css（基础层）里定义，那里也写了为什么
   「不能给 html+body 都设 height:100%」（sticky 会被推出包含块而集体失效）。
   本文件不再重复声明 —— 同一属性只留一份定义，免得改一处以为生效。 */

:root { --rail-w: 212px; }     /* 布局变量，与 style.css 的设计令牌互补 */

.app { display: flex; align-items: flex-start; min-height: 100vh; }

/* ------------------------------------------------------------- 侧边栏
   默认收起：它是 position:fixed 的浮层，translateX(-100%) 完全移出视口，
   主内容占满全宽（这是为了让多列表格拿到全部横向空间）。
   唤出方式：悬浮/点击顶栏的 ☰。
   ⚠️ 顶栏是 sticky 的，所以浮层从 topbar 下方开始（top: var(--topbar-h)），
      这样页面标题与状态栏始终可见，也让 ☰ 按钮不会被浮层盖住。 */
.sidebar {
  position: fixed; left: 0; top: var(--topbar-h, 54px);
  height: calc(100vh - var(--topbar-h, 54px));
  width: var(--rail-w);
  flex-shrink: 0; display: flex; flex-direction: column;
  background: var(--bg-2); border-right: 1px solid var(--line);
  transform: translateX(-100%);
  transition: transform .18s ease, box-shadow .18s ease;
  z-index: 60;
}
.app.rail-open .sidebar {
  transform: none;
  box-shadow: 14px 0 38px rgba(0, 0, 0, .5);
}
.side-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 14px 14px 16px; border-bottom: 1px solid var(--line);
}
.side-brand .logo { width: 26px; height: 26px; border-radius: 7px; }
.side-brand .t { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.side-brand .t b { font-size: 13.5px; letter-spacing: .2px; }
.side-brand .t span { font-size: 10.5px; color: var(--tx-3); letter-spacing: .4px; }
.side-pin { margin-left: auto; flex-shrink: 0; }
.side-pin svg { width: 15px; height: 15px; }

.nav { padding: 10px 8px; display: flex; flex-direction: column; gap: 2px;
       flex: 1; overflow-y: auto; }
.nav-group {
  font-size: 10px; font-weight: 700; letter-spacing: .9px; color: var(--tx-3);
  padding: 12px 10px 6px; text-transform: uppercase;
}
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  color: var(--tx-2); font-size: 13px; font-weight: 550;
  border: 1px solid transparent; background: transparent;
  font-family: inherit; text-align: left; width: 100%;
  transition: background .14s, color .14s, border-color .14s;
}
.nav-item:hover { background: var(--panel); color: var(--tx); }
.nav-item.on {
  background: var(--panel-2); color: var(--tx);
  border-color: var(--line-2); box-shadow: inset 2px 0 0 var(--amber);
}
.nav-item.on .ico { color: var(--amber); }
.nav-item .ico { width: 16px; height: 16px; flex-shrink: 0; color: var(--tx-3); }
.nav-item .badge {
  margin-left: auto; font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  padding: 1px 6px; border-radius: 20px; background: #232c3e; color: var(--tx-2);
}
.nav-item.on .badge { background: var(--amber); color: #1a1205; }

.side-foot { padding: 10px; border-top: 1px solid var(--line); }
.user-card {
  display: flex; align-items: center; gap: 9px; padding: 8px 9px;
  border-radius: 9px; background: var(--panel); border: 1px solid var(--line);
}
.avatar {
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  background: linear-gradient(135deg, var(--amber), #c99400); color: #1a1205;
}
.user-card .u { min-width: 0; flex: 1; line-height: 1.3; }
.user-card .u b { display: block; font-size: 12.5px; overflow: hidden;
                  text-overflow: ellipsis; white-space: nowrap; }
.user-card .u span { font-size: 10.5px; color: var(--tx-3); }
.icon-btn {
  border: 0; background: transparent; color: var(--tx-3); cursor: pointer;
  padding: 5px; border-radius: 6px; display: grid; place-items: center;
  transition: color .15s, background .15s;
}
.icon-btn:hover { color: var(--tx); background: var(--panel-2); }
.icon-btn svg { width: 15px; height: 15px; }

/* 主内容：固定展开时让位给侧边栏。
   ⚠️ 让位加在 .page 上而不是 .main 上 —— 顶栏是 .main 的子元素，
      若给 .main 加 margin-left，顶栏（含 ☰ 按钮）会跟着右移，
      鼠标悬停在 ☰ 上点击固定后按钮就"跑了"，再点就点不到。
      只让页面正文让位，顶栏保持通栏、☰ 永远在最左侧。 */
.main {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
}
.main > .page { margin-left: 0; transition: margin-left .18s ease; }
.app.rail-pinned .main > .page { margin-left: var(--rail-w); }

/* ------------------------------------------------ 页面级滚动条（document 本身）
   2026-09-27 用户截图：「用户与权限」页右边的滑条不好看 —— 那是一根**没被样式覆盖**的
   Chrome 默认灰白条（页面上其它滚动容器都挂了深色细条，唯独整页滚动没管）。
   ⚠️ 这里只能挂在 html / body 上：整页滚动条属于**视口**，不属于任何元素，
      给 .page 加样式对它无效。⚠️ 不要 "body { overflow:hidden }" 去藏它 ——
      本项目多处依赖整页滚动 + sticky 顶栏（见 style.css 顶部那条注释）。
   配色与 .scroll-thin 对齐，但**宽一点（10px）**：整页滚动条是常驻控件，
   压在 8px 以下在 Windows 上拖拽会有明显「抓不住」的手感。 */
html {                                        /* Firefox */
  scrollbar-width: thin;
  scrollbar-color: var(--line-2) transparent;
}
html::-webkit-scrollbar { width: 10px; height: 10px; }
html::-webkit-scrollbar-track { background: var(--bg); }  /* 与页底色一致，视觉上隐形 */
html::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border: 2px solid transparent; border-radius: 6px;
  background-clip: content-box;
}
html::-webkit-scrollbar-thumb:hover { background: #46536a; background-clip: content-box; }
html::-webkit-scrollbar-corner { background: var(--bg); }

/* 全局顶栏的 position / height / z-index 等主定义在 style.css 的 .topbar，
   这里只补外壳侧的正文样式（页内 sticky 用 --topbar-h 做偏移基准）。 */
.topbar .ptitle { font-size: 13.5px; font-weight: 650; white-space: nowrap; }
.topbar .psub { font-size: 11.5px; color: var(--tx-3); }

/* 顶栏标题位上的**模块页签**（同一模组的两个视图互跳，如 交易账户 / 模拟交易）。
   外观复用 .seg（页面里的分段控件），这里只压扁尺寸以适配 54px 顶栏。
   ⚠️ 两个 flex 必须显式归零：.seg 的 button 默认 `flex: 1`，放进顶栏会撑开整行。 */
.topbar .head-tabs { flex: 0 0 auto; gap: 2px; padding: 2px; border-radius: 8px; }
.topbar .head-tabs button { flex: 0 0 auto; padding: 4px 11px; font-size: 12px; }
.topbar .head-tabs button.on { color: var(--amber); }

/* ☰ 侧边栏开关（常驻顶栏左端）
   ⚠️ 不要用 v-if 在展开时隐藏它 —— 元素被移除后 mouseleave 不再派发，
      hover 状态会永远卡住。这里用样式表达状态。 */
.rail-toggle {
  display: grid; place-items: center; flex-shrink: 0;
  width: 30px; height: 30px; margin-right: -8px; border-radius: 8px;
  cursor: pointer; border: 1px solid transparent;
  background: transparent; color: var(--tx-2);
  transition: background .14s, color .14s, border-color .14s;
}
.rail-toggle:hover { background: var(--panel-2); color: var(--tx); border-color: var(--line-2); }
.rail-toggle.on {
  color: var(--amber); border-color: rgba(240, 185, 11, .34);
  background: rgba(240, 185, 11, .08);
}
.rail-toggle svg { width: 17px; height: 17px; }

.page { padding: 16px 18px 40px; }
.page-narrow { max-width: 980px; }
/* 页面自带全宽条（KPI 行 / 控件条 / 吸顶表头）时用它，避免左右留白割裂 */
.page-flush { padding: 0 0 40px; }

/* ------------------------------------------------- 页面内二级 Tab
   用于「一个策略页下挂多个视图」（EMA 监控 → 实时监控 / 历史记录）。
   刻意不做 sticky：本页只有 .controls 与表头吸顶，多一级会打乱
   JS 写入的 --thead-top 偏移，收益也不大。 */
.viewtabs {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 10px 18px; border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.viewtabs .vt {
  display: flex; align-items: center; gap: 7px;
  font: inherit; font-size: 13px; font-weight: 600;
  padding: 6px 14px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--tx-2);
  transition: background .15s, color .15s, border-color .15s;
}
.viewtabs .vt:hover { color: var(--tx); background: var(--panel); }
.viewtabs .vt.on {
  background: var(--panel-2); color: var(--tx);
  border-color: var(--line-2); box-shadow: inset 0 -2px 0 var(--amber);
}
.viewtabs .vt .ico { width: 15px; height: 15px; }
.viewtabs .vt.on .ico { color: var(--amber); }
.viewtabs .vt-hint {
  margin-left: 10px; font-size: 11.5px; color: var(--tx-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 历史记录子视图（嵌在 page-flush 容器里，自带内边距） */
.rec-view { padding: 16px 18px 40px; }

/* ============================================================= 卡片 */
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}
.card + .card { margin-top: 14px; }
.card-h {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}
.card-h h3 { margin: 0; font-size: 13px; font-weight: 650; letter-spacing: .2px; }
.card-h .sub { font-size: 11.5px; color: var(--tx-3); }
.card-h .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.card-b { padding: 14px; }
.card-b.tight { padding: 0; }

.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 1100px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================= 分区（设置页）
   一组相关卡片 + 一个小节标题。卡间距**全部由这里的 gap 负责**，
   模板里不要再写 style="margin-top:14px"。
   ⚠️ 必须把 .card + .card 那条外边距在分区内归零：不然它和外层 gap
      叠加成 28px；在 .grid-2 里更糟 —— 第二张卡会被压矮 14px，
      两卡底边错位（这就是原先把 margin-top:0 写在内联里的原因）。 */
.sec { display: flex; flex-direction: column; gap: 14px; }
.sec + .sec { margin-top: 26px; }
.sec > .card + .card,
.sec .grid-2 > .card + .card,
.sec .grid-3 > .card + .card { margin-top: 0; }

.sec-h { display: flex; align-items: center; gap: 9px; padding: 0 1px; }
.sec-h::before {                          /* 左侧竖条：一眼分清分区起点 */
  content: ''; width: 3px; height: 12px; border-radius: 2px;
  background: var(--amber); opacity: .9; flex-shrink: 0;
}
.sec-h h2 {
  margin: 0; font-size: 12px; font-weight: 700; letter-spacing: 1px;
  color: var(--tx-2); white-space: nowrap;
}
.sec-h .sub { font-size: 11px; color: var(--tx-3); white-space: nowrap; }
.sec-h .rule {
  flex: 1; height: 1px; min-width: 16px;
  background: linear-gradient(90deg, var(--line-2), transparent);
}
@media (max-width: 720px) { .sec-h .sub { display: none; } }

/* 状态文案：**别用涨跌色表达状态**。
   本项目已把 --down(绿) 当"正常"用（.dot.live / tag-short / note.ok 都是），
   所以 ok 沿用绿；但"需要注意、并非错误"的状态必须用琥珀 ——
   原先给「数据密钥未解锁」上了 --up(红)，看着像故障，而它只是提示重新登录。 */
.st-ok { color: var(--down); }
.st-warn { color: var(--amber); }

/* 统计块 */
.stat { padding: 12px 14px; }
.stat .s-l { font-size: 11px; color: var(--tx-3); letter-spacing: .3px; }
.stat .s-v {
  font-family: var(--mono); font-size: 20px; font-weight: 700;
  letter-spacing: -.3px; line-height: 1.25; margin-top: 2px;
}
.stat .s-sub { font-size: 11px; color: var(--tx-3); font-family: var(--mono); margin-top: 2px; }
.s-v.up, .up-text { color: var(--up); }
.s-v.down, .down-text { color: var(--down); }
.s-v.amber { color: var(--amber); }
.s-v.violet { color: var(--violet); }
.s-v.cyan { color: var(--cyan); }

/* ============================================================= 表单 */
.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
.field:last-child { margin-bottom: 0; }
.field > label { font-size: 11.5px; color: var(--tx-2); letter-spacing: .2px; }
.field .hint { font-size: 11px; color: var(--tx-3); line-height: 1.5; }
.input, textarea.input {
  font: inherit; font-size: 12.5px; color: var(--tx);
  background: #0d121b; border: 1px solid var(--line-2);
  border-radius: 7px; padding: 8px 10px; outline: none; width: 100%;
  font-family: var(--mono);
}
.input:focus { border-color: #3d4c6b; }
.input::placeholder { color: var(--tx-3); }
.input.err { border-color: rgba(246,70,93,.6); }
select.input { cursor: pointer; font-family: inherit; }

.row { display: flex; gap: 10px; align-items: flex-end; }
.row > * { flex: 1; min-width: 0; }
.row.tight { gap: 8px; }

.btn-primary {
  background: var(--amber); border-color: var(--amber); color: #1a1205;
  font-weight: 650;
}
.btn-primary:hover:not(:disabled) { background: #ffc81f; border-color: #ffc81f; }
.btn-danger { border-color: rgba(246,70,93,.45); color: #ff9aa7; }
.btn-danger:hover:not(:disabled) { background: rgba(246,70,93,.12); }
/* 做多 / 做空按钮：**用方向色（多=绿、空=红）**，不是涨跌色。
   历史上这里写成了 var(--up)/var(--down)（多=红），与币安/OKX 的下单按钮正好相反，
   已按用户要求改掉。改色只动 :root 的 --side-*。 */
.btn-buy { background: var(--side-long); border-color: var(--side-long); color: #04241a; font-weight: 650; }
.btn-buy:hover:not(:disabled) { background: #17dd8f; border-color: #17dd8f; }
.btn-sell { background: var(--side-short); border-color: var(--side-short); color: #fff; font-weight: 650; }
.btn-sell:hover:not(:disabled) { background: #ff5a70; border-color: #ff5a70; }
.btn-block { width: 100%; justify-content: center; }
.btn-sm { padding: 4px 9px; font-size: 11.5px; }
.btn-xs { padding: 2px 7px; font-size: 11px; border-radius: 5px; }

.seg { display: flex; gap: 3px; background: #0d121b; padding: 3px;
       border-radius: 9px; border: 1px solid var(--line); }
.seg button {
  flex: 1; font: inherit; font-size: 12px; font-weight: 600;
  padding: 6px 8px; border-radius: 6px; cursor: pointer;
  border: 0; background: transparent; color: var(--tx-2); white-space: nowrap;
  transition: background .15s, color .15s;
}
.seg button:hover { color: var(--tx); }
.seg button.on { background: var(--panel-2); color: var(--tx); }
.seg button.on.long { background: rgba(14,203,129,.16); color: var(--side-long); }
.seg button.on.short { background: rgba(246,70,93,.16); color: var(--side-short); }

/* 提示条 */
.note {
  display: flex; gap: 9px; padding: 10px 12px; border-radius: 8px;
  font-size: 11.5px; line-height: 1.6; border: 1px solid var(--line-2);
  background: var(--bg-2); color: var(--tx-2);
}
.note b { color: var(--tx); }
.note.warn { border-color: rgba(240,185,11,.34); background: rgba(240,185,11,.07); }
.note.danger { border-color: rgba(246,70,93,.36); background: rgba(246,70,93,.07); }
.note.ok { border-color: rgba(14,203,129,.34); background: rgba(14,203,129,.07); }
.note .ni { flex-shrink: 0; font-size: 13px; line-height: 1.4; }

/* ============================================================= 轻量表格 */
.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12px; }
.tbl thead th {
  background: #0d121b; color: var(--tx-3);
  font-size: 10.5px; font-weight: 600; letter-spacing: .5px;
  text-transform: uppercase; text-align: right;
  padding: 8px 12px; border-bottom: 1px solid var(--line-2);
  white-space: nowrap; user-select: none;
}
.tbl thead th.l { text-align: left; }
.tbl thead th.c { text-align: center; }
.tbl tbody td {
  padding: 8px 12px; text-align: right; border-bottom: 1px solid #161c28;
  font-family: var(--mono); font-size: 12px; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.tbl tbody td.l { text-align: left; font-family: inherit; }
.tbl tbody td.c { text-align: center; }
.tbl tbody tr:hover { background: #131a26; }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl .empty-row td { text-align: center; color: var(--tx-3); padding: 30px 12px;
                     font-family: inherit; }

/* 表格里的「自然语言」列：td.l 的 font-family:inherit 会盖掉 .tbl 的等宽，
   但 UA / 说明这类内容还需要允许折行并限宽，否则宽屏下把时间列挤到折行。 */
.tbl td.ua-cells { white-space: normal; max-width: 300px; font-size: 11.5px;
                   color: var(--tx-2); line-height: 1.5; }
/* 会话标识：等宽 + 次要色，避免 12 位哈希在表里抢视觉重点 */
.sid { font-family: var(--mono); font-weight: 600; color: var(--tx-2);
       letter-spacing: .2px; }
.b-desc { font-size: 11.5px; color: var(--tx-2); }
.b-issue { display: flex; align-items: flex-start; gap: 6px; margin-top: 4px;
           font-size: 11.5px; color: var(--amber); }
.b-issue .ico { width: 13px; height: 13px; margin-top: 2px; }

.tag {
  display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .3px;
  padding: 1.5px 6px; border-radius: 4px; margin-right: 3px;
  font-family: -apple-system, "Segoe UI", sans-serif;
}
/* 交易**方向**标签（持仓/挂单/成交表里的「多 / 空」）：多=绿、空=红。
   ⚠️ 别用 .tag-short 当方向标签 —— 它在本项目里同时兼作"正常/已就绪"通用标签
      （已验证 / 已绑定 / 就绪 / 未停用 都用它），把方向语义压上去会连累一堆无关的绿色。
      所以方向另开两个专用类，色值仍只来自 :root 的 --side-*。 */
.tag-side-long { background: rgba(14,203,129,.16); color: var(--side-long);
                 border: 1px solid rgba(14,203,129,.32); }
.tag-side-short { background: rgba(246,70,93,.16); color: var(--side-short);
                  border: 1px solid rgba(246,70,93,.32); }
.tag-short { background: rgba(14,203,129,.16); color: var(--down);
             border: 1px solid rgba(14,203,129,.32); }
.tag-gray { background: rgba(93,100,120,.16); color: var(--tx-3);
            border: 1px solid var(--line-2); }
.tag-amber { background: rgba(240,185,11,.16); color: var(--amber);
             border: 1px solid rgba(240,185,11,.32); }
.tag-cyan { background: rgba(34,195,214,.14); color: var(--cyan);
            border: 1px solid rgba(34,195,214,.3); }

/* ============================================================= 交易页 */
/* 左栏 300px（原 330px）：下单面板的信息密度靠"一行放完"来提，
   不靠加宽 —— 加宽只会让右表更挤，而面板本身纵向就能收进一屏。 */
.trade-layout { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 14px; }
@media (max-width: 1080px) { .trade-layout { grid-template-columns: minmax(0, 1fr); } }

/* --------------------------------------------------- 下单面板：参数条 */
.ord-bar { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
.chip {
  font: inherit; font-size: 11.5px; font-weight: 600;
  padding: 5px 10px; border-radius: 7px; cursor: pointer; white-space: nowrap;
  border: 1px solid var(--line-2); background: #0d121b; color: var(--tx-2);
  transition: all .14s;
}
.chip:hover:not(:disabled) { color: var(--tx); border-color: #37415a; }
.chip.on { background: rgba(240,185,11,.14); border-color: rgba(240,185,11,.45);
           color: var(--amber); }
.chip.lev { font-family: var(--mono); color: var(--amber);
            border-color: rgba(240,185,11,.35); }
.chip.lev::after { content: ' ⌄'; opacity: .7; }
.chip.ghost { margin-left: auto; color: var(--tx-3); cursor: default; }
.chip.ghost:hover { color: var(--tx-3); border-color: var(--line-2); }
.chip:disabled { opacity: .5; cursor: not-allowed; }

.field > label .lbl-r { float: right; font-family: var(--mono); color: var(--tx-3); }

/* 金额输入：右侧留给「USDT ⌄」（单位选择）与「全部」 */
.amt { position: relative; }
.amt .input { padding-right: 128px; }
.amt-unit {
  position: absolute; right: 58px; top: 50%; transform: translateY(-50%);
  font: inherit; font-size: 11px; padding: 2px 6px; border-radius: 5px;
  border: 1px solid transparent; background: transparent; color: var(--tx-2);
  cursor: pointer;
}
.amt-unit:hover, .amt-unit.on { border-color: var(--line-2); color: var(--amber); }
.amt-max {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  font: inherit; font-size: 11px; padding: 2px 7px; border-radius: 5px;
  border: 1px solid var(--line-2); background: transparent; color: var(--tx-2);
  cursor: pointer;
}
.amt-max:hover { color: var(--amber); border-color: rgba(240,185,11,.42); }

/* 单位选择浮层（订单金额 / 初始保证金）。
   ⚠️ 必须有 pop-mask：否则点别处不关、且浮层会挡住下面的滑块与按钮。 */
.pop-mask { position: fixed; inset: 0; z-index: 18; }
.unit-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 19;
  width: 268px; padding: 10px 10px 6px;
  background: var(--panel-2); border: 1px solid var(--line-2);
  border-radius: 10px; box-shadow: 0 16px 40px rgba(0,0,0,.5);
}
.up-h { font-size: 11px; color: var(--tx-3); letter-spacing: .3px; margin-bottom: 7px; }
.up-row {
  display: flex; gap: 8px; align-items: flex-start; width: 100%;
  text-align: left; font: inherit; cursor: pointer;
  background: transparent; border: 1px solid var(--line-2);
  border-radius: 8px; padding: 8px 9px; margin-bottom: 6px;
}
.up-row:hover { border-color: #37415a; }
.up-row.on { border-color: rgba(240,185,11,.5); background: rgba(240,185,11,.05); }
.up-row b { display: block; font-size: 12px; color: var(--tx); }
.up-row i {
  display: block; font-style: normal; font-size: 10.5px; line-height: 1.5;
  color: var(--tx-3); margin-top: 2px;
}
.up-radio {
  width: 12px; height: 12px; margin-top: 2px; flex-shrink: 0;
  border-radius: 50%; border: 1.5px solid var(--line-2);
}
.up-row.on .up-radio {
  border-color: var(--amber);
  background: radial-gradient(circle, var(--amber) 0 42%, transparent 48%);
}

/* 百分比滑块（下单面板 / 杠杆弹窗共用；`.rng-a` 是合约页在用的旧名，不动它） */
input[type="range"].rng {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 14px; background: transparent; margin: 7px 0 0;
  cursor: pointer; outline: none;
}
input[type="range"].rng::-webkit-slider-runnable-track {
  height: 3px; border-radius: 2px; background: #2a3450;
}
input[type="range"].rng::-webkit-slider-thumb {
  -webkit-appearance: none; width: 12px; height: 12px; margin-top: -4.5px;
  border-radius: 50%; background: var(--amber); border: 2px solid #0d121b;
}
.pct-ticks, .lev-ticks { display: flex; justify-content: space-between; }
.pct-ticks button, .lev-ticks button {
  font: inherit; font-size: 10px; color: var(--tx-3);
  background: none; border: 0; padding: 1px 0; cursor: pointer;
}
.pct-ticks button:hover, .lev-ticks button:hover { color: var(--amber); }
.lev-ticks button { font-family: var(--mono); font-size: 10.5px; }
.lev-ticks button.on { color: var(--amber); font-weight: 700; }

/* 止盈止损折叠开关：不设的时候不该占两行高度 */
.tpsl-toggle {
  display: flex; align-items: center; gap: 7px; margin: 0 0 10px;
  font-size: 11.5px; color: var(--tx-2); cursor: pointer; user-select: none;
}
.tpsl-toggle input { accent-color: var(--amber); width: 13px; height: 13px;
                     margin: 0; cursor: pointer; }
.tpsl-toggle .lbl-r { margin-left: auto; color: var(--tx-3); font-size: 11px; }

.lev-row { display: flex; flex-wrap: wrap; gap: 5px; }
.lev-row button {
  font: inherit; font-size: 11.5px; font-weight: 600;
  padding: 4px 9px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--panel-2); color: var(--tx-2);
  transition: all .14s;
}
.lev-row button:hover { color: var(--tx); border-color: #37415a; }
.lev-row button.on { background: rgba(240,185,11,.16); color: var(--amber);
                     border-color: rgba(240,185,11,.45); }

/* 杠杆/保证金滑块 */
input[type="range"].rng-a { width: 100%; }

.summary-box {
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 8px; padding: 10px; margin-bottom: 12px;
}
.summary-box .sb-row {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 11.5px; padding: 3px 0; color: var(--tx-2);
}
.summary-box .sb-row b { font-family: var(--mono); font-size: 12px; color: var(--tx); }
.summary-box .sb-row.hl b { color: var(--amber); font-size: 13px; }
/* 下单面板里的摘要更紧凑：这是"看一眼就能下单"的信息，不是报表 */
.trade-layout .summary-box { padding: 9px 10px; margin-bottom: 10px; }
.trade-layout .summary-box .sb-row { padding: 2px 0; font-size: 11px; }

/* --------------------------------------------------- 调整杠杆（弹窗）
   桌面端做成居中小卡片：手机上 OKX 是底部抽屉，但这里是 1600px 宽的桌面端，
   抽屉式的远距离移动反而难用。 */
.modal-mask {
  position: fixed; inset: 0; z-index: 120; padding: 20px;
  background: rgba(4,7,12,.62);
  display: flex; align-items: center; justify-content: center;
}
.modal {
  width: 386px; max-width: 100%; max-height: 100%; overflow: auto;
  background: var(--panel); border: 1px solid var(--line-2);
  border-radius: 12px; box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.modal-h {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 14px; border-bottom: 1px solid var(--line);
}
.modal-h h3 { margin: 0; font-size: 13.5px; font-weight: 650; }
.modal-h .sub { font-size: 11px; color: var(--tx-3); font-family: var(--mono); }
.modal-h .x { margin-left: auto; }
.modal-b { padding: 14px; display: flex; flex-direction: column; gap: 11px; }

.lev-stepper {
  display: flex; align-items: center; gap: 6px;
  background: #0d121b; border: 1px solid var(--line-2);
  border-radius: 9px; padding: 5px;
}
.lev-stepper button {
  width: 36px; height: 32px; flex-shrink: 0; border: 0; border-radius: 7px;
  background: transparent; color: var(--tx-2); font-size: 17px; line-height: 1;
  cursor: pointer;
}
.lev-stepper button:hover:not(:disabled) { background: var(--panel-2); color: var(--tx); }
.lev-stepper button:disabled { opacity: .3; cursor: not-allowed; }
.lev-stepper input {
  flex: 1; min-width: 0; text-align: center; border: 0; outline: none;
  background: transparent; color: var(--tx);
  font-family: var(--mono); font-size: 19px; font-weight: 700;
}
/* 数字输入框的上下箭头：窄框里既挤又容易误触，去掉（仍可键盘上下调） */
.lev-stepper input::-webkit-outer-spin-button,
.lev-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.lev-slider { padding: 0 2px; }
.ma-note { font-size: 11px; color: var(--tx-3); line-height: 1.75; }
.ma-note b { color: var(--tx-2); font-family: var(--mono); }
.ma-row { display: flex; align-items: center; gap: 10px; }
.ma-row .l { font-size: 11.5px; color: var(--tx-2); }
.ma-def {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 0 3px; border-top: 1px solid var(--line);
  font-size: 11.5px; color: var(--tx-2);
}
.ma-def b { margin-left: auto; font-family: var(--mono); color: var(--amber); }

.pos-actions { display: flex; gap: 5px; justify-content: flex-end; }

.bar-mini { height: 3px; border-radius: 2px; background: var(--line-2);
            overflow: hidden; margin-top: 4px; }
.bar-mini i { display: block; height: 100%; background: var(--amber); }

/* ============================================================= 币安合约看盘 */
/* 左：账户持仓；右：合约图表。左栏定宽 —— 表格列宽需要稳定的落点，
   用 fr 会让「持仓量」这类长数字把别的列挤到换行。
   实际宽度由 JS 写进 inline style（可拖动调节），这里的 438px 只是首帧兜底。

   ⚠️ 两栏之间用「一整列分隔条」承载拖拽，而不是靠 grid 的 gap ——
      gap 是空白，没有可抓取的热区。列间距因此设为 0，视觉间距由分隔条自己提供。 */
.futures {
  display: grid;
  /* ⚠️ 列模板用 CSS 变量承载宽度，**不要**用 inline 的 grid-template-columns ——
     inline 样式优先级高于样式表，会把下面媒体查询里的单列规则压掉，
     窄屏下会硬生生挤成三列。变量只是「数据」，列模板始终由样式表决定。 */
  grid-template-columns: var(--fut-left, 438px) var(--fut-split-w, 14px) minmax(0, 1fr);
  column-gap: 0; row-gap: 14px; align-items: start;
  /* ⚠️ 本页用「绿涨红跌」（用户要求，与币安 App 惯例一致）；
     站点其它页面仍是中式「红涨绿跌」。在这里覆写 --up/--down，
     页面内所有 var(--up)/var(--down) 以及 .up/.down 类（卡头价格、涨跌幅、
     持仓收益与收益率、资金费率）会一起翻转。
     必须与 web/js/chart.js 顶部的 UP/DOWN 常量保持一致 —— 否则会出现
     「卡头红了表示涨、K 线却绿了表示涨」这种自相矛盾。 */
  --up: #0ecb81;
  --down: #f6465d;
}
@media (max-width: 1240px) {
  .futures { grid-template-columns: minmax(0, 1fr); }
  .fut-split { display: none; }   /* 单列时不需要分隔条（display:none 不占网格轨道） */
}

/* 分隔条：拖动调节左右宽度。双击恢复默认、←/→ 微调（见 futures.js） */
.fut-split {
  position: relative; align-self: stretch;   /* 必须 stretch —— 否则只有 grip 那点高度可抓 */
  cursor: col-resize; touch-action: none; outline: none;
}
.fut-split::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%;
  width: 1px; margin-left: -.5px; background: var(--line-2);
}
/* ⚠️ grip 用 sticky 而不是「垂直居中」：
   分隔条的高度 = 两栏中较高的那一栏（降级成候选池时左边能有 1500px+），
   垂直居中会把 grip 推到 y≈840 —— 首屏根本看不到，等于没有抓手。
   sticky + 顶部偏移让它始终停在视口内，滚动时也不会跑掉。
   ⚠️ 颜色同理：--line-2(#2a3346) 在 #0b0e14 底上几乎看不见，所以用 --tx-3(#5d6478)。 */
.fut-split .grip {
  position: sticky; top: 120px;
  display: block; width: 5px; height: 38px;
  margin: 150px auto 0; border-radius: 3px;
  background: var(--tx-3); opacity: .75;
}
.fut-split:hover::before,        .fut-split.on::before { background: var(--amber); }
.fut-split:hover .grip,          .fut-split.on .grip   { background: var(--amber); opacity: 1; }
.fut-split:focus-visible::before { background: var(--amber); }
.fut-split:focus-visible .grip   { background: var(--amber); opacity: 1; }
.futures.dragging { cursor: col-resize; }

.fut-col > .card { margin-top: 0; }
.fut-col > .card + .card,
.fut-col > .card + .note { margin-top: 14px; }
.fut-col > .note { margin-top: 14px; }

/* 账户摘要（权益 / 可用 / 未实现盈亏） */
.acct-strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.acct-strip .as {
  padding: 9px 10px; background: #0d121b;
  border: 1px solid var(--line); border-radius: 8px;
}
.acct-strip .as .l { font-size: 10.5px; color: var(--tx-3); letter-spacing: .2px; }
.acct-strip .as .v { font-family: var(--mono); font-size: 13px; margin-top: 3px; }

/* 持仓表：整行可点选（切换右栏图表），故用更紧凑的字号与内边距 */
.fut-pos .tbl { font-size: 11.5px; }
.fut-pos .tbl thead th { padding: 7px 6px; }
.fut-pos .tbl tbody td { padding: 7px 6px; }
.fut-pos .tbl tbody tr { cursor: pointer; }
.fut-pos .tbl tbody tr.on { background: rgba(240,185,11,.075); }
.fut-pos .tbl tbody tr.on td:first-child { box-shadow: inset 2px 0 0 var(--amber); }
.fut-pos .tbl tbody td .tag { margin-left: 4px; padding: 1px 4px; font-size: 10px; }

.fut-pool-h { font-size: 11px; color: var(--tx-3); padding: 0 2px 7px;
              display: flex; flex-wrap: wrap; gap: 2px 8px; }
/* 候选池价格来自监控快照、图表价格来自 24hr ticker —— 两者抓取时刻不同，
   必须显式说明，否则用户会以为是同一个数值出了 bug */
.fut-pool-note { color: #4a5164; }

/* 图表卡头 */
.fut-head { flex-wrap: wrap; row-gap: 6px; }
.fut-head h3 { font-family: var(--mono); font-size: 14px; }
.fut-px { font-family: var(--mono); font-size: 15px; font-weight: 650; margin-left: 2px; }
.fut-px.up, .fut-chg.up { color: var(--up); }
.fut-px.down, .fut-chg.down { color: var(--down); }
.fut-chg { font-family: var(--mono); font-size: 12px; }
.fut-sym { width: 122px; padding: 4px 8px; font-size: 11.5px; }
.seg.fut-iv button { padding: 4px 11px; font-size: 11.5px; }
/* 刷新档位：文案比周期长（"30秒" vs "4小时"），但按钮更多，收紧一点padding */
.seg.fut-rf button { padding: 4px 8px; font-size: 11px; }

/* 图例（EMA 现值与偏离度） */
.fut-legend { display: flex; flex-wrap: wrap; gap: 7px; padding: 11px 14px 0; }
.fut-legend .lg {
  font-family: var(--mono); font-size: 11.5px; padding: 3px 9px; border-radius: 6px;
  background: #0d121b; border: 1px solid var(--line); white-space: nowrap;
}
.fut-legend .lg i { font-style: normal; opacity: .78; }
.fut-legend .lg-note { color: var(--tx-3); font-family: inherit; }
/* 「正在加载更早的 K 线…」/ 加载失败 —— 拖到最左自动翻历史时的状态提示 */
.fut-legend .lg-loading { color: var(--amber); border-color: rgba(240, 185, 11, .35); }

/* 图表底板 */
.kchart { position: relative; width: 100%; background: #0b0e14;
          border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.kc-base, .kc-over { position: absolute; left: 0; top: 0; display: block; }
.kc-over { cursor: crosshair; touch-action: none; }   /* touch-action: 指针拖拽平移要用 */
.kc-over.kc-drag { cursor: grabbing; }
.kc-empty {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; color: var(--tx-3); font-size: 12.5px;
}
/* 缩放工具条（悬浮在图表右上角）。滚轮缩放与拖动平移是主用法，
   这三个按钮是给「不想记手势」时用的，同时也是功能可发现性的提示。 */
.kc-tools {
  position: absolute; top: 4px; right: 4px; z-index: 3;
  display: flex; gap: 3px; padding: 2px; border-radius: 7px;
  background: rgba(11,14,20,.72);
}
.kc-tb {
  width: 22px; height: 22px; padding: 0; line-height: 1;
  border: 1px solid var(--line); border-radius: 5px;
  background: #0d121b; color: var(--tx-2);
  font-size: 12px; font-family: inherit; cursor: pointer;
}
.kc-tb:hover { border-color: var(--amber); color: var(--amber); }

/* 图表下边缘的水平分隔条：上下拖动调图表高度（双击恢复默认）。
   与图表同底色，看起来是图表的一部分；抓手用 --tx-3 才在深底上看得出来。 */
.fut-hsplit {
  height: 13px; display: flex; align-items: center; justify-content: center;
  cursor: ns-resize; touch-action: none; background: #0b0e14;
}
.fut-hsplit .grip-h {
  width: 46px; height: 4px; border-radius: 2px;
  background: var(--tx-3); opacity: .7;
}
.fut-hsplit:hover .grip-h, .fut-hsplit.on .grip-h { background: var(--amber); opacity: 1; }

/* 图表底部指标条 */
.fut-foot {
  display: flex; flex-wrap: wrap; gap: 6px 18px; padding: 10px 14px;
  font-size: 11.5px; color: var(--tx-3);
}
.fut-foot b { font-family: var(--mono); font-weight: 500; color: var(--tx-2); }
.fut-foot b.up { color: var(--up); }
.fut-foot b.down { color: var(--down); }
.fut-foot .right-side { margin-left: auto; }
.fut-warn { color: var(--amber); margin-right: 10px; }

/* ============================================================= 登录页 */
/* 纯黑底太平、也看不出这是「交易终端」。背景由 5 层纯 CSS 叠出来（零图片文件）：
     ① 顶部一道金线渐隐（品牌收口）
     ② 中心聚焦暗角：四周压暗，视线被推回卡片
     ③ 底部一排极淡的 K 线 + EMA 折线剪影（内联 SVG，repeat-x 随窗口平铺）
     ④ 三团品牌色柔光 violet / cyan / amber（取色自 :root）
     ⑤ 深蓝黑基底
   ::before 再做一层「极光缓慢漂移」，只动 transform（GPU 合成，不触发重排）。
   ⚠️ 光斑 alpha 一律 ≤ .17：再高卡片边缘就会发灰、黑底变脏。
   ⚠️ K 线层要压在柔光之上、暗角之下：剪影像是「从金色地平线里长出来」的，
      两端多余的蜡烛又会被暗角自然收掉，不必额外做横向遮罩。 */
.auth-wrap {
  position: relative; min-height: 100vh; overflow: hidden;
  display: grid; place-items: center; padding: 24px;
  background:
    linear-gradient(90deg, transparent,
                    rgba(240,185,11,.42) 50%, transparent) top / 100% 1px no-repeat,
    radial-gradient(140% 118% at 50% 42%, transparent 42%, rgba(4,6,11,.62) 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='720' height='360' viewBox='0 0 720 360'%3E%3Cg opacity='0.42'%3E%3Cpolyline points='40,258 110,232 180,232 250,202 320,200 390,172 460,170 530,140 600,142 670,114' fill='none' stroke='%23f0b90b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cg stroke-width='2.5'%3E%3Cline x1='40' y1='210' x2='40' y2='300' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='29' y='230' width='22' height='55' rx='2' fill='%23f6465d' opacity='.62'/%3E%3Cline x1='110' y1='185' x2='110' y2='275' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='99' y='205' width='22' height='50' rx='2' fill='%23f6465d' opacity='.62'/%3E%3Cline x1='180' y1='200' x2='180' y2='262' stroke='%230ecb81' opacity='.5'/%3E%3Crect x='169' y='212' width='22' height='42' rx='2' fill='%230ecb81' opacity='.62'/%3E%3Cline x1='250' y1='160' x2='250' y2='245' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='239' y='175' width='22' height='52' rx='2' fill='%23f6465d' opacity='.62'/%3E%3Cline x1='320' y1='176' x2='320' y2='232' stroke='%230ecb81' opacity='.5'/%3E%3Crect x='309' y='184' width='22' height='36' rx='2' fill='%230ecb81' opacity='.62'/%3E%3Cline x1='390' y1='135' x2='390' y2='215' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='379' y='150' width='22' height='48' rx='2' fill='%23f6465d' opacity='.62'/%3E%3Cline x1='460' y1='148' x2='460' y2='202' stroke='%230ecb81' opacity='.5'/%3E%3Crect x='449' y='156' width='22' height='32' rx='2' fill='%230ecb81' opacity='.62'/%3E%3Cline x1='530' y1='105' x2='530' y2='190' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='519' y='118' width='22' height='48' rx='2' fill='%23f6465d' opacity='.62'/%3E%3Cline x1='600' y1='120' x2='600' y2='174' stroke='%230ecb81' opacity='.5'/%3E%3Crect x='589' y='128' width='22' height='32' rx='2' fill='%230ecb81' opacity='.62'/%3E%3Cline x1='670' y1='80' x2='670' y2='158' stroke='%23f6465d' opacity='.5'/%3E%3Crect x='659' y='92' width='22' height='46' rx='2' fill='%23f6465d' opacity='.62'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")
      bottom center / auto 30% repeat-x,
    radial-gradient(1150px 760px at 78% 6%,   rgba(125,140,255,.17), transparent 62%),
    radial-gradient(940px 640px at 6% 88%,    rgba(34,195,214,.12),  transparent 62%),
    radial-gradient(1100px 700px at 50% 124%, rgba(240,185,11,.17),  transparent 64%),
    linear-gradient(165deg, #0d1220 0%, #0a0e18 46%, #070a11 100%);
}
.auth-wrap::before {                      /* 极光：两团柔光缓慢漂移 */
  content: ''; position: absolute; inset: -30%; pointer-events: none;
  background:
    radial-gradient(circle closest-side at 32% 40%, rgba(240,185,11,.10), transparent),
    radial-gradient(circle closest-side at 68% 62%, rgba(125,140,255,.13), transparent);
  animation: auth-aurora 34s ease-in-out infinite alternate;
}
@keyframes auth-aurora {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to   { transform: translate3d(4%, 4%, 0) scale(1.15); }
}
.auth-wrap::after {                       /* 细网格（只在卡片周围可见） */
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(148,163,184,.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(148,163,184,.06) 1px, transparent 1px);
  background-size: 46px 46px;
  -webkit-mask-image: radial-gradient(760px 540px at 50% 42%, #000 0%, transparent 78%);
  mask-image: radial-gradient(760px 540px at 50% 42%, #000 0%, transparent 78%);
}
@media (prefers-reduced-motion: reduce) { /* 尊重系统「减少动态效果」设置 */
  .auth-wrap::before { animation: none; }
}
.auth-card {
  position: relative; z-index: 1;
  width: 100%; max-width: 400px; background: var(--panel);
  border: 1px solid rgba(240,185,11,.20); border-radius: 14px;
  box-shadow: 0 26px 70px rgba(0,0,0,.62),
              0 0 0 1px rgba(255,255,255,.02) inset,
              0 0 44px rgba(240,185,11,.05);
  overflow: hidden;
}
.auth-card::before {                      /* 卡片顶部金边高光 */
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(240,185,11,.8), transparent);
}
.auth-head { padding: 26px 24px 18px; text-align: center; }
.auth-head .logo { width: 44px; height: 44px; border-radius: 11px; margin-bottom: 12px; }
.auth-head h2 { margin: 0 0 4px; font-size: 17px; font-weight: 680; letter-spacing: .2px; }
.auth-head p { margin: 0; font-size: 12px; color: var(--tx-3); }
.auth-body { padding: 0 24px 22px; }
.auth-tabs { display: flex; gap: 4px; margin-bottom: 18px;
             background: #0d121b; padding: 3px; border-radius: 9px; }
.auth-tabs button {
  flex: 1; font: inherit; font-size: 12.5px; font-weight: 600;
  padding: 7px; border-radius: 6px; cursor: pointer;
  border: 0; background: transparent; color: var(--tx-2);
}
.auth-tabs button.on { background: var(--panel-2); color: var(--tx); }
.auth-foot { padding: 12px 24px 18px; font-size: 11px; color: var(--tx-3);
             text-align: center; border-top: 1px solid var(--line); line-height: 1.6; }

/* 验证码行：输入框 + 「发送验证码」（带 60 秒倒计时） */
.code-row { display: flex; gap: 8px; align-items: stretch; }
.code-row .input { flex: 1; min-width: 0; letter-spacing: 2px; }
.code-row .btn { flex: 0 0 auto; white-space: nowrap;
                 font-variant-numeric: tabular-nums; min-width: 92px; }

/* 次级操作（忘记密码 / 返回上一步） */
.auth-aux { display: flex; align-items: center; gap: 10px; margin: -4px 0 14px; }
.auth-aux .spacer { flex: 1; }
.link-btn {
  font: inherit; font-size: 11.5px; padding: 0; border: 0; background: none;
  color: var(--amber); cursor: pointer;
}
.link-btn:hover:not(:disabled) { text-decoration: underline; }
.link-btn:disabled { color: var(--tx-3); cursor: default; }

/* ============================================================= 杂项 */
.spinner {
  width: 15px; height: 15px; border-radius: 50%; display: inline-block;
  border: 2px solid var(--line-2); border-top-color: var(--amber);
  animation: spin .7s linear infinite; vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loading-box { padding: 46px 20px; text-align: center; color: var(--tx-3); font-size: 12.5px; }
.loading-box .spinner { width: 22px; height: 22px; border-width: 2.5px; margin-bottom: 10px; }

.kv-list { display: flex; flex-direction: column; }
.kv-list .kv {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 8px 0; border-bottom: 1px solid #161c28; font-size: 12px;
}
.kv-list .kv:last-child { border-bottom: 0; }
.kv-list .kv > span:first-child { color: var(--tx-2); flex-shrink: 0; }
.kv-list .kv > b { font-family: var(--mono); text-align: right; word-break: break-all; }

.copy-row { display: flex; align-items: center; gap: 8px; }
.copy-row code {
  font-family: var(--mono); font-size: 11.5px; color: var(--cyan);
  background: #0d121b; border: 1px solid var(--line); border-radius: 6px;
  padding: 5px 9px; flex: 1; overflow-x: auto; white-space: nowrap;
}

.pulse-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block;
             background: var(--down); box-shadow: 0 0 0 3px rgba(14,203,129,.15); }
.pulse-dot.busy { background: var(--amber); box-shadow: 0 0 0 3px rgba(240,185,11,.18);
                  animation: pulse 1s ease-in-out infinite; }
.pulse-dot.err { background: var(--up); box-shadow: 0 0 0 3px rgba(246,70,93,.18); }

@media (max-width: 860px) {
  /* 窄屏：侧边栏浮层退化为图标条。
     ⚠️ --rail-w 必须同步改小 —— 侧边栏宽度与 .app.rail-pinned .main 的
        margin-left 都取自它，只改一边就会留下一条空白。 */
  :root { --rail-w: 62px; }
  .side-brand { justify-content: center; padding: 12px 6px; }
  .side-brand .t, .side-pin, .nav-group,
  .nav-item span.lbl, .user-card .u, .user-card .icon-btn { display: none; }
  .nav-item { justify-content: center; padding: 10px 0; }
  .nav-item .badge { display: none; }
  .side-foot { padding: 8px; }
  .user-card { justify-content: center; padding: 6px; }
  .page { padding: 12px; }
}
/* ---------------- 用户与权限 / 审计（P1/P2 新增页） ----------------
   ⚠️ 只放这两页独有的类；卡片 / 表格 / 标签 / 提示一律复用 .card .tbl .tag .note，
      不再造第二套（两个样式表分工见文件头与本文件顶部的说明）。 */
.pg-mini { font-size: 11.5px; color: var(--tx-3); line-height: 1.5; }
.role-sel { min-width: 104px; padding: 3px 6px; font-size: 12px; }

/* ---- 用户与权限的**一级页签**（账户 / 角色），2026-09-27 用户要求拆开
   ⚠️⚠️ 类名 **新造**（.ustabs / .ut），**绝不**复用：
      · `.viewtabs` / `.vt` —— 顶层页签断言按它们计数，本项目四处自测钉着 `nVt === 4`；
      · `.simtabs` / `.stb` —— 那是「量化模拟」专属子页签，语义不同，借来会误导。
   视觉上比顶层页签**实一档**（它是本页唯一的导航，不该看着像可选装饰）：
   底部一条琥珀下划线标记当前项，右侧留 hint 位放「本页签在做什么」。 */
.ustabs {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.ustabs .ut {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 13px; font-weight: 600;
  padding: 6px 13px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--tx-3);
  transition: background .15s, color .15s, border-color .15s;
}
.ustabs .ut:hover { color: var(--tx-2); background: var(--panel); }
.ustabs .ut.on {
  background: var(--panel-2); color: var(--tx);
  border-color: var(--line-2); box-shadow: inset 0 -2px 0 var(--amber);
}
.ustabs .ut .ico { width: 14px; height: 14px; opacity: .85; }
.ustabs .ut.on .ico { color: var(--amber); opacity: 1; }
/* 计数徽标：账户 / 角色 各显示自己的条数，省得进页签才知道有几个 */
.ustabs .ut .ut-n {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  padding: 1px 6px; border-radius: 9px;
  background: var(--bg-2); color: var(--tx-3); border: 1px solid var(--line);
}
.ustabs .ut.on .ut-n { color: var(--amber); border-color: rgba(240, 185, 11, .3); }
.ustabs .ut-hint {
  margin-left: auto; font-size: 11.5px; color: var(--tx-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- 账户搜索条（用户名 / uid / 邮箱，空格分词 AND）
   放在卡片头里，跟「刷新」同一条基线；窄屏自动折行。 */
.acc-search { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.acc-search .as-input {
  font: inherit; font-size: 12px; color: var(--tx);
  background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 8px;
  padding: 5px 10px 5px 28px; min-width: 210px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235d6478' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 8px center; background-size: 13px 13px;
}
.acc-search .as-input::placeholder { color: var(--tx-3); }
.acc-search .as-input:focus { outline: none; border-color: var(--amber);
  box-shadow: 0 0 0 3px rgba(240, 185, 11, .12); }
.acc-search .as-clear {
  font: inherit; font-size: 11.5px; cursor: pointer;
  background: transparent; border: 1px solid var(--line-2); border-radius: 7px;
  color: var(--tx-3); padding: 4px 9px;
}
.acc-search .as-clear:hover { color: var(--tx); border-color: var(--tx-3); }
.acc-search .as-hit { font-size: 11.5px; color: var(--tx-3); }
.acc-search .as-hit b { color: var(--amber); font-family: var(--mono); }

/* ---------------- 角色权限编辑器（2026-09-27：角色可自定义，权限按「模块 → 页签」两级勾选）
   ⚠️ 只加「模块/页签两级勾选」需要的版式；卡片 / 表格 / 标签 / 提示一律复用
      .card .tbl .tag .note .input，不再造第二套。 */
.perm-editor .pe-head { display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap; margin-bottom: 12px; }
.perm-editor .pe-lab { font-size: 12px; color: var(--tx-2); white-space: nowrap; }
.perm-editor .perm-key { font-family: var(--mono); font-size: 11px; color: var(--tx-3);
  background: var(--bg-2, rgba(127, 127, 127, .1)); border-radius: 4px; padding: 1px 5px; }
.pt-list { display: flex; flex-direction: column; gap: 10px; }
.pt-mod { border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.pt-mod-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pt-chk { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.pt-chk input { width: 14px; height: 14px; accent-color: var(--amber); cursor: pointer; }
/* 页签行：缩进 + 左侧一条细线，一眼看出层级（不靠颜色区分） */
.pt-tabs { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 8px 0 2px 22px;
  padding-left: 10px; border-left: 2px solid var(--line); }
.pt-tab { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12px; color: var(--tx-2); }
.pt-tab input { width: 13px; height: 13px; accent-color: var(--amber); cursor: pointer; }
.audit-deny { color: var(--danger); font-weight: 600; }
.deny-box { max-width: 760px; }
.deny-box code { font-family: var(--mono); font-size: 11.5px;
  background: var(--panel-2); padding: 1px 5px; border-radius: 4px; }
.perm-matrix td.l { vertical-align: top; }
.perm-matrix .pg-mini { font-weight: 400; }
/* 编辑器别横向拉满：一行读 1500px 会看丢勾选状态（权限勾错就是真出事）。
   1200px 是「模块行 + 页签行 + 键名 + 说明」四段还能一眼扫完的宽度上限。 */
.perm-editor { max-width: 1200px; }
/* 页签面板的最小高度：账户表短的时候不要一点「角色」整页跳一下 */
.upane { min-height: 220px; }
@media (max-width: 860px) {
  .ustabs .ut-hint { display: none; }
  .acc-search .as-input { min-width: 0; flex: 1; }
}

/* ---------------- 模拟交易页（合约列表 + 快捷下单） ----------------
   ⚠️ 只加「这一页独有」的类；右栏图表、分栏拖拽、卡片/表格/标签
      全部复用 `.futures` / `.kchart` / `.card` / `.tbl` / `.tag`（右栏是同一个组件）。
   本页也在 `.futures` 里，所以**涨跌色是绿涨红跌**（见上面 .futures 的说明），
      强平价这类"警示但非涨跌"的数字用 --amber，别用 --up（那在本页是绿）。 */

/* 搜索框 + 四个视角的页签 */
.st-search { font-family: inherit; }
.st-tabs { display: flex; gap: 3px; }
.st-tabs button { font-size: 11.5px; padding: 5px 6px; }
.st-tabs .cnt {
  font-family: var(--mono); font-size: 10px; opacity: .75; margin-left: 2px;
}

/* 列表容器：200 个合约不能把页面撑到几千像素 —— 卡片内部滚动。
   ⚠️ 高度用视口减固定偏移，保证「左栏列表」与「右栏图表」首屏都在视野里；
      不用 max-height:100% 之类，因为 .fut-col 的高度由内容决定（没有确定高度）。
   滚动条走深色细样式（用户 2026-09-24：白色粗滚动条太扎眼，参照币安的细条）；
   横向滚动条直接关掉 —— 列数收敛后表格不该比容器宽，宽了说明内容有问题。 */
.st-list {
  max-height: calc(100vh - 330px);
  /* ⚠️ 不能写 `overflow: auto hidden` 两值简写 —— 用户的 Chrome 不认，
     整条声明作废 → overflow 回到 visible，纵向滚动直接消失（2026-09-24 实测）。
     必须逐轴写。 */
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;                  /* Firefox */
  scrollbar-color: #333d4d transparent;
}
/* ---------------------------------------------- 细深色滚动条（共用一处）
   2026-09-24 用户反馈「白色粗滚动条太扎眼，参照币安的细条」。
   ⚠️⚠️ 这里只留**一份**数值。历史上每个页面各挂一遍选择器，结果
      「数据分析面板 .an-scroll 又漏了」→ 用户截图抓到右侧白条。
      2026-09-27 收敛成 `.scroll-thin` 一个类：**新容器一律挂它**，
      旧容器（.st-list/.cx-scroll/.an-scroll）保留在列表里兼容，不再新增。
   ⚠️ 光写 ::-webkit-scrollbar 不够 —— Firefox 只认 scrollbar-width/color，
      所以两类属性一起给（前者管 Chrome/Edge/Safari，后者管 Firefox）。
   ⚠️ track 必须 transparent 而不是某个色值：滚动条底槽上色后，
      即使没有滚动也会在容器右缘留一条暗带，看着像「多了一列」。 */
.scroll-thin,
.st-list, .cx-scroll, .an-scroll {
  scrollbar-width: thin;                  /* Firefox */
  scrollbar-color: var(--line-2) transparent;
}
.scroll-thin::-webkit-scrollbar,
.st-list::-webkit-scrollbar, .cx-scroll::-webkit-scrollbar, .an-scroll::-webkit-scrollbar {
  width: 8px; height: 8px;
}
.scroll-thin::-webkit-scrollbar-track,
.st-list::-webkit-scrollbar-track, .cx-scroll::-webkit-scrollbar-track, .an-scroll::-webkit-scrollbar-track {
  background: transparent;
}
/* 拇指：默认比轨道深一档、圆角；hover 再亮一档。
   8px 宽 + 3px 透明边框（background-clip: content-box）＝视觉 4px 细条，
   但**命中区**仍有 8px —— 太细会点不到（旧值 6px 无边框，拖动偏窄）。 */
.scroll-thin::-webkit-scrollbar-thumb,
.st-list::-webkit-scrollbar-thumb, .cx-scroll::-webkit-scrollbar-thumb, .an-scroll::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border: 2px solid transparent; border-radius: 6px;
  background-clip: content-box;
}
.scroll-thin::-webkit-scrollbar-thumb:hover,
.st-list::-webkit-scrollbar-thumb:hover, .cx-scroll::-webkit-scrollbar-thumb:hover, .an-scroll::-webkit-scrollbar-thumb:hover {
  background: #46536a; background-clip: content-box;
}
.scroll-thin::-webkit-scrollbar-corner,
.st-list::-webkit-scrollbar-corner, .cx-scroll::-webkit-scrollbar-corner, .an-scroll::-webkit-scrollbar-corner {
  background: transparent;
}
/* 横向条高度也压到 8px 并给上边距，免得多行的表格横向滚时贴住内容 */
.scroll-thin::-webkit-scrollbar:horizontal,
.st-list::-webkit-scrollbar:horizontal { height: 8px; }
.st-list .tbl thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel);                     /* 必须不透明，否则滚动时穿透 */
}
.st-list .tbl tbody tr { cursor: pointer; }
.st-list .tbl tbody tr.on { background: rgba(240,185,11,.075); }
.st-list .tbl tbody tr.on td:first-child { box-shadow: inset 2px 0 0 var(--amber); }
/* 30 列宽的行在窄左栏里要能收住，避免把「24h成交额」挤到换行 */
.st-list .tbl td, .st-list .tbl th { padding: 6px 6px; font-size: 11.5px; }

.tag-violet { background: rgba(125,140,255,.16); color: var(--violet);
              border: 1px solid rgba(125,140,255,.32); }

/* 图表悬浮层的定位基准（kchart-panel 的 chart-overlay 插槽外层） */
.kc-wrap { position: relative; }

/* 快捷下单悬浮条（币安式：☰ + 开多@价 + 数量输入 + 开空@价 + ×，浮在图表上，
   可拖动、可收起成右下角小圆签）。类名 .st-quick 是自测锚点，别改。
   2026-09-24 二次收紧：底部 meta 行（杠杆/模式/可用/预估强平/调整杠杆）整体删掉 ——
   杠杆与保证金模式一律用「交易账户」页设的默认，悬浮条只管开仓。 */
.st-quick.qo-float {
  position: absolute; right: 14px; bottom: 14px; z-index: 6;
  padding: 5px 7px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
  user-select: none;
}
.qo-bar { display: flex; align-items: stretch; gap: 5px; }
.qo-handle {
  display: flex; align-items: center; padding: 0 3px;
  color: var(--tx-3); font-size: 12px; cursor: grab; touch-action: none;
}
.qo-handle:active { cursor: grabbing; }
.qo-side {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0; min-width: 78px; padding: 3px 9px;
  border: 0; border-radius: 5px; cursor: pointer; color: #fff;
}
.qo-side i { font-style: normal; font-weight: 600; font-size: 11.5px; line-height: 1.25; }
.qo-side b { font-family: var(--mono); font-weight: 500; font-size: 10.5px; opacity: .92; }
.qo-side.buy { background: var(--up); }      /* .futures 内 --up/--down 已是绿涨红跌 */
.qo-side.sell { background: var(--down); }
.qo-side:disabled { opacity: .6; cursor: default; }
.qo-amt {
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  min-width: 64px; padding: 2px 6px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 5px;
}
.qo-amt label { font-size: 9.5px; color: var(--tx-3); line-height: 1.35; text-align: center; }
.qo-amt input {
  width: 100%; background: transparent; border: 0; outline: none; text-align: center;
  color: var(--tx); font-family: var(--mono); font-size: 12px;
}
.qo-amt input::-webkit-outer-spin-button,
.qo-amt input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qo-close {
  align-self: center; padding: 0 3px; border: 0; background: transparent;
  color: var(--tx-3); font-size: 15px; line-height: 1; cursor: pointer;
}
.qo-close:hover { color: var(--tx); }
/* 收起态：右下角小圆签，点一下重新展开 */
.qo-chip {
  position: absolute; right: 16px; bottom: 16px; z-index: 6;
  padding: 6px 13px; border: 1px solid var(--line-2); border-radius: 999px;
  background: var(--panel); color: var(--amber); font-size: 12px; cursor: pointer;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
}
.qo-chip:hover { border-color: var(--amber); }

/* ============ 图表持仓徽章 + TP/SL（2026-09-24 新功能） ============
   锚定在 .kc-wrap 上，y 由 chart.js 的 geo 事件（lo/hi/padT/plotH）换算。
   徽章 = 左侧盈亏胶囊（盈亏 · ROI · TP/SL · ×）；TP/SL 线已设时带拖动手柄，
   按住手柄（或按住徽章上的 TP/SL）在图上滑动即可改价，松手落账。 */
.pos-layer { position: absolute; inset: 0; z-index: 5; pointer-events: none; }
.pos-layer > * { pointer-events: auto; }
.pos-pill {
  position: absolute; left: 8px; transform: translateY(-50%);
  display: flex; align-items: center; gap: 6px;
  padding: 3px 6px 3px 9px;
  background: rgba(16, 20, 27, .92); border: 1px solid var(--line-2);
  border-radius: 999px; font-size: 11px; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .4);
}
.pos-pill .pp-pnl { font-family: var(--mono); font-weight: 600; }
.pos-pill .pp-roe { font-family: var(--mono); color: var(--tx-3); }
.pos-pill .pp-btn {
  border: 1px solid var(--line-2); background: transparent; border-radius: 999px;
  color: var(--tx-2); font-size: 10.5px; padding: 2px 8px; cursor: pointer;
}
.pos-pill .pp-btn:hover { color: var(--amber); border-color: var(--amber); }
.pos-pill .pp-x {
  border: 0; background: transparent; color: var(--tx-3);
  font-size: 14px; line-height: 1; padding: 0 2px; cursor: pointer;
}
.pos-pill .pp-x:hover { color: var(--down); }
/* TP / SL 线上的拖动手柄 */
.pos-grip {
  position: absolute; left: 8px; transform: translateY(-50%);
  display: flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  font-family: var(--mono); font-size: 10.5px; cursor: ns-resize;
  touch-action: none; user-select: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .4);
}
.pos-grip.tp { background: rgba(14, 203, 129, .16); color: #2ebd85; border: 1px solid rgba(14,203,129,.5); }
.pos-grip.sl { background: rgba(246, 70, 93, .16); color: #f6465d; border: 1px solid rgba(246,70,93,.5); }
.pos-grip .g-ico { font-size: 10px; opacity: .8; }
/* 手柄上的取消按钮：清掉这一侧的止盈/止损（另一侧保持不动） */
.pos-grip .g-x {
  margin-left: 2px; padding: 0 2px; border: 0; background: transparent;
  color: inherit; opacity: .55; font-size: 12px; line-height: 1; cursor: pointer;
}
.pos-grip .g-x:hover { opacity: 1; color: #fff; }
/* 快捷拾取模式：按住 TP/SL 按钮进入，整层接管指针，横线+读数跟鼠标走 */
.pos-pick { position: absolute; inset: 0; z-index: 7; cursor: ns-resize; }
.pos-pick .pk-line {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 1px dashed var(--amber); pointer-events: none;
}
.pos-pick .pk-chip {
  position: absolute; left: 50%; transform: translate(-50%, -50%);
  padding: 3px 10px; border-radius: 6px; white-space: nowrap;
  background: rgba(16, 20, 27, .95); border: 1px solid var(--line-2);
  font-family: var(--mono); font-size: 11px; pointer-events: none;
}
/* 仓位止盈止损弹窗 */
.tpsl-grid { display: flex; flex-direction: column; gap: 10px; }
.tpsl-grid .tp-row { display: flex; gap: 8px; }
.tpsl-grid .tp-cell {
  flex: 1; display: flex; flex-direction: column; gap: 4px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
}
.tpsl-grid .tp-cell.tp { border-left: 3px solid #2ebd85; }
.tpsl-grid .tp-cell.sl { border-left: 3px solid #f6465d; }
.tpsl-grid .tp-cell .l { font-size: 11px; color: var(--tx-2); }
.tpsl-grid .tp-cell input {
  width: 100%; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 6px; color: var(--tx); font-family: var(--mono);
  font-size: 12.5px; padding: 5px 8px; outline: none;
}
.tpsl-grid .tp-cell input:focus { border-color: var(--amber); }
.tpsl-grid .tp-prev { font-size: 11px; color: var(--tx-3); }
.tpsl-grid .tp-prev b { font-family: var(--mono); }
.tpsl-info { font-size: 11px; color: var(--tx-3); line-height: 1.7; }
.tpsl-info b { font-family: var(--mono); color: var(--tx-2); }
@media (max-width: 720px) {
  .qo-bar { flex-wrap: wrap; }
  .qo-amt { flex: 1; }
  .st-list { max-height: none; }
}

/* ============================================================= EMA 交叉监控
   2026-09-25 改版：原「左上涨 / 右下跌」两栏**合并为一页一张表**，
   用上方页签（`.tabs .tab`）切换视图 —— 两栏各占半屏时列挤不下、也不好横向比。

   ⚠️ `.card + .card { margin-top:14px }` 在单栏里不构成问题（只有一张卡），
      但若将来又改回多卡布局，记得在本容器内把它归零（.sec 那段注释踩过）。 */
.cx-card { margin: 14px 18px 0; }
.cx-cnt {
  margin-left: auto; font-family: var(--mono); font-size: 12px; color: var(--tx-2);
}
.cx-hint {
  padding: 7px 14px; font-size: 11.5px; line-height: 1.5;
  border-bottom: 1px solid var(--line); background: var(--bg-2);
}
/* 一屏内滚动：与 .st-list 同款处理（滚动条样式见上面那组 .st-list / .cx-scroll 规则）——
   ⚠️ 不能写 `overflow: auto hidden` 两值简写（用户的 Chrome 会整条丢弃，
      纵向滚动直接消失，2026-09-24 踩过） */
.cx-scroll { overflow-y: auto; overflow-x: hidden; max-height: calc(100vh - 330px); }
/* 表头吸顶：必须不透明，否则滚动时数据行会从下面穿过去 */
.cx-scroll .tbl thead th {
  position: sticky; top: 0; z-index: 2; background: var(--panel);
}
.cx-tbl tbody td { padding: 7px 12px; }
/* 进行中：整行微微提亮，一眼看出「还在走」 */
.cx-tbl tbody tr.open { background: rgba(240, 185, 11, .05); }
.cx-tbl tbody tr.open:hover { background: rgba(240, 185, 11, .085); }
.cx-tbl tbody tr.open td:first-child { box-shadow: inset 2px 0 0 var(--amber); }

/* 分组头 / 噪声抽屉：整行可点（折叠分组、展开抽屉），视觉上比数据行重一档。
   ⚠️⚠️ 对齐必须用**更高特异度**的选择器。`.tbl tbody td { text-align:right }` 特异度是
      (0,1,2)，而这里若只写 `.cx-grp td` 只有 (0,1,1) —— **会被压掉、静默失效**，
      分组头与噪声抽屉双双跑到右边（2026-09-25 用户反馈「分组列表都靠右」）。
      `.cx-tbl tbody tr.cx-grp td` = (0,2,2) 才压得住。别改回 `.cx-grp td`。 */
.cx-grp { cursor: pointer; }
.cx-grp td {
  background: var(--panel-2);
  border-bottom: 1px solid var(--line-2); padding: 7px 12px;
  font-size: 11.5px; color: var(--tx-2);
}
.cx-tbl tbody tr.cx-grp td { text-align: left; }
.cx-grp:hover td { background: #16202e; }
.cx-grp b { color: var(--tx); font-size: 12px; letter-spacing: .2px; }
.cx-grp b, .cx-grp span { margin-right: 10px; }
.cx-caret { display: inline-block; width: 12px; color: var(--tx-3); }
.cx-gn { font-family: var(--mono); color: var(--tx-2); }
/* 分组头里的统计数字：等宽 + 不换行（一组 4 个数并排，别让小数点跳动） */
.cx-gs { font-family: var(--mono); white-space: nowrap; }
.cx-gl { color: var(--tx-3); }
/* ⚠️ `.cx-grp b { color: var(--tx) }` 特异度 (0,1,1) 会盖掉 `.up/.down` 的 (0,1,0)，
   所以分组头里的正负色必须显式放行（值用的是 span，这里再兜一层） */
.cx-tbl tbody tr.cx-grp .cx-gs .up { color: var(--up); }
.cx-tbl tbody tr.cx-grp .cx-gs .down { color: var(--down); }
.cx-tbl tbody tr.cx-grp .cx-gs .flat { color: var(--tx-2); }

/* 交叉监控页的 KPI 比通用 6 列多一张（2026-09-25 加了「平均收益」）——
   基础层的 .kpirow 写死 repeat(6…)，这里在覆盖层改成 7 列 */
.cx-kpirow { grid-template-columns: repeat(7, minmax(0, 1fr)); }
/* KPI 数值要能表达正负色（平均收益）：`.kpi .k-v` 是 (0,2,0)，会盖掉 `.up/.down` 的 (0,1,0) */
.kpi .k-v.up { color: var(--up); }
.kpi .k-v.down { color: var(--down); }
.kpi .k-v.flat { color: var(--tx-2); }

/* ===== 交叉监控页：整页锁定视口高度，表格区自己滚 ====
   ⚠️ 2026-09-25 用户反馈「最右侧那条页面滚动条难看」。**不能全局隐藏 body 的滚动条** ——
   别的长页面（模拟交易 / 历史记录 / 盘点）全靠它滚。正确做法是让本页**不产生页面级溢出**：
   高度 = 视口 − 顶栏，内部用 flex 分配，表格容器 .cx-scroll 吃掉剩余高度并自己滚。
   ⚠️ .page-flush 自带 40px 下边距，必须清掉（否则永远差 40px、照样出滚动条）；
      用 .page.cx-page 这种双类选择器压住基础层，别单写 .cx-page。 */
.page.cx-page {
  height: calc(100vh - var(--topbar-h, 54px));
  padding-bottom: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
.cx-page .cx-card { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.cx-page .cx-scroll { flex: 1 1 auto; min-height: 0; max-height: none; }
.cx-page .cx-foot { flex: 0 0 auto; }

/* 可排序表头：点一下切升降序（▼/▲），未激活时是安静的 ↕ */
.cx-tbl thead th.cx-sort { cursor: pointer; user-select: none; }
.cx-tbl thead th.cx-sort:hover { color: var(--tx); }
.cx-tbl thead th.cx-sort.on { color: var(--tx); }
.cx-sa { margin-left: 4px; font-size: 9px; color: var(--tx-3); }
.cx-tbl thead th.cx-sort.on .cx-sa { color: var(--amber); }
@media (max-width: 1280px) {
  .cx-kpirow { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  .cx-kpirow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* 噪声抽屉：琥珀底色，一眼区分「这批是被自动收起来的」 */
.cx-noise td { background: rgba(240, 185, 11, .055); }
.cx-noise:hover td { background: rgba(240, 185, 11, .095); }

.cx-sym { font-size: 12.5px; letter-spacing: .2px; }
.cx-quo { font-size: 10.5px; color: var(--tx-3); margin-left: 2px; }
/* 行内小标签：跟合约名同一格，靠 inline-block 自然排开 */
.cx-t { margin-left: 5px; }
/* 起点 / 终点 / 持续这类「价 + 时间」的两行式单元格 */
.cx-t2 { font-size: 11.5px; color: var(--tx-2); }
.cx-t2 b { font-family: var(--mono); color: var(--tx); margin-right: 6px; }
.cx-t2 span { font-family: var(--mono); color: var(--tx-3); }
/* 榜内排名 · 24h涨跌：两个数挤在一格里，必须给间隔 ——
   否则渲染成「#26+13.09%」，用户直接反馈「看不懂」（2026-09-25）。
   ⚠️ `.cx-t2 span{color:var(--tx-3)}` 是 (0,1,1)，会盖掉 `.up/.down` 的 (0,1,0)；
   `.cx-t2 .up`（0,2,0）才压得住 —— 否则 24h 涨跌永远是灰的、丢了正负色。 */
.cx-rank .cx-rk { color: var(--tx-2); }
.cx-rank .cx-chg { margin-left: 8px; }
.cx-t2 .up { color: var(--up); }
.cx-t2 .down { color: var(--down); }
.cx-live { color: var(--amber) !important; }
.cx-ret { font-size: 13px; }
.cx-foot {
  padding: 10px 18px 0; font-size: 11.5px; line-height: 1.7;
}
@media (max-width: 900px) {
  .cx-scroll { max-height: none; overflow-x: auto; }
  .cx-card { margin: 12px 8px 0; }
}

/* ============================================================ 数据分析页 /analysis
   布局与 cross 页同源：整页固定高度 → flex 分配 → 只有表格区自己滚。
   ⚠️ 别用「隐藏 body 滚动条」来消掉最右侧那条 —— 页面级滚动有别的页在用，
      本页只能让自己高度不超标（见下面的 .page.an-page）。
   ⚠️ 表格对齐复用项目既有的 `.tbl td.l` / `.tbl thead th.l`，**不要另写规则** ——
      `.tbl tbody td` 是右对齐且特异度 (0,1,2)，新写的低特异度规则会静默失效
      （本项目已经因为这件事踩过 4 次，最典型的是分组头一直靠右）。 */
/* 数据分析面板（并入 EMA 交叉监控页的第三个页签，宿主是 .page.cx-page）：
   面板自己不设高度 —— 它是 cx-page（高度=视口−顶栏）里的一个 flex 子项，
   吃掉页签条之外的剩余高度，再把剩余高度交给 .an-scroll 内滚。
   这样「页面级不溢出」由宿主的 overflow:hidden 兜底，面板不需要自己再锁一次。
   ⚠️ 表格对齐复用项目既有的 `.tbl td.l` / `.tbl thead th.l`，**不要另写规则** ——
      `.tbl tbody td` 是右对齐且特异度 (0,1,2)，新写的低特异度规则会静默失效
      （本项目已经因为这件事踩过 4 次，最典型的是分组头一直靠右）。 */
.cx-page .an-body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  padding: 0 18px 14px;
}
.an-card {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden;
}
.an-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  scrollbar-width: thin; scrollbar-color: #333d4d transparent; }
.an-scroll .tbl thead th { position: sticky; top: 0; z-index: 2; background: var(--panel); }
.an-tbl tbody td { padding: 7px 12px; }
/* 样本不足的组整行压暗（不隐藏 —— 用户仍需要看到「这一档存在但不够看」） */
.an-tbl tbody tr.thin { opacity: .55; }
.an-tbl tbody tr.thin:hover { opacity: .85; }
.an-tbl .an-halves { white-space: nowrap; }
.an-tbl .an-sep { color: var(--tx-3); }
.an-thin, .an-conf { margin-left: 8px; }

.an-meta {
  flex: 0 0 auto; display: flex; align-items: center;
  gap: 14px; flex-wrap: wrap; padding: 8px 2px 12px;
  font-size: 12px; color: var(--tx-2);
}
.an-meta b { font-weight: 650; color: var(--tx-1, var(--tx-2)); }
.an-meta .an-warn, .an-meta .an-warn b { color: var(--amber); }
.an-meta .an-dim { color: var(--tx-3); font-size: 11.5px; }
.an-meta .an-sp { flex: 1 1 auto; }
.an-kpirow, .an-controls { flex: 0 0 auto; }
.an-chk {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--tx-2); cursor: pointer;
}
.an-err { flex: 0 0 auto; margin: 0; padding: 6px 2px; color: var(--danger); font-size: 12.5px; }
.an-foot {
  flex: 0 0 auto; margin: 0; padding: 10px 14px;
  border-top: 1px solid var(--line);
  font-size: 11.5px; line-height: 1.65; color: var(--tx-3);
}
.an-foot b { color: var(--tx-2); font-weight: 650; }
/* 事后量警示条：贴在筛选器与分布表之间，只要选中「事后量」维度就出现。
   用 amber 而不是 danger —— 这不是错误，是「别照这个择时」的提醒。 */
.an-after {
  flex: 0 0 auto; margin: 0 0 8px; padding: 8px 12px;
  border: 1px solid rgba(240, 180, 60, .35); border-radius: 8px;
  background: rgba(240, 180, 60, .07);
  font-size: 12px; line-height: 1.65; color: var(--tx-2);
}
.an-after b { color: var(--amber); font-weight: 650; }

/* ============================================================ 量化模拟页（第 4 个页签）
   面板见 web/js/pages/sim.js。
   ⚠️ 这一页**整体复用** analysis 那一套（.an-body / .an-card / .an-scroll / .an-tbl /
      .an-meta / .an-controls / .an-foot / .an-dim / .an-warn / .an-err），
      下面只补「本页独有」的几样：分节标题、方案卡、结论行、资金曲线缩略图、风险数字。
   ⚠️⚠️ **不要在这里写任何 td / th 的对齐规则** —— 对齐一律复用 `.tbl td.l` /
      `.tbl thead th.l`。`.tbl tbody td { text-align: right }` 的特异度是 (0,1,2)，
      低特异度的规则会被它静默压掉（本项目已栽过 4 次）。 */

/* 分节：一页里有 6 张表，每张前面一行小标题 —— 滚动时靠它认「现在看的是哪一节」。
   ⚠️ 节与节之间用**一条极淡的分隔线**，不是靠加大 margin —— 只加间距的话，
      一页 6 节在视觉上仍连成一大坨文字（这正是「太乱」的主因）。
      `+` 只命中相邻兄弟，归档页里嵌套的 .sim-sec（逐笔明细）不会被误加线。 */
.sim-sec { margin: 0; }
.sim-sec + .sim-sec { margin-top: 13px; padding-top: 12px; border-top: 1px dashed var(--line); }
.sim-h {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 0 7px; font-size: 12.5px; font-weight: 650; color: var(--tx);
}
.sim-sub { font-size: 11.5px; font-weight: 400; color: var(--tx-3); line-height: 1.5; }
.sim-sub b { color: var(--tx-2); font-weight: 650; }

/* 折叠块：把「读结论前才需要看」的长说明收起来（口径与偏差 / 方案卡的规则细节）。
   ⚠️ 用 <details> 而不是 v-if —— 收起时文字**仍在 DOM 里**，
      自测对 `.sim-notes li` 的计数与关键串检查照样读得到，而页面上默认只占一行。
   ⚠️ summary 用 display:flex 会去掉 Chrome 的默认三角，所以自己画一个（::before）。 */
.sim-fold { margin: 0; }
.sim-fold > summary {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  cursor: pointer; list-style: none; padding: 1px 0;
}
.sim-fold > summary::-webkit-details-marker { display: none; }
.sim-fold > summary::before {
  content: '▸'; flex: 0 0 auto; font-size: 10px; line-height: 1.7;
  color: var(--amber); opacity: .75; transition: transform .15s;
}
.sim-fold[open] > summary::before { transform: rotate(90deg); }
.sim-fold > summary:hover { color: var(--tx-2); }
/* 收起时不要留着 .sim-h 那 8px 的下外边距（否则每一节都白撑一行） */
.sim-fold:not([open]) > summary { margin-bottom: 0; }
.sim-fold[open] > summary { margin-bottom: 7px; }
/* 方案卡里的折叠：比正文更轻 —— 卡不高，三张才排得齐 */
.sim-plan .sim-fold { margin-top: 6px; }
.sim-plan .sim-fold > summary { font-size: 11px; color: var(--tx-3); }
.sim-plan .sim-fold[open] > summary { margin-bottom: 4px; }

/* 方案卡（三张并排，窄屏自动换行）：把「规则到底是什么」摊开，不让用户靠猜 */
.sim-plans { display: flex; gap: 10px; flex-wrap: wrap; }
.sim-plan {
  flex: 1 1 258px; min-width: 0;
  padding: 9px 12px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel-2);
}
.sim-ph { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--tx); }
.sim-ps { margin-top: 3px; font-size: 11.5px; color: var(--tx-2); font-family: var(--mono); }
/* 规则长段（.sim-pd）现在住在卡片里的 <details> 里，所以自己不带外边距 */
.sim-pd { margin: 0; font-size: 11.5px; line-height: 1.65; color: var(--tx-3); }
.sim-pr { margin-top: 5px; font-size: 11px; color: var(--amber); letter-spacing: .2px; }

/* .sim-lead / .sim-lead-2（结论行的样式）已于 2026-09-26 随元素一并删除。 */

/* 口径条里紧跟「全仓 ⇒ 不会强平」的逐仓对照小字。
   ⚠️ .an-meta 是 flex 容器 ⇒ 相邻子元素之间的换行空白被丢弃，
      不加这条 margin 会渲染成「不会强平· 逐仓对照」（视觉上粘成一句）。 */
.sim-iso { margin-left: 6px; }

/* 表前/表后的口径警示与自校验结论 */
.sim-note-warn {
  margin: 0 0 7px; padding: 6px 11px; border-radius: 8px;
  border: 1px solid rgba(240, 180, 60, .3); background: rgba(240, 180, 60, .06);
  font-size: 11.5px; line-height: 1.6; color: var(--tx-2);
}
.sim-note-warn b { color: var(--amber); font-weight: 650; }
.sim-legend { margin: 6px 0 0; font-size: 11px; line-height: 1.6; color: var(--tx-3); }
.sim-legend b { color: var(--tx-2); }

.sim-load { display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 60px 0; color: var(--tx-3); font-size: 12.5px; }

/* 主表里「净盈亏最高」那行加一条左侧琥珀边。
   ⚠️ 不禁用其它行 —— 小样本下第一名的稳定性很差，三行都要能读。 */
.sim-tbl tbody tr.sim-best > td:first-child { box-shadow: inset 3px 0 0 var(--amber); }
/* 合计行：比数据行重一点（它是与主表对账的那一行） */
.sim-tbl tbody tr.sim-total > td { border-top: 1px solid var(--line-2); color: var(--tx-2); }
/* 紧凑表（出场原因 / 触发率）：行少列少，不需要主表那么高的行距 */
.sim-tbl.sim-tight tbody td { padding: 6px 12px; }

/* ⚠️ 下面这些是**文本样式**，不是对齐规则（对齐仍由 .tbl 的 .l 决定） */
.sim-ps2 { display: block; margin-top: 1px; font-size: 10.5px; color: var(--tx-3); }
.sim-dim { color: var(--tx-3); }
.sim-skip { color: var(--amber); font-size: 10.5px; }
.sim-sep { color: var(--tx-3); }
.sim-lv { color: var(--tx); font-family: var(--mono); }
/* 最大回撤用 amber 而不是 --down(绿)：这一列是**风险**不是「下跌」，
   上绿会让人把「回撤深」读成「跌得好」（本项目的方向色/涨跌色已绕过两次） */
.sim-dd { color: var(--amber); }

/* 资金曲线缩略图：显示尺寸 118×26（viewBox 由模板给定）
   ⚠️ stroke 用 currentColor —— svg 上挂着 .up/.down，颜色跟着净盈亏走
      （红=赚、绿=亏，中式涨跌色；跨类名规则不动 color，直接继承就够）。 */
.sim-spark { display: block; width: 118px; height: 26px; }
.sim-spark .sim-sl { fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linejoin: round; stroke-linecap: round; }
.sim-spark .sim-sf { fill: currentColor; opacity: .12; stroke: none; }

/* 口径与偏差：这几条住在 <details> 里（默认收起），所以行距可以给足 ——
   展开时读得舒服，收起时只占一行，不再把页面撑长。 */
.sim-notes { margin: 0 0 8px; padding-left: 18px;
  font-size: 11.5px; line-height: 1.65; color: var(--tx-3); }
.sim-notes:last-child { margin-bottom: 0; }
.sim-notes li { margin-bottom: 3px; }
.sim-notes b { color: var(--tx-2); font-weight: 650; }

/* ============================================ 量化模拟：**子页签条**（总览 / 监控 / 归档）
   ⚠️⚠️ 刻意**不复用** `.viewtabs` / `.vt` 两个类名 —— 顶层页签的断言是按
      `.viewtabs .vt` 计数的（本项目四处自测都钉着 `nVt === 4`），复用会让
      「顶部页签 4 个」集体变红。子级另起 `.simtabs` / `.stb`。
   视觉上比顶层**轻一档**：字号更小、更矮、色更淡，左侧一道琥珀竖线表示「归属上层」。 */
.simtabs {
  flex: 0 0 auto; position: relative;
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 6px 18px 6px 26px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
/* 归属线：告诉眼睛「这三个是上面那个页签的下级」，比纯缩进更明确 */
.simtabs::before {
  content: ''; position: absolute; left: 18px; top: 9px; bottom: 9px;
  width: 2px; border-radius: 2px; background: var(--amber); opacity: .45;
}
.simtabs .stb {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 12.5px; font-weight: 600;
  padding: 4px 12px; border-radius: 7px; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--tx-3);
  transition: background .15s, color .15s, border-color .15s;
}
.simtabs .stb:hover { color: var(--tx-2); background: var(--panel); }
.simtabs .stb.on {
  background: var(--panel-2); color: var(--tx);
  border-color: var(--line-2); box-shadow: inset 0 -2px 0 var(--amber);
}
.simtabs .stb .ico { width: 13px; height: 13px; opacity: .85; }
.simtabs .stb.on .ico { color: var(--amber); opacity: 1; }
.simtabs .stb-hint {
  margin-left: 12px; font-size: 11.5px; color: var(--tx-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- 逐条信号表（监控 / 归档共用 `.sim-rows`）：列多，整表 nowrap 靠横向滚 ---- */
.sim-rows { white-space: nowrap; }
/* ⚠️ 「进行中」整行淡琥珀底。类挂在 `tr` 上、选择器带 `tr`：
   `.sim-rows tbody td` 是 (0,1,2)，与基础 `.tbl tbody td` 同分但写在后面，
   `.sim-rows tbody tr.sml-row-open td` 是 (0,2,2) —— 两层都必须够高才压得住。 */
.sim-rows tbody tr.sml-row-open td { background: rgba(240, 185, 11, .045); }
.sim-rows tbody tr.sml-row-open:hover td { background: rgba(240, 185, 11, .08); }

/* ---- 可排序的列头（监控页「逐条信号」表，2026-09-26 起只列进行中的段）----
   ⚠️ 这里**只加「可点 + 当前列高亮」，绝不写 text-align** —— 对齐一律走既有的
      `.tbl thead th.l`（(0,1,2)），这里再写一条会互相打架且难查。
   选择器带 `thead`：`.sim-rows thead th.sim-sort` = (0,2,2)，
   压得住 `.tbl thead th` 的 (0,1,2)：两层都必须够高才压得住。 */
.sim-rows thead th.sim-sort { cursor: pointer; user-select: none; }
.sim-rows thead th.sim-sort:hover { color: var(--tx); }
.sim-rows thead th.sim-sort.on { color: var(--tx); }
.sim-sa { margin-left: 3px; font-size: 10px; color: var(--tx-3); }
.sim-rows thead th.sim-sort.on .sim-sa { color: var(--amber); }

/* 合约名两段式（base 大、quote 小灰）—— 与 `.cx-sym` 同源，别再另立体系 */
.sim-sym { font-size: 12.5px; letter-spacing: .2px; }
.sim-sym .sml-quo { font-size: 10.5px; color: var(--tx-3); margin-left: 2px; }

/* 归宿小标签：默认安静灰（已结束 / 段末平 / 反向交叉平 …），
   只有「进行中」与「强平」两个状态给颜色 —— 它们才是要一眼看到的。 */
.sml-badge {
  display: inline-block; padding: 1px 6px; border-radius: 5px;
  font-size: 10.5px; font-weight: 600; line-height: 1.65;
  background: var(--panel-2); color: var(--tx-3); border: 1px solid var(--line);
}
.sml-badge.sml-on {
  background: rgba(240, 185, 11, .14); color: var(--amber);
  border-color: rgba(240, 185, 11, .4);
}
/* 强平：用 danger 而不是涨跌色 —— 它是「爆仓」不是「跌」 */
.sml-badge.sml-liq {
  background: rgba(246, 70, 93, .14); color: var(--danger);
  border-color: rgba(246, 70, 93, .4);
}
/* 同名的 `.sml-on` 也单独用在纯文本上（汇总表里的「持仓中」笔数）：
   那时它是普通 span、没有 `.sml-badge` 的底 —— 只给色，别给背景。 */
.sml-on { color: var(--amber); font-weight: 650; }
/* 已落袋金额：挂在方案净盈亏下方的小字；该笔仍持仓时同样是琥珀 */
.sml-rz { display: block; margin-top: 1px; font-size: 10.5px; color: var(--tx-3); }
.sml-rz.sml-on { color: var(--amber); }

/* ---- 归档：选中那一日的高亮行
   ⚠️ 必须带 `td`：`.arc-sel`(0,1,0) 单独写压不过 `.tbl tbody td`(0,1,2)，
      底色会静默不生效（本项目因特异度踩过多次）。 */
.tbl tbody tr.arc-sel td { background: rgba(240, 185, 11, .07); }
.tbl tbody tr.arc-sel:hover td { background: rgba(240, 185, 11, .11); }
/* 归档明细里的方案切换条：`.tabs` 的附加类，只负责与上方标题拉开距离 */
.sim-planpick { margin: 0 0 9px; }
