:root {
  color-scheme: dark;

  /* ── 型階（type scale）·modern-design 1.25 比 ────────────────────────────
     ⛔ 最小就是 --fs-sm(14px)：站長 2026-08-22「字體最小有下限，部分字體還是過小」。
        原本全站有 106 處低於 14px（80 條 font-size ＋ 26 條藏在 font: 簡寫裡），本輪全部拉到 14。
     ⭐ 新寫的碼一律用這組 token，⛔ 不要再硬寫 px —— 硬寫的值會散開，
        下次要調整就得再掃一次 106 個地方。
     ⚠ 舊碼目前是直接改成 14px 的數值而非 var()：這份檔有 5 個 :root，
        且 `font:` 簡寫一旦 var 未定義會讓整條宣告失效（字體全掉）⇒ 分兩步走比較安全。 */
  --fs-sm: 14px;    /* 下限。標籤、輔助說明 */
  --fs-base: 16px;  /* 內文 */
  --fs-md: 18px;
  --fs-lg: 20px;
  --fs-xl: 24px;
  --fs-2xl: 30px;
  --fs-3xl: 36px;
  --fs-4xl: 48px;
  --lh-body: 1.5;
  --lh-heading: 1.2;
  --bg: #07111f;
  --surface: #0e1c2e;
  --surface-2: #14243a;
  --border: #243b56;
  --text: #eef6ff;
  --muted: #8fa9c4;
  --blue: #35a4ff;
  --violet: #9d7cff;
  --cyan: #3ed7d0;
  --green: #48d597;
  --red: #ff6279;
  --amber: #f2b84b;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  /* ⛔ 單一真相源：**每個分頁**的標題到頂部那排常駐按鈕的距離，只由這一個值決定。
     站長 2026-08-20：「標題距離長方常駐按紐 要單一真相源的距離 不是忽高忽低」。
     ⚠ 根因不是 .section-title 的 margin（它在 60/507/1148 三處都寫 48px），而是
       **各 panel 的首元素結構不同** ⇒ 實測 73（交易紀錄・設定）/ 114（總覽）/
       121（Webhook・API Key）三種值，落差 48px。
     ⇒ 改成「panel 自己負責頂端距離、首元素一律不帶自己的上邊距」，
       任何新分頁不必再各自調 margin 就自動對齊。 */
  --panel-title-gap: var(--space-7);
  /* 選中態單一真相源（Fluent/Material 選中＝實心底＋對比邊，WCAG 1.4.11 ≥3:1）。
     機器人頁籤／紀錄頁籤／頂欄分頁都讀這三個，⛔ 不要各寫一套藍。
     26% 太淡：站長「我都看不出來我選哪個」。42% 才是分段控制的實心底。 */
  --sel-bg: color-mix(in srgb, var(--blue) 42%, transparent);
  --sel-border: var(--blue);
  --sel-ink: var(--text);
  --text-xs: 12px;
  --text-sm: 14px;
  --text-lg: 18px;
  --text-base: 16px;
  --text-xl: 20px;
  --text-2xl: 24px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
* { box-sizing: border-box; }
/* Keep the viewport content width stable when a page gains or loses its
   vertical scrollbar. Grid workbench deliberately disables page scrolling;
   without a stable root gutter its top-row controls shift horizontally. */
@media (min-width: 761px) {
  html { scrollbar-gutter: stable; }
}
body { margin: 0; min-width: 320px; background: radial-gradient(circle at 85% -10%, #12345d 0, transparent 32%), var(--bg); color: var(--text); }
button, input, select { font: inherit; }
button, .button { cursor: pointer; }
/* ⛔ .app-header 的基底定義只有一處（見檔尾 0.3.20 區塊）。0.3.35 之前這裡、290、651、
   856、2297 共五處各寫一份，全部被檔尾那份完整覆蓋 ⇒ 誰贏誰輸只看行序，改上面幾處
   完全沒有效果卻看起來像有改。要改 header 幾何請改檔尾那一處。 */
.brand { display: flex; align-items: center; gap: 16px; }
.brand-mark { width: 44px; height: 52px; display: grid; place-items: center; border-radius: 14px; font-size: 30px; font-weight: 900; background: linear-gradient(135deg, #2a74ff, #39d7d3); box-shadow: 0 8px 30px #1b8ee655; }
.brand strong { display: block; font-size: 24px; letter-spacing: .2px; }
.brand small { display: block; margin-top: 4px; color: var(--muted); }
.mode-badge { color: #98f1c8; padding: 12px 16px; border: 1px solid #2f765d; border-radius: 999px; font-size: 14px; font-weight: 800; letter-spacing: .6px; background: #13382d80; }
.mode-badge span { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 8px; background: var(--green); box-shadow: 0 0 12px var(--green); }
.tabs { height: 72px; display: flex; align-items: end; gap: 4px; padding: 0 48px; border-bottom: 1px solid var(--border); background: #0a1626; }
.tab { height: 72px; padding: 0 24px; border: 0; border-bottom: 3px solid transparent; background: transparent; color: var(--muted); font-weight: 700; }
.tab:hover, .tab.active { color: var(--text); border-bottom-color: var(--blue); }
.status-link { margin: auto 0 auto auto; color: var(--cyan); text-decoration: none; font-size: 14px; }
main { padding: 48px 48px 60px; max-width: 1500px; margin: auto; }
.panel { display: none; }
/* ⭐ 距離由 --panel-title-gap 一處決定（見 :root 的說明）。
   ⛔ 首元素的自帶上邊距一律歸零 —— 不歸零的話它會疊在 padding 上，
   而每個 panel 的首元素又不一樣 ⇒ 又回到忽高忽低。 */
.panel { padding-top: var(--panel-title-gap); }
.panel > *:first-child { margin-top: 0; }
.panel.active { display: block; animation: appear .18s ease-out; }
@keyframes appear { from { opacity: 0; transform: translateY(4px); } }
.metric-grid { display: grid; grid-template-columns: repeat(4, minmax(180px, 1fr)); gap: 24px; }
.metric { position: relative; min-height: 164px; padding: 32px; overflow: hidden; border: 1px solid var(--border); border-radius: 18px; background: linear-gradient(145deg, #14263c, #0d1a2b); box-shadow: 0 16px 45px #0003; }
.metric::after { content: ''; position: absolute; right: -25px; bottom: -40px; width: 110px; height: 128px; border-radius: 50%; background: #238cff18; }
.metric span { display: block; color: var(--muted); font-weight: 700; }
.metric strong { display: inline-block; margin-top: 24px; font-size: 48px; letter-spacing: -1px; }
.metric small { margin-left: 12px; color: var(--muted); }
.section-title { display: flex; align-items: center; justify-content: space-between; gap: 32px; margin: 48px 0 24px; }
h1, h2, h3, p { margin-top: 0; }
.section-title h1 { margin-bottom: 8px; }
.section-title p, .muted { margin-bottom: 0; }
button, .button { min-height: 48px; padding: 0 24px; border: 1px solid transparent; color: white; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; }
.primary { background: linear-gradient(135deg, #2579ef, #25a5e8); box-shadow: 0 8px 22px #167bdd35; }
.secondary { background: #152a42; border-color: #31506f; }
.danger { background: #4a1e2b; border-color: #783044; color: #ffb1bf; }
.warning { background: #493817; border-color: #7d6128; color: #ffd77b; }
button:hover, .button:hover { filter: brightness(1.12); }
button:focus-visible, .button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
.actions { display: flex; gap: 12px; }
/* ⛔ auto-fill 不是 auto-fit —— 差一個字，差在「卡片寬度跟不跟數量走」。
   站長 2026-08-21（第二次講同一件事）：「機器人我說 不要一個 兩個 三個 不同寬 統一卡片大小 就好」

   auto-fit 會把【空的欄摺疊掉】，然後把剩下的空間分給有內容的那幾欄
   ⇒ 卡片越少、每張越寬。auto-fill 保留空欄 ⇒ 欄寬只跟容器寬度有關。

   2026-08-21 用真瀏覽器量的（chromium，viewport 1600、容器 1504px）：
     auto-fit ：1 張 = 1504px｜2 張 = 740px｜3 張 = 485px｜4 張 = 358px  ← 站長看到的
     auto-fill：1 張 = 358px｜2 張 = 358px｜3 張 = 358px｜4 張 = 358px  ← 要的
   ⚠ 這條規則是欄數與欄寬的【唯一】真相源；:607 那條只設 gap，⛔ 別去那裡找欄數。
   ⛔ 也不要改成寫死欄數（例 repeat(4, ...)）：視窗縮小時會橫向溢出，
      而 minmax 的 340px 下限本來就在替小視窗兜底。 */
.bot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 24px; }
.card, .bot-card { border: 1px solid var(--border); background: linear-gradient(145deg, #102037, #0c192a); box-shadow: 0 14px 42px #0002; }
.bot-card { padding: 24px; }
.bot-head { display: flex; align-items: start; justify-content: space-between; gap: 24px; }
.bot-head h3 { margin-bottom: 4px; }
.bot-head p { font-size: 14px; }
.badge { display: inline-flex; align-items: center; padding: 8px 12px; text-transform: uppercase; }
.badge.running { color: #9af0c8; background: #173b31; }
.badge.stopped { color: #b5c5d7; background: #263546; }
.badge.connecting { color: #8bd8ff; background: #173650; }
.badge.awaiting_verification { color: #ffd77b; background: #493817; }
.badge.error { color: #ff9daf; background: #4a1e2b; }
/* ⛔ 2026-08-18：3 欄 -> 2 欄。這裡本來就是錯的 —— renderBots 產生的是**四個**欄位
   （指定商品／持倉／最新價格／未實現），四個塞進 3 欄，第四個會孤零零掉到第二列。
   字級放大後欄寬不足，中文開始**逐字換行**（一個字一行），這個既有錯誤才被看見。
   四個項目排 2x2 才對稱，且每欄可用寬度直接加倍（340px 卡片內約 90px -> 約 140px）。
   ⛔ 別改回 3 欄再靠縮小字級塞進去 —— 那是拿可讀性換排版。
   min-width:0 是 grid 子項的必備保險：預設 min-width:auto 會讓長字串撐破欄位。 */
.bot-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin: 24px 0; }
.bot-stats > div { min-width: 0; }
.bot-stats div { padding: 16px; border-radius: 11px; background: #071420; }
.bot-stats span { display: block; }
.bot-stats strong { display: block; margin-top: 4px; font-size: 18px; }
.positive { color: var(--green) !important; }.negative { color: var(--red) !important; }
.bot-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.bot-actions button { min-height: 40px; padding: 0 16px; font-size: 14px; }
.webhook { margin-top: 24px; padding: 16px; background: #07131f; }
.webhook span { display: block; margin-bottom: 8px; }
.webhook code { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #76d8ff; font-size: 14px; cursor: pointer; }
.empty { padding: 64px 32px; text-align: center; border: 1px dashed #31506f; border-radius: 17px; color: var(--muted); }
.filters { display: grid; grid-template-columns: 180px 180px 1fr; gap: 12px; margin-bottom: 16px; }
input, select { width: 100%; min-height: 48px; padding: 0 16px; border: 1px solid var(--border); background: #081727; outline: none; }
input:focus, select:focus { border-color: var(--blue); box-shadow: 0 0 0 3px #248af522; }
.table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: 15px; background: #0b1929; }
table { width: 100%; border-collapse: collapse; min-width: 900px; }
th, td { padding: 16px 24px; text-align: left; border-bottom: 1px solid #1d344c; font-size: 14px; }
th { position: sticky; top: 0; color: var(--muted); background: #102238; }
td { color: #d9e7f5; }
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 24px; }
.media-card { overflow: hidden; border: 1px solid var(--border); border-radius: 15px; background: #0c1b2c; }
.media-card img { width: 100%; aspect-ratio: 16/10; display: block; object-fit: cover; background: #06101b; }
.media-info { padding: 16px; }
.media-info strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-info small { display: block; color: var(--muted); margin: 8px 0 12px; }
.settings-grid { display: grid; grid-template-columns: repeat(2, minmax(320px, 1fr)); gap: 24px; }
.module-heading {
  min-width: 0;
  margin: 0 0 20px;
  padding: 0 0 20px;
  border-bottom: 1px solid var(--border);
}
.module-heading h2 { margin: 0; font-size: var(--fs-section, 24px); line-height: 1.4; }
.module-heading small { display: block; margin-top: 8px; color: var(--muted); font-size: 16px; line-height: 1.6; }

.form-card { padding: 32px; }
label { display: block; margin: 24px 0; }
label input, label select { margin-top: 8px; }
.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 16px 0; border-bottom: 1px solid #1d344c; }
.switch-row span small { display: block; margin-top: 4px; color: var(--muted); font-weight: 400; }
.switch-row input { width: 20px; height: 20px; }
.inline-form { display: grid; grid-template-columns: 1fr 140px auto; gap: 12px; align-items: center; }
.credential-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.credential-form button { align-self: end; margin-bottom: 24px; }
.list { margin-top: 16px; }
.list-item { display: flex; align-items: center; justify-content: space-between; padding: 16px 0; border-bottom: 1px solid #1d344c; }
.account-manager { grid-column: 1 / -1; padding: 0; overflow: hidden; background: linear-gradient(145deg, #102239, #0a1728); }
.account-manager::before { content: ''; display: block; height: 5px; background: linear-gradient(90deg, var(--green), var(--cyan), var(--blue)); }
.account-manager-head { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 32px 32px 24px; border-bottom: 1px solid #203a55; }
.account-manager-title { display: flex; align-items: center; gap: 24px; }
.account-manager-title h2 { margin-bottom: 8px; font-size: 30px; }
.account-manager-title p { margin-bottom: 0; color: var(--muted); font-size: 14px; }
.account-title-icon { width: 50px; height: 56px; display: grid; flex: 0 0 50px; place-items: center; border: 1px solid #2b6d70; border-radius: 15px; color: #86f1cd; background: linear-gradient(145deg, #173a36, #102c34); box-shadow: 0 10px 26px #0004; }
.account-title-icon svg { width: 29px; height: 29px; fill: currentColor; }
.simulation-chip, .secure-chip, .account-count, .account-status, .account-demo { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; border-radius: 999px; font-weight: 800; }
.simulation-chip { padding: 12px 16px; border: 1px solid #2d6d5a; color: #9af0c8; background: #14362d; font-size: 14px; letter-spacing: .45px; }
.simulation-chip span, .account-status span { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 10px #48d59799; }
.account-manager-grid { display: grid; grid-template-columns: minmax(360px, .85fr) minmax(480px, 1.15fr); min-height: 484px; }
.credential-panel, .account-list-panel { padding: 32px 32px 32px; }
.credential-panel { border-right: 1px solid #203a55; background: #0a1829aa; }
.subsection-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
.subsection-heading h3 { margin: 2px 0 0; }
.eyebrow { display: block; color: #63bee9; font-size: 14px; font-weight: 900; letter-spacing: 1.2px; text-transform: uppercase; }
.secure-chip { padding: 8px 12px; color: #9af0c8; background: #173b31; font-size: 14px; }
.account-form-hint { margin: 0 0 24px; color: var(--muted); font-size: 14px; line-height: 1.55; }
/* ⛔ 這裡本來是 float: right，而 float **不會**把 grid 容器推開 —— 它只影響行盒。
   於是「指定商品」的說明文字直接壓在 .symbol-picker（display:grid）的搜尋框上，
   兩段字疊在一起（站長 2026-08-18 截圖指出）。其他欄位看起來沒事，只是因為它們
   後面接的是普通的 input/select。
   ⇒ 改成獨立一行的 block：說明本來就該在標題底下，而且這樣每個欄位的排法一致
   （站長第一句話就是「畫面對齊」）。間距取 8px 網格上的 4，⛔ 不要臨時填一個數字。 */
.field-help { display: block; margin-top: 4px; color: #6f8da8; font-size: 14px; font-weight: 500; line-height: 1.5; }
.account-form-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 12px; padding-top: 8px; }
.account-form-actions button { min-width: 136px; margin-bottom: 0; }
.account-list-heading { margin-bottom: 24px; }
.account-count { padding: 8px 12px; color: #9cc7e8; background: #132a40; font-size: 14px; }
.account-list { display: grid; gap: 16px; }
[data-dashboard-panel] { padding-top:18px; }
#dashboardAccountsPanel .account-list { position:relative; grid-template-columns:repeat(auto-fit,minmax(min(100%,350px),1fr)); }
#dashboardAccountsPanel .account-card { touch-action:pan-y; min-width:0; }
#dashboardAccountsPanel .account-manager { margin:0; }
#dashboardAccountsPanel .account-manager-grid { grid-template-columns:1fr; }
#dashboardAccountsPanel .account-capital-grid { padding:16px; }
.account-list.is-drag-sorting { cursor:grabbing; user-select:none; }
.account-list.is-drag-sorting .account-card { transition:transform 140ms cubic-bezier(.2,0,0,1); }
.account-list .account-card.is-dragging { transition:none; cursor:grabbing; box-shadow:0 15px 36px #0008; }
.account-list .bot-drop-line { position:absolute; width:3px; background:var(--cyan); pointer-events:none; z-index:40; }
.account-currency-evidence { margin:12px 0; color:var(--muted); }
@media (max-width:640px) {
  #dashboard > .section-title { flex-direction:column; align-items:stretch; }
  #dashboard > .section-title > .actions { flex-wrap:wrap; max-width:100%; }
  #dashboardAccountsPanel .account-card-actions { flex-wrap:wrap; }
}
.account-card { position: relative; overflow: hidden; border: 1px solid #29445f; border-radius: 15px; background: linear-gradient(145deg, #12253c, #0c1b2d); box-shadow: 0 12px 30px #0002; }
.account-card::before { content: ''; position: absolute; inset: 0 auto 0 0; width: 4px; background: linear-gradient(var(--blue), var(--cyan)); }
.account-card-head { display: flex; align-items: center; gap: 16px; padding: 24px 24px 16px 32px; border-bottom: 1px solid #213a52; }
.account-avatar { width: 42px; height: 48px; display: grid; flex: 0 0 42px; place-items: center; border-radius: 12px; color: #9edcff; background: #173b57; font-size: 16px; font-weight: 900; letter-spacing: .6px; }
.account-card-title { min-width: 0; flex: 1; }
.account-card-title h4 { margin: 0 0 4px; overflow: hidden; color: var(--text); font-size: 20px; text-overflow: ellipsis; white-space: nowrap; }
.account-card-title p { margin: 0; color: var(--muted); font-size: 14px; }
.account-platform-avatar { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.account-platform-avatar img { width: 26px; height: 26px; object-fit: contain; }
.bot-account-platform-preview { display: inline-flex; align-items: center; gap: 8px; min-height: 24px; margin-top: 7px; color: var(--muted); font-size: 12px; }
.bot-account-platform-preview img { width: 21px; height: 21px; object-fit: contain; }
.account-switch-platform-logo { width: 22px; height: 22px; margin-right: 7px; object-fit: contain; vertical-align: middle; }
.account-status { padding: 8px 12px; color: #9af0c8; background: #173b31; font-size: 14px; }
.account-details { margin: 0; padding: 4px 24px 4px 32px; }
.account-detail-row { display: grid; grid-template-columns: 120px minmax(0, 1fr); align-items: center; min-height: 60px; border-bottom: 1px solid #1b3248; }
.account-detail-row:last-child { border-bottom: 0; }
.account-detail-row dt { color: var(--muted); font-size: 14px; font-weight: 700; }
.account-detail-row dd { min-width: 0; margin: 0; color: #e7f2fb; font-size: 14px; }
.account-username { font: 700 14px/1.3 ui-monospace, SFMono-Regular, Consolas, monospace; letter-spacing: .55px; }
.account-demo { padding: 8px 12px; border: 1px solid #315d7c; color: #a9ddff; background: #132d45; font-size: 14px; }
/* Environment badge on a saved account. Colour carries the ONE thing that
   matters at a glance — can this account send orders — and it is never the
   only carrier: the badge always spells out 可送單 / 演練 / 已鎖定 in words,
   so the distinction survives a colour-blind reader and a greyscale screenshot. */
.account-env { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 999px; font-size: 14px; font-weight: 800; white-space: nowrap; }
.account-env-demo { border: 1px solid #315d7c; color: #a9ddff; background: #132d45; }
.account-env-rehearsal { border: 1px solid #7d6320; color: #ffdf9b; background: #3a2f10; }
.account-env-locked { border: 1px solid #7d3030; color: #ffb4b4; background: #3a1414; }
.account-env-unknown { border: 1px dashed #5a6f85; color: #b9cbdb; background: #16232f; }
/* The sentence under the environment picker. Same three-way tone, and it is
   the only place the operator is told what the choice actually does. */
.account-env-note { margin: -8px 0 14px; grid-column: 1 / -1; color: var(--muted); font-size: 14px; line-height: 1.55; min-height: 17px; }
.account-env-note.is-rehearsal { color: #ffdf9b; }
.account-env-note.is-locked { color: #ffb4b4; }
.broker-account-field { grid-column: 1 / -1; }
/* ⛔ 明寫，不要倚賴「.broker-account-field 剛好沒設 display」：這一格預設帶 hidden
   （站長 2026-08-19「不要給用戶填寫」），而任何一條之後加上的 display 規則都會蓋掉
   瀏覽器內建的 [hidden]{display:none} —— 屬性照樣是對的、畫面上卻看得見，而每一個
   「它藏起來了嗎」的檢查都會回答藏起來了。 */
.broker-account-field[hidden] { display: none; }
/* 0.4.5 欄位重排（平台｜類別 ／ 帳號｜密碼 ／ 帳號代碼 ／ 帳號名稱）後，帳號名稱是
   奇數欄位的落點 ⇒ 半格會在它右邊留一個空格子。⛔ 不要為了「看起來成對」把別的欄位
   搬回來湊 —— 帳號代碼那格是 1/-1（test/broker-account-ui.test.js 釘住），搬過來會紅。 */
.account-name-field { grid-column: 1 / -1; }
.broker-account-note { min-height: 18px; margin: -8px 0 4px; grid-column: 1 / -1; color: var(--muted); font-size: 14px; line-height: 1.55; }
.broker-account-note.is-bound, .account-binding-state.is-bound { color: #9af0c8; }
.broker-account-note.is-unbound, .account-binding-state.is-unbound { color: #ffdf9b; }
.account-binding-state { display: inline-block; font-weight: 750; line-height: 1.45; }
.account-encrypted { color: #86dcb9; }
.account-card-actions { display: flex; justify-content: flex-end; gap: 12px; padding: 16px 24px 24px 32px; border-top: 1px solid #213a52; background: #07152288; }
.account-card-actions button { min-height: 44px; font-size: 14px; }
.account-card-actions .danger { margin-left: 8px; }
.account-list-empty { padding: 64px 32px; text-align: center; border: 1px dashed #31506f; border-radius: 14px; color: var(--muted); background: #08172788; }
.account-list-empty strong { display: block; margin-bottom: 8px; color: #cce0f2; font-size: 16px; }
.safety-card li { margin: 16px 0; color: #aac0d5; }
.connection-line { display: flex; align-items: center; gap: 12px; margin: 16px 0 4px; padding: 12px 16px; border-radius: 9px; color: var(--muted); background: #071522; font-size: 14px; }
.connection-line.connected { color: #98f1c8; border: 1px solid #285f4c; }
.connection-line.error { color: #ff9daf; border: 1px solid #743447; }
.connection-line.awaiting_verification { color: #ffd77b; border: 1px solid #735a25; }
/* ⛔ 欄數**不在這裡**決定 —— 真相源是本檔後面那條 .receiver-grid（搜 `auto-fit`）。
   這行只負責 display 與 gap；2026-08-20 我先改了這裡卻沒生效，實測 grid-template-columns
   仍是 0.92fr/1.08fr ⇒ 同名規則寫了兩處時，**決定畫面的是最後那一條**。 */
.receiver-grid { display: grid; gap: 24px; }
.receiver-status { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; padding: 16px; border: 1px solid var(--border); border-radius: 11px; background: #071522; }
.receiver-status > span { width: 12px; height: 12px; flex: 0 0 12px; border-radius: 50%; background: var(--red); box-shadow: 0 0 15px #ff627966; }
.receiver-status > span.online { background: var(--green); box-shadow: 0 0 15px #48d59788; }
.receiver-status strong, .receiver-status small { display: block; }
.receiver-status small { margin-top: 3px; color: var(--muted); }
.copy-field { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; margin-top: 8px; }
.copy-field code { display: block; overflow: hidden; padding: 16px; border: 1px solid var(--border); border-radius: 9px; color: #76d8ff; background: #07131f; text-overflow: ellipsis; white-space: nowrap; }
.notice { padding: 16px 16px; border-left: 3px solid var(--amber); color: #f1d597; background: #392d1566; font-size: 14px; line-height: 1.55; }
.strategy-route-note { margin: 12px 0 16px; color: #8fc7ec; font-size: 14px; line-height: 1.5; }
.strategy-route-note code { color: #b7e7ff; }
.template-head { display: flex; justify-content: space-between; align-items: start; gap: 24px; }
.json-template { min-height: 328px; margin: 24px 0 16px; padding: 24px; overflow-x: hidden; overflow-y: auto; border: 1px solid #245075; border-radius: 11px; color: #9bdcff; background: #06111c; font: 14px/1.7 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }
.receiver-help code { color: #84d9ff; }
.section-title.compact { margin-top: 32px; }
/* ===== 一鍵全啟（站長 2026-08-24：「總覽 右側 做一個大按鈕」）=====
   ⚠ 它是「大按鈕」但⛔ 不能長得像緊急鈕：全部平倉／強制停機是紅色系，
     那個顏色在交易軟體裡代表「會動到部位」。一鍵全啟只是連線 ⇒ 用主色系。
   flex-shrink: 0 ⇒ 標題文字變長時它不會被壓扁成看不出是按鈕的細條。 */
.start-all {
  flex: 0 0 auto;
  min-width: 160px;
  padding: 16px 28px;
  border: 0;
  border-radius: 12px;
  /* ⭐ 站長 2026-08-25：「一鍵全啟 改成 **VIP 金色按紐**」。
     ⭐ 金屬感來自**亮帶**不是單一個金色 —— 單色 #ffd700 看起來是「黃色按鈕」不是金。
        五個色標＝暗金邊 → 金 → 高光 → 金 → 暗金邊，亮帶壓在偏左上（配合 135deg 的光源）。
     ⛔ 不發明新的顏色變數：這條血統就是既有的 --amber（#f2b84b／#ffc65a／#ffd37a 三個
        主題層都在用），⛔ 不要為了這顆按鈕另開一組 token。
     ⚠ 文字用深棕 #2b1d05 不是黑：純黑配金會顯得髒，而深棕與高光的對比仍遠超 AA。
     ⚠ inset 那道細白線是「邊緣受光」，⛔ 不要拿掉改用 border —— border 會撐大盒子，
        而這顆按鈕的 min-width 是跟旁邊的分組控制列對齊過的。 */
  background: linear-gradient(135deg, #a9761f 0%, #f2c75c 22%, #fff2c4 46%, #f0c257 64%, #a97a1e 100%);
  color: #2b1d05;
  font-size: 16px;
  font-weight: 800;
  letter-spacing: .5px;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 10px 28px rgba(214, 163, 62, .32), inset 0 1px 0 rgba(255, 255, 255, .55);
  text-shadow: 0 1px 0 rgba(255, 246, 214, .45);
}
/* hover 讓亮帶更亮一點點。⛔ 不做「亮帶掃過去」的動畫：那是促銷頁的手法，
   而這顆按鈕按下去會真的去連券商 —— 它該看起來貴重，⛔ 不是該看起來在催人按。 */
.start-all:hover:not(:disabled) {
  filter: brightness(1.06) saturate(1.04);
  box-shadow: 0 12px 32px rgba(214, 163, 62, .42), inset 0 1px 0 rgba(255, 255, 255, .68);
}
/* ⛔ 停用時要看得出來在忙（按鈕文字會變成「啟動中 3/7」），⛔ 不是單純變灰讓人以為壞了。 */
.start-all:disabled { cursor: progress; opacity: .72; box-shadow: none; }
.running-bot-count { color: var(--muted); font-size: 13px; white-space: nowrap; }
.switch-row[data-worker-feature][hidden] { display: none !important; }
/* The legacy label has no worker-feature attribute; author flex rules override UA hidden. */
.bot-auto-catchup-legacy[hidden] { display: none !important; }
.bot-missed-order-policy-error { margin: 4px 0 0; color: var(--danger, #ff708e); font-size: 13px; line-height: 1.5; }
.bot-missed-order-policy-error[hidden] { display: none !important; }
.start-all.is-stop-all { background: #a52e3e; border-color: #da5161; color: #fff; box-shadow: none; }
.start-all.is-stop-all:hover:not(:disabled) { background: #c43b4e; border-color: #ff8290; }
/* ── 全部運行中＝**達成態**（站長 2026-08-25：「全啟以後…要變成不能按的按紐」）──
   ⛔ 不沿用上面 :disabled 那個樣子：它的 cursor: progress 講的是「正在忙、等一下」，
      而這裡的意思相反 —— 事情已經做完了。兩個狀態共用一種外觀，使用者就分不出
      「還在啟動」跟「全都啟動好了」，而那正好是這顆按鈕唯一要回答的問題。
   ⭐ 金色＝「可以按、按了會發生事」；達成態要**退場**：靜態、低飽和、綠色系。
   ⛔ 不另開顏色 token：綠就是既有的 --green（連線中的圓點用的同一支血統）。
   ⚠ opacity 明確寫回 1 —— 上面 :disabled 的 .72 會同時命中這顆（它確實是 disabled），
     不寫死就會變成一顆半透明的綠，讀起來又回到「壞掉」那一側。 */
.start-all.is-all-running {
  background: linear-gradient(135deg, rgba(72, 213, 151, .2) 0%, rgba(72, 213, 151, .08) 100%);
  color: var(--green);
  box-shadow: inset 0 0 0 1px rgba(72, 213, 151, .45);
  text-shadow: none;
  opacity: 1;
  cursor: default;
}
.start-all.is-all-running::before { content: '✓'; margin-right: 8px; font-weight: 900; }
/* 0.5.0 反熵：font-size 移交檔尾設計系統層（區段標題統一 28px）。
   ⛔ 這條 (0,2,1) 會贏過檔尾的 `.section-title h2` (0,1,1)，留著＝總覽頁那個
      「交易機器人」永遠停在 20px，比它管的卡片標題還小 ＝ 階層反轉沒修到。
   ⚠ margin-bottom 保留：它是這個變體存在的理由（compact 版標題與副標更貼）。 */
.section-title.compact h2 { margin-bottom: 4px; }
.delivery-status { display: inline-flex; padding: 4px 12px; border-radius: 999px; font-size: 14px; font-weight: 800; }
.delivery-status.accepted { color: #8bd8ff; background: #173650; }
.delivery-status.executed { color: #9af0c8; background: #173b31; }
.delivery-status.failed { color: #ff9daf; background: #4a1e2b; }
dialog { width: min(660px, calc(100vw - 40px)); padding: 0; border: 1px solid #31506f; border-radius: 18px; background: #0c1a2b; color: var(--text); box-shadow: 0 30px 100px #000a; }
dialog::backdrop { background: #020915b5; backdrop-filter: blur(4px); }
dialog form { padding: 32px; }
.dialog-title, .dialog-actions { display: flex; align-items: start; justify-content: space-between; gap: 24px; }
.dialog-title p { color: var(--muted); margin-bottom: 0; }
/* ⛔ 這顆是**正圓**，不是「圓角矩形剛好看起來圓」。
   之前只設 min-width: 40px，高度則繼承 button 的 min-height: 48px ⇒ 40×48 ＋ 圓角 10px
   ＝ 一個直立的橢圓（站長 2026-08-18 指出；同一個病之前在頭像上出現過一次）。
   ⇒ 寬高一起釘死才會圓。44 是觸控目標下限，⛔ 不要為了好看縮到 40 以下。 */
.icon-button {
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: #172b41; font-size: 24px; line-height: 1;
}
.dialog-actions { justify-content: flex-end; margin-top: 32px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
.hidden { display: none !important; }
.smart-list { max-height: 160px; overflow: auto; margin-top: 24px; }
.smart-item { display: flex; justify-content: space-between; align-items: center; padding: 12px; margin-top: 8px; border-radius: 9px; background: #071522; font-size: 14px; }
#toast { position: fixed; right: 26px; bottom: 26px; z-index: 20; max-width: 390px; padding: 16px 24px; border: 1px solid #32608a; border-radius: 11px; background: #12304b; box-shadow: 0 15px 50px #0006; opacity: 0; transform: translateY(12px); pointer-events: none; transition: .2s; display: flex; align-items: center; gap: 12px; }
#toast.show { opacity: 1; transform: translateY(0); }
#toast.toast-sticky { padding-right: 48px; pointer-events: auto; }
#toast .toast-close { position: absolute; top: 7px; right: 8px; display: grid; place-items: center; width: 30px; min-width: 30px; height: 30px; min-height: 30px; padding: 0; border: 0; border-radius: 8px; color: currentColor; background: transparent; font-size: 22px; line-height: 1; opacity: .72; }
#toast .toast-close:hover, #toast .toast-close:focus-visible { background: rgba(255,255,255,.1); opacity: 1; }
#toast.toast-success { border-color: #2f9d6a; background: #12352a; color: #d8ffe9; }
#toast.toast-error { border-color: #9b4052; background: #4b1f2b; }
#toast .toast-check { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--green); color: #062015; font-weight: 900; font-size: 16px; flex: 0 0 auto; }
button.copied { border-color: #2f9d6a !important; color: #9cf0c4 !important; }
button.primary.copied { border-color: #9cf0c4 !important; background: #9cf0c4 !important; color: #092419 !important; }
.symbol-picker { display: grid; gap: 12px; margin-top: 8px; }
.symbol-picker input[type="search"] { width: 100%; padding: 16px 16px; border-radius: 9px; border: 1px solid var(--border); background: #07131f; color: var(--text); }
.symbol-select { width: 100%; padding: 16px 16px; border-radius: 9px; border: 1px solid var(--border); background: #07131f; color: var(--text); }
.symbol-picker-actions { display: flex; flex-wrap: wrap; gap: 12px; }

/* ===== 選中商品的來源色（⛔ 掛在**選單框自己**身上，不是另一個框）=====
   站長 2026-08-19 講了兩次：先是「選了 NQU6 他上面不會顯示 感覺不像是選單」，
   上一輪補了一個 .symbol-chosen 回顯框；他接著說「直接將所選項目顯示在選單的那個框，
   不要再下面多做一個框」⇒ 回顯框已刪，改讓 select 收合後自己顯示。
   ⭐ 文字回顯由瀏覽器原生負責（收合後顯示選中 option 的完整文字，含來源標記）；
      這裡只補**顏色**這一項。
   ⛔ 顏色只跟著 data-origin 走，⛔ 不看文字內容 —— 文字會被 i18n 換掉，
      而顏色講的是「這個代碼能不能拿去下單」，那件事跟語言無關。 */
/* ⚠ 展開的下拉清單另外指定底色/字色：select 的 color 會被收合框拿去用，
   若不把 option 拉回中性色，整份清單會跟著變綠或變紅 ⇒ 反而看不出哪一列是哪一組。 */
.symbol-select option { background: #07131f; color: var(--text); }
.symbol-select optgroup { background: #07131f; color: #8693bc; }
/* ✅ 平台確認過的 —— 這是唯一能拿去做 100% 比對的來源，所以給它唯一的綠色。 */
.symbol-select[data-origin="broker-confirmed"] { border-color: var(--green); color: var(--green); }
/* ⛔ 圖表用代碼：送出去下不了單 ⇒ 用紅色，⛔ 不要只是淡化處理。
   站長要的是「有字說出來」，顏色是那句話的第二道保險。 */
.symbol-select[data-origin="chart-only"] { border-color: var(--red); color: var(--red); }
/* 尚未選 ⇒ 中性灰，⛔ 不用紅色：還沒選不是錯誤。 */
.symbol-select[data-origin="none"] { color: #8693bc; }
/* ===== 機器人卡上的交易帳號窗口（站長 2026-08-20）=====
   ⛔ 帳號代碼**不遮罩** —— 這是他自己的帳號，遮起來剛好擋住他換帳號時唯一要看的東西。
   ⚠ 鎖定態（機器人還在跑）仍然可按：擋的理由要由點下去之後的警告說出來，
     畫成 disabled 的話畫面上沒有任何地方會解釋「為什麼不能按」。 */
.bot-account-window {
  display: grid;
  gap: 4px;
  width: 100%;
  margin: 12px 0 0;
  padding: 12px 14px;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(6, 20, 33, .55);
  color: var(--text);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.bot-account-window:hover { border-color: var(--cyan, #19ddff); background: rgba(10, 30, 48, .75); }
.bot-account-window:focus-visible { outline: 2px solid var(--cyan, #19ddff); outline-offset: 2px; }
.bot-account-window-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* ⛔ 不要 text-transform: uppercase —— 這格寫的是環境名（「考核」「模擬」），
   中文吃不到大寫、而英文環境名被拉成 DEMO/PROP 反而看不出是哪一種帳號。 */
.bot-account-window-kicker { font-size: 14px; font-weight: 700; letter-spacing: .4px; color: #8693bc; }
.bot-account-window-cta { font-size: 14px; font-weight: 700; color: var(--cyan, #19ddff); }
.bot-account-window.is-locked .bot-account-window-cta { color: #8693bc; }
.bot-account-restriction-notice { min-width: 0; margin: 6px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--warning, #ffd07a); font-size: 12px; }
.bot-account-window-name { display: block; min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 16px; font-weight: 700; line-height: 1.3; }
.bot-account-window { min-width: 0; grid-template-columns: minmax(0, 1fr); }
.account-switch-item-main > strong { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⭐ 帳號代碼用等寬字：它是要拿來跟交易頁上那串**逐字比對**的，
   比例字型會讓 0/O、1/l 分不出來。 */
.bot-account-window-spec { font-family: ui-monospace, Consolas, monospace; font-size: 14px; color: var(--muted); }

/* ===== 換帳號視窗的清單 ===== */
.account-switch-list { display: grid; gap: 8px; padding: 0 24px; }
.account-switch-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(6, 20, 33, .55);
  color: var(--text);
  cursor: pointer;
}
.account-switch-item:hover { border-color: var(--cyan, #19ddff); background: rgba(10, 30, 48, .75); }
.account-switch-item.is-current { border-color: var(--green, #72f2c3); }
.account-switch-item-main { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.account-switch-item-main strong { font-size: 16px; font-weight: 700; }
.account-switch-item-main small { font-family: ui-monospace, Consolas, monospace; font-size: 14px; color: var(--muted); }
.account-switch-item-env { font-size: 14px; color: #8693bc; }
.account-switch-item-tag { font-size: 14px; font-weight: 700; color: var(--green, #72f2c3); }

.brand-dialog { border: 1px solid rgba(53,164,255,.35); border-radius: 16px; padding: 0; background: linear-gradient(180deg, #12253d, #0b1728); color: var(--text); max-width: min(520px, 92vw); box-shadow: 0 24px 80px #000a, 0 0 40px #1b8ee622; }
.brand-dialog::backdrop { background: rgba(3, 8, 16, .72); backdrop-filter: blur(6px); }
.brand-dialog .dialog-title { padding: 24px 24px 12px; }
.brand-dialog .dialog-actions { padding: 16px 24px 24px; display: flex; justify-content: flex-end; gap: 12px; }
.brand-dialog .dialog-actions > [hidden] { display: none !important; }
.brand-dialog #confirmDialogMessage { color: var(--muted); line-height: 1.5; margin: 0; }
@media (max-width: 1050px) { .metric-grid { grid-template-columns: repeat(2, 1fr); }.settings-grid, .receiver-grid, .account-manager-grid { grid-template-columns: 1fr; }.credential-panel { border-right: 0; border-bottom: 1px solid #203a55; } }
@media (max-width: 760px) {
  .credential-form { grid-template-columns: 1fr; }
  .account-form-actions, .account-env-note, .broker-account-field, .broker-account-note, .account-name-field { grid-column: 1; }
}

/* Future command-deck theme */
:root {
  --bg: #020711;
  --surface: #071421;
  --surface-2: #0a1d30;
  --border: rgba(84, 160, 210, .27);
  --border-hot: rgba(36, 213, 255, .62);
  --text: #eaf8ff;
  --muted: #7594aa;
  --blue: #3c85ff;
  --violet: #7a5ae0;
  --cyan: #19ddff;
  --green: #46f4aa;
  --red: #ff5578;
  --amber: #ffc65a;
  --panel-glow: 0 24px 70px rgba(0, 0, 0, .34), inset 0 1px rgba(154, 224, 255, .055);
  font-family: "Segoe UI Variable", "Segoe UI", Inter, ui-sans-serif, system-ui, sans-serif;
}

html { background: var(--bg); }

body {
  min-height: 100vh;
  background:
    radial-gradient(circle at 12% -8%, rgba(22, 184, 255, .16), transparent 29%),
    radial-gradient(circle at 88% 5%, rgba(65, 87, 255, .14), transparent 31%),
    linear-gradient(155deg, #030914 0%, #020711 46%, #06111d 100%);
  color: var(--text);
  letter-spacing: .01em;
}

.ambient-grid {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .46;
  background-image:
    linear-gradient(rgba(55, 149, 203, .07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(55, 149, 203, .07) 1px, transparent 1px);
  background-size: 48px 48px;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, transparent 78%);
  mask-image: linear-gradient(to bottom, #000 0, transparent 78%);
}

.ambient-grid::before,
.ambient-grid::after {
  content: '';
  position: absolute;
  pointer-events: none;
}

.ambient-grid::before {
  inset: 0;
  background: linear-gradient(90deg, transparent 0 49.8%, rgba(25, 221, 255, .07) 50%, transparent 50.2%);
}

.ambient-grid::after {
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(25, 221, 255, .58), transparent);
  box-shadow: 0 0 18px rgba(25, 221, 255, .4);
  animation: deck-scan 11s linear infinite;
}

@keyframes deck-scan { from { transform: translateY(90px); } to { transform: translateY(920px); } }
@keyframes status-pulse { 0%, 100% { opacity: 1; box-shadow: 0 0 9px currentColor; } 50% { opacity: .5; box-shadow: 0 0 20px currentColor; } }
@keyframes panel-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

.brand { gap: 24px; }

.brand-mark {
  position: relative;
  width: 52px;
  height: 60px;
  border: 1px solid rgba(89, 210, 255, .7);
  border-radius: 11px 4px 11px 4px;
  color: #eaffff;
  background: linear-gradient(145deg, rgba(20, 119, 238, .92), rgba(0, 217, 224, .58));
  box-shadow: 0 0 0 4px rgba(24, 177, 255, .06), 0 0 32px rgba(14, 182, 255, .28), inset 0 1px rgba(255,255,255,.3);
  transform: rotate(-3deg);
}

.brand-mark::before,
.brand-mark::after {
  content: '';
  position: absolute;
  border-color: rgba(137, 235, 255, .9);
}

.brand-mark::before { inset: -5px 9px; border-top: 1px solid; border-bottom: 1px solid; }
.brand-mark::after { inset: 9px -5px; border-left: 1px solid; border-right: 1px solid; }
.brand-mark i { position: relative; z-index: 1; font: 900 16px/1 Bahnschrift, "Segoe UI", sans-serif; letter-spacing: 1.5px; transform: rotate(3deg); }
.brand strong { font: 680 24px/1.1 Bahnschrift, "Segoe UI", sans-serif; letter-spacing: .2px; }
.brand strong em { color: var(--cyan); font-size: 14px; font-style: normal; letter-spacing: 2.2px; text-shadow: 0 0 16px rgba(25, 221, 255, .6); }
.brand small { margin-top: 8px; color: #688aa2; font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: 2.1px; }

.header-status { display: flex; align-items: center; gap: 16px; }
.node-chip {
  padding: 12px 16px;
  border: 1px solid rgba(84, 160, 210, .24);
  border-radius: 6px;
  color: #698ba2;
  background: rgba(7, 22, 36, .72);
  font: 700 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1.3px;
}

.mode-badge {
  position: relative;
  padding: 12px 24px;
  border: 1px solid rgba(70, 244, 170, .38);
  border-radius: 7px 2px 7px 2px;
  color: #8dffd0;
  background: linear-gradient(120deg, rgba(15, 62, 49, .75), rgba(8, 31, 34, .72));
  box-shadow: inset 0 0 20px rgba(70, 244, 170, .045), 0 0 24px rgba(70, 244, 170, .06);
  font: 800 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1px;
}

.mode-badge span { color: var(--green); animation: status-pulse 2.4s ease-in-out infinite; }

.tabs {
  position: relative;
  height: 72px;
  align-items: center;
  gap: 12px;
  padding: 0 64px;
  border-bottom: 1px solid rgba(84, 160, 210, .18);
  background: rgba(4, 14, 25, .78);
  backdrop-filter: blur(18px);
}

.tab {
  position: relative;
  height: 48px;
  min-height: 48px;
  padding: 0 24px;
  border: 1px solid transparent;
  border-radius: 7px;
  color: #6f8da3;
  background: transparent;
  font-size: 14px;
  font-weight: 720;
  letter-spacing: .5px;
  transition: .18s ease;
}

.tab::before {
  content: '';
  width: 4px;
  height: 4px;
  margin-right: 12px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
}

.tab:hover { border-color: rgba(67, 165, 224, .2); color: #abd9ef; background: rgba(18, 53, 79, .3); }
.tab.active {
  border-color: rgba(25, 221, 255, .32);
  color: #dffaff;
  background: linear-gradient(120deg, rgba(11, 98, 147, .42), rgba(11, 42, 70, .38));
  box-shadow: inset 0 0 22px rgba(25, 221, 255, .05), 0 0 24px rgba(25, 221, 255, .04);
}
.tab.active::after { content: ''; position: absolute; left: 18px; right: 18px; bottom: -12px; height: 2px; background: var(--cyan); box-shadow: 0 0 12px var(--cyan); }
.status-link { color: #4bb7d5; font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: .7px; }

main { max-width: 1660px; padding: 48px 64px 72px; }
.panel.active { animation: panel-in .28s ease-out; }

.metric-grid { gap: 24px; }
.metric {
  min-height: 180px;
  padding: 64px 32px 32px;
  border: 1px solid rgba(70, 162, 217, .28);
  border-radius: 13px 3px 13px 3px;
  background:
    linear-gradient(135deg, rgba(13, 42, 65, .78), rgba(5, 17, 29, .9)),
    repeating-linear-gradient(90deg, transparent 0 13px, rgba(25, 221, 255, .025) 14px);
  box-shadow: var(--panel-glow);
  transition: border-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.metric:hover { transform: translateY(-2px); border-color: rgba(25, 221, 255, .52); box-shadow: 0 25px 80px rgba(0,0,0,.38), 0 0 24px rgba(25,221,255,.06); }
.metric::before {
  content: attr(data-code);
  position: absolute;
  top: 17px;
  left: 24px;
  color: rgba(67, 198, 238, .62);
  font: 800 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1.4px;
}
.metric::after {
  right: -42px;
  bottom: -59px;
  width: 148px;
  height: 172px;
  border: 1px solid rgba(25, 221, 255, .14);
  background: radial-gradient(circle, rgba(43, 144, 255, .13), transparent 64%);
  box-shadow: 0 0 0 18px rgba(36, 131, 255, .025), 0 0 0 38px rgba(36, 131, 255, .018);
}
.metric > span { color: #8eabbf; font-size: 14px; letter-spacing: .8px; }
.metric strong { margin-top: 24px; color: #effbff; font: 630 48px/1 Bahnschrift, ui-monospace, Consolas, monospace; letter-spacing: -.6px; text-shadow: 0 0 25px rgba(91, 191, 255, .12); }
.metric small { color: #6694ad; font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: .6px; }

/* ===== 金額自適應：放不下就縮，⛔ 不是切掉（站長 2026-08-24「沒有自適應」）=====
   交接 legacy queue 記債最久的一條。.metric 與 .bot-stats div 都是 overflow:hidden
   ＋ 固定字級 ⇒ 放不下【不是換行是切掉】，而且沒有省略號、沒有 title、沒有任何徵兆
   ⇒ -$1234567.89 被切成 -$1234567 之後，它仍然是一個讀得通的合法數字。
   ⛔ 省略號對金額沒有用（看得出被切、仍然不知道被切掉什麼）⇒ 正解是【縮字級】。
   ⭐ 用容器查詢而不是 vw：這幾張卡的寬度由 grid 欄數與側欄開合決定，跟視窗寬不是同一件事
      ⇒ 拿 vw 算會在側欄收起時整組算錯。
   ⛔ @supports 包起來：不支援容器查詢的引擎原樣退回現況（⛔ 不會比現在更糟）。
   ⚠ 兩個下限（20px／12px）是可讀性底線，⛔ 不是量出來的最佳值：真正的判準是
      改完之後 scrollWidth 不得大於 clientWidth（_verify 量測，負對照＝把 clamp 拿掉會紅）。 */
@supports (container-type: inline-size) {
  .metric { container-type: inline-size; }
  .metric strong { font-size: clamp(20px, 10cqi, 48px); }
  .bot-stats > div { container-type: inline-size; }
  .bot-stats strong { font-size: clamp(12px, 13cqi, 18px); }
}
/* 縮到下限仍放不下時（極端長的數字）至少要【看得出來被切了】——
   ⛔ 這是最後一道，不是主要手段：省略號的作用只是「別讓它安靜地說謊」。 */
.metric strong, .bot-stats strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.section-title { margin: 48px 0 24px; }
.section-title h1 { margin-bottom: 8px; font: 650 30px/1.2 Bahnschrift, "Segoe UI", sans-serif; }
.section-title h1::before, .section-title h2::before { content: '//'; margin-right: 12px; color: var(--cyan); font-family: ui-monospace, Consolas, monospace; text-shadow: 0 0 14px rgba(25,221,255,.55); }
.section-title p { line-height: 1.6; }
h2, h3 { font-family: Bahnschrift, "Segoe UI", sans-serif; letter-spacing: .2px; }

button, .button {
  min-height: 48px;
  padding: 0 24px;
 
  font-size: 14px;
 
  letter-spacing: .45px;
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease, filter .15s ease;
}
button:hover, .button:hover { transform: translateY(-1px); filter: brightness(1.12); }
button:active, .button:active { transform: translateY(0); }
.primary { border-color: rgba(91, 218, 255, .52); background: linear-gradient(135deg, #126de6, #09a7d7); box-shadow: 0 9px 28px rgba(13, 131, 231, .24), inset 0 1px rgba(255,255,255,.2); }
.primary:hover { box-shadow: 0 12px 34px rgba(13, 163, 231, .34), 0 0 18px rgba(25,221,255,.14); }
.secondary { border-color: rgba(77, 151, 199, .34); color: #bad9e9; background: linear-gradient(145deg, rgba(17, 48, 72, .84), rgba(9, 28, 44, .92)); }
.danger { border-color: rgba(255, 85, 120, .38); color: #ff9bb0; background: linear-gradient(145deg, rgba(87, 24, 43, .8), rgba(46, 17, 30, .9)); }
.warning { border-color: rgba(255, 198, 90, .38); color: #ffdb91; background: rgba(72, 50, 16, .74); }

.card, .bot-card {
  border: 1px solid rgba(73, 153, 203, .25);
 
  background: linear-gradient(145deg, rgba(10, 30, 49, .9), rgba(4, 15, 27, .93));
  box-shadow: var(--panel-glow);
  backdrop-filter: blur(15px);
}
.bot-grid { gap: 24px; }
.bot-card { position: relative; overflow: hidden; padding: 32px; transition: .2s ease; }
.bot-card::before { content: ''; position: absolute; left: 0; top: 0; width: 92px; height: 2px; background: linear-gradient(90deg, var(--cyan), transparent); box-shadow: 0 0 12px rgba(25,221,255,.6); }
.bot-card:hover { transform: translateY(-2px); border-color: rgba(25,221,255,.42); }
.bot-head p { font: 600 14px/1.4 ui-monospace, Consolas, monospace; letter-spacing: .5px; }
.badge { gap: 8px; border: 1px solid transparent; font: 800 14px/1 ui-monospace, Consolas, monospace; letter-spacing: .7px; }
.badge::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; }
.badge.running { color: #83f7c3; background: rgba(18, 66, 50, .58); }
.badge.stopped { color: #8ba2b2; background: rgba(39, 54, 68, .7); }
.badge.connecting { color: #77d9ff; background: rgba(14, 61, 88, .7); }
.bot-stats { gap: 12px; margin: 24px 0; }
.bot-stats div { position: relative; overflow: hidden; padding: 16px; border: 1px solid rgba(72, 142, 184, .14); border-radius: 7px; background: rgba(2, 12, 21, .64); }
.bot-stats div::after { content: ''; position: absolute; right: 0; bottom: 0; width: 18px; height: 1px; background: var(--cyan); opacity: .45; }
.bot-stats strong { margin-top: 8px; font-family: ui-monospace, Consolas, monospace; color: #dff5ff; }
.webhook { border: 1px solid rgba(50, 132, 178, .18); background: rgba(1, 10, 18, .7); }
.webhook code { color: #5cdfff; }

input, select {
  min-height: 52px;
  border: 1px solid rgba(76, 145, 188, .28);
 
 
  background: rgba(3, 15, 26, .82);
  box-shadow: inset 0 0 18px rgba(8, 90, 130, .035);
}
input::placeholder { color: #49687e; }
input:focus, select:focus { border-color: rgba(25,221,255,.75); box-shadow: 0 0 0 3px rgba(25,221,255,.08), inset 0 0 20px rgba(25,221,255,.035); }

.table-wrap { border-color: rgba(77, 151, 199, .24); border-radius: 11px 2px 11px 2px; background: rgba(3, 14, 24, .84); box-shadow: var(--panel-glow); }
th, td { padding: 16px 24px; border-bottom-color: rgba(62, 125, 163, .17); font-size: 14px; }
th { color: #7196ad; background: rgba(9, 31, 50, .96); font: 760 14px/1.2 ui-monospace, Consolas, monospace; letter-spacing: .6px; }
td { color: #c9dce6; }
tbody tr { transition: background .15s ease; }
tbody tr:hover { background: rgba(19, 97, 137, .12); }

.receiver-grid { gap: 24px; }
.receiver-status { position: relative; overflow: hidden; border-color: rgba(69, 157, 207, .27); border-radius: 9px 2px 9px 2px; background: rgba(2, 15, 25, .72); }
.receiver-status::after { content: 'UPLINK STATUS'; position: absolute; top: 8px; right: 10px; color: rgba(83, 156, 195, .5); font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: 1px; }
.receiver-status > span { color: var(--red); animation: status-pulse 2.4s ease-in-out infinite; }
.receiver-status > span.online { color: var(--green); }
.receiver-status strong { letter-spacing: .3px; }
.copy-field code { border-color: rgba(41, 156, 207, .32); border-radius: 7px 2px 7px 2px; color: #61dcff; background: rgba(1, 11, 20, .86); font-family: ui-monospace, Consolas, monospace; }
.notice { border-left-color: var(--amber); color: #d8bb79; background: linear-gradient(90deg, rgba(89, 60, 15, .34), rgba(42, 31, 14, .2)); }
.json-template { min-height: 364px; border-color: rgba(25,221,255,.35); border-radius: 9px 2px 9px 2px; color: #70defa; background: rgba(0, 10, 18, .9); box-shadow: inset 0 0 34px rgba(13, 95, 133, .09), 0 0 24px rgba(25,221,255,.025); font-size: 14px; }
.template-head h2 { font-size: 20px; }
.strategy-route-note { color: #65a9c7; }
.delivery-status { border: 1px solid transparent; border-radius: 5px; font: 800 14px/1 ui-monospace, Consolas, monospace; letter-spacing: .5px; }
.delivery-status.accepted { border-color: rgba(119,217,255,.2); color: #77d9ff; background: rgba(14,61,88,.7); }
.delivery-status.executed { border-color: rgba(70,244,170,.2); color: #83f7c3; background: rgba(18,66,50,.58); }
.delivery-status.failed { border-color: rgba(255,85,120,.2); color: #ff9bb0; background: rgba(87,24,43,.7); }

.account-manager { border-color: rgba(25,221,255,.25); border-radius: 14px 3px 14px 3px; background: linear-gradient(145deg, rgba(8,29,46,.94), rgba(3,14,25,.96)); }
.account-manager::before { height: 2px; background: linear-gradient(90deg, var(--green), var(--cyan) 48%, transparent 88%); box-shadow: 0 0 14px rgba(25,221,255,.5); }
.account-manager-head { border-bottom-color: rgba(75, 151, 194, .19); }
.account-title-icon { border-color: rgba(25,221,255,.36); border-radius: 10px 3px 10px 3px; color: #7df4d4; background: linear-gradient(145deg, rgba(17,83,78,.7), rgba(7,41,55,.75)); box-shadow: 0 0 24px rgba(25,221,255,.08); }
.simulation-chip, .secure-chip, .account-status, .account-demo, .account-count { border-radius: 5px; font-family: ui-monospace, Consolas, monospace; letter-spacing: .5px; }
.credential-panel { border-right-color: rgba(75,151,194,.18); background: rgba(2, 15, 27, .44); }
.eyebrow { color: #4acbea; font-family: ui-monospace, Consolas, monospace; }
.account-card { border-color: rgba(75,151,194,.25); border-radius: 10px 2px 10px 2px; background: linear-gradient(145deg, rgba(13,42,65,.8), rgba(4,18,31,.92)); }
.account-card::before { width: 2px; background: linear-gradient(var(--cyan), transparent); box-shadow: 0 0 9px var(--cyan); }
.account-avatar { border: 1px solid rgba(25,221,255,.23); border-radius: 8px 2px 8px 2px; color: #95e9ff; background: rgba(14, 67, 96, .62); }
.account-card-head, .account-card-actions { border-color: rgba(66,135,174,.17); }
.account-detail-row { border-bottom-color: rgba(66,135,174,.14); }
.safety-card li { color: #8ca9bb; line-height: 1.55; }

.media-card { border-color: rgba(75,151,194,.24); border-radius: 10px 2px 10px 2px; background: rgba(5,20,33,.9); box-shadow: var(--panel-glow); }
.connection-line { border-radius: 7px 2px 7px 2px; background: rgba(1,12,21,.72); }
.empty, .account-list-empty { border-color: rgba(64,147,194,.32); border-radius: 10px 2px 10px 2px; background: rgba(3,15,26,.44); }

dialog {
  border-color: rgba(25,221,255,.34);
  border-radius: 14px 3px 14px 3px;
  background: linear-gradient(145deg, rgba(10,31,49,.98), rgba(3,14,25,.99));
  box-shadow: 0 35px 120px rgba(0,0,0,.75), 0 0 38px rgba(25,221,255,.08), inset 0 1px rgba(154,224,255,.08);
}
dialog::backdrop { background: rgba(0, 5, 12, .78); backdrop-filter: blur(9px); }
dialog form { position: relative; }
dialog form::before { content: ''; position: absolute; left: 24px; right: 58%; top: 0; height: 2px; background: linear-gradient(90deg, var(--cyan), transparent); box-shadow: 0 0 12px var(--cyan); }
.icon-button { border-color: rgba(69,151,198,.3); background: rgba(14,43,65,.8); }

#toast { border-color: rgba(25,221,255,.44); border-radius: 9px 2px 9px 2px; color: #daf7ff; background: rgba(8,40,58,.96); box-shadow: 0 18px 65px rgba(0,0,0,.62), 0 0 24px rgba(25,221,255,.1); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
}

@media (max-width: 1050px) {
  main { padding-left: 32px; padding-right: 32px; }
  .header-status { gap: 8px; }
  .node-chip { display: none; }
  .tab { padding: 0 16px; }
}

/* Orbital space theme */
:root {
  --bg: #050611;
  /* 2026-08-18：不透明度 .78/.72 -> .93/.90。內容表面要夠實，資料才不會躺在
     一張會變亮的照片上（大企業級產品的作法：照片只負責氛圍，內容區是實的）。
     ⚠ 誠實邊界：總覽那四張 .metric 卡片**不吃這個 token** —— 它們在下面用寫死的
     漸層自己蓋掉了，所以改這裡對它們零效果（我實測過，畫面一模一樣）。
     真正管到那四張卡的是 `.metric` 的 background 那條，兩處都要動。 */
  --surface: rgba(13, 17, 39, .93);
  --surface-2: rgba(20, 25, 55, .90);
  --border: rgba(163, 174, 255, .2);
  --border-hot: rgba(153, 181, 255, .48);
  --text: #f3f4ff;
  --muted: #8e96bb;
  --blue: #6c8cff;
  --cyan: #78e5ff;
  --violet: #9d7cff;
  --magenta: #e38cff;
  --green: #72f2c3;
  --red: #ff708e;
  --amber: #ffd37a;
  --panel-glow: 0 28px 75px rgba(0, 0, 0, .34), inset 0 1px rgba(224, 228, 255, .055);
}

body {
  background:
    radial-gradient(ellipse at 82% 0%, rgba(95, 65, 190, .19), transparent 34%),
    radial-gradient(ellipse at 9% 20%, rgba(34, 111, 184, .16), transparent 31%),
    radial-gradient(ellipse at 50% 110%, rgba(86, 45, 140, .16), transparent 38%),
    linear-gradient(155deg, #080a1a 0%, #04050e 48%, #080716 100%);
}

.ambient-grid {
  z-index: 0;
  opacity: .92;
  background-image:
    radial-gradient(circle, rgba(255,255,255,.9) 0 1px, transparent 1.4px),
    radial-gradient(circle, rgba(164,204,255,.68) 0 1px, transparent 1.5px),
    radial-gradient(circle, rgba(255,255,255,.45) 0 1px, transparent 1.5px);
  background-size: 137px 137px, 211px 211px, 307px 307px;
  background-position: 17px 29px, 83px 117px, 151px 41px;
  -webkit-mask-image: none;
  mask-image: none;
  animation: star-drift 80s linear infinite;
}

.app-header, .tabs, main { position: relative; z-index: 1; }
/* fixed 子層不能逃出 main 的 stacking context；全螢幕時把整個工作區提到頂欄之上。 */
body.workbench-fullscreen-active main { z-index: 10000; }
/* The existing AI card class is the presentation owner's sole projection.
   Raise its parent stacking context above navigation, below native titlebar. */
body:has(.ai-chat-card.is-presentation-fullscreen) main { z-index: 10000; }
html[data-host="tauri"] .ai-chat-card.is-presentation-fullscreen { top: var(--qw-titlebar-h, 44px); }
/* ⋯ 選單掛在 body，必須高於全螢幕 main；否則按鈕有收到點擊，選單卻畫在背後。 */
body.workbench-fullscreen-active > .wb-menu { z-index: 20040; }

.ambient-grid::before {
  inset: -15% -10%;
  background:
    radial-gradient(ellipse at 76% 20%, rgba(141, 95, 255, .17), transparent 20%),
    radial-gradient(ellipse at 68% 26%, rgba(58, 170, 255, .12), transparent 27%),
    radial-gradient(ellipse at 24% 72%, rgba(195, 96, 255, .08), transparent 24%);
  filter: blur(16px);
}

.ambient-grid::after {
  left: auto;
  right: 5vw;
  top: 160px;
  width: min(34vw, 510px);
  height: min(34vw, 588px);
  border: 1px solid rgba(150, 175, 255, .13);
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, rgba(218, 231, 255, .34), transparent 4%),
    radial-gradient(circle at 35% 33%, #586fa4 0, #27355e 19%, #12182f 49%, #080a18 69%, transparent 70%),
    radial-gradient(circle, rgba(120, 151, 255, .14), transparent 72%);
  box-shadow:
    -34px -12px 90px rgba(105, 151, 255, .11),
    0 0 0 46px rgba(134, 125, 255, .015),
    0 0 0 105px rgba(91, 80, 193, .012);
  filter: drop-shadow(0 0 35px rgba(100, 128, 255, .1));
  animation: planet-float 10s ease-in-out infinite;
}

@keyframes star-drift { to { background-position: 154px 166px, 294px 328px, 458px 348px; } }
@keyframes planet-float { 0%, 100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-12px) rotate(-2deg); } }

.brand-mark {
  width: 54px;
  height: 64px;
  border-color: rgba(178, 184, 255, .42);
  border-radius: 50%;
  color: #f0ebff;
  background: radial-gradient(circle at 35% 28%, #bfcaff, #667eea 30%, #352a72 65%, #15132d 100%);
  box-shadow: 0 0 0 7px rgba(133, 124, 255, .05), 0 0 34px rgba(118, 114, 255, .25), inset -8px -10px 18px rgba(4, 6, 22, .4);
  transform: none;
}
.brand-mark::before {
  inset: 22px -9px;
  border: 1px solid rgba(176, 206, 255, .62);
  border-radius: 50%;
  transform: rotate(-18deg);
}
.brand-mark::after { display: none; }
.brand-mark i { font-size: 18px; text-shadow: 0 0 12px white; transform: none; }
.brand-mark img { width: 46px; height: 52px; display: block; object-fit: contain; }
.brand strong { font-family: "Segoe UI Variable", "Segoe UI", sans-serif; font-size: 24px; font-weight: 660; letter-spacing: .1px; }
.brand strong em { color: #b9a7ff; font-size: 14px; letter-spacing: 2.8px; text-shadow: 0 0 18px rgba(166, 135, 255, .5); }
.brand small { color: #747da5; font-family: "Segoe UI Variable", "Segoe UI", sans-serif; font-size: 14px; letter-spacing: 2.4px; }

.node-chip {
  border-color: rgba(161, 173, 255, .17);
  border-radius: 999px;
  color: #7e86aa;
  background: rgba(17, 20, 45, .55);
}
.mode-badge {
  border-color: rgba(114, 242, 195, .28);
  border-radius: 999px;
  color: #a2f5d6;
  background: rgba(17, 57, 52, .42);
  box-shadow: 0 0 28px rgba(86, 238, 190, .05);
}

.tabs {
  height: 76px;
  border-bottom-color: rgba(151, 162, 232, .12);
  background: rgba(8, 10, 26, .62);
}
.tab {
  border-radius: 999px;
  color: #7f87aa;
  font-size: 14px;
  font-weight: 650;
}
.tab::before { width: 3px; height: 3px; box-shadow: 0 0 9px currentColor; }
.tab:hover { border-color: rgba(162, 174, 255, .16); color: #cbd0ee; background: rgba(60, 65, 119, .18); }
.tab.active {
  border-color: rgba(159, 175, 255, .28);
  color: #f4f2ff;
  background: linear-gradient(120deg, rgba(100, 111, 224, .34), rgba(111, 78, 174, .25));
  box-shadow: 0 9px 28px rgba(59, 51, 131, .18), inset 0 1px rgba(255,255,255,.07);
}
.tab.active::after { left: 27%; right: 27%; bottom: -13px; height: 1px; background: #afa5ff; box-shadow: 0 0 14px #8e82ff; }
.status-link { color: #9ba9e8; font-family: "Segoe UI", sans-serif; }

.metric {
  min-height: 184px;
  border-color: rgba(156, 168, 241, .2);
  border-radius: 22px;
  background:
    radial-gradient(circle at 90% 15%, rgba(132, 114, 255, .11), transparent 31%),
    linear-gradient(145deg, rgba(23, 28, 60, .74), rgba(9, 12, 29, .82));
  box-shadow: var(--panel-glow);
  backdrop-filter: blur(18px);
}
.metric:hover { border-color: rgba(177, 173, 255, .4); box-shadow: 0 28px 85px rgba(0,0,0,.4), 0 0 36px rgba(124,108,255,.07); }
.metric::before { color: rgba(183, 176, 255, .55); letter-spacing: 1.2px; }
.metric::after {
  right: -46px;
  bottom: -62px;
  border-color: rgba(177, 187, 255, .13);
  background: radial-gradient(circle at 34% 30%, rgba(166, 191, 255, .18), rgba(79, 85, 157, .08) 38%, transparent 68%);
  box-shadow: 0 0 0 22px rgba(133, 123, 255, .018), 0 0 0 49px rgba(133, 123, 255, .012);
}
.metric > span { color: #a2a8c7; }
.metric strong { color: #f8f7ff; font-family: "Segoe UI Variable", "Segoe UI", sans-serif; font-weight: 620; text-shadow: 0 0 28px rgba(175,176,255,.12); }
.metric small { color: #7e86aa; }

.section-title h1, .section-title h2 { font-family: "Segoe UI Variable", "Segoe UI", sans-serif; }
.section-title h1::before, .section-title h2::before { content: '✦'; margin-right: 16px; color: #a895ff; font-family: inherit; font-size: .7em; text-shadow: 0 0 18px rgba(168,149,255,.55); }

.primary {
  border-color: rgba(179, 182, 255, .36);
  background: linear-gradient(135deg, #667eea, #8b5fd3);
  box-shadow: 0 10px 30px rgba(92, 72, 191, .26), inset 0 1px rgba(255,255,255,.18);
}
.primary:hover { box-shadow: 0 13px 38px rgba(106, 82, 211, .34), 0 0 20px rgba(153,131,255,.14); }
.secondary { border-color: rgba(156, 168, 233, .22); color: #c5c9e5; background: rgba(28, 34, 68, .62); }
.danger { border-color: rgba(255, 112, 142, .28); color: #ffadc0; background: rgba(80, 26, 49, .56); }

.card, .bot-card {
  border-color: rgba(157, 167, 229, .18);
 
  background:
    radial-gradient(circle at 100% 0%, rgba(111, 91, 214, .08), transparent 28%),
    linear-gradient(145deg, rgba(19, 24, 52, .78), rgba(8, 11, 27, .84));
  box-shadow: var(--panel-glow);
  backdrop-filter: blur(20px) saturate(115%);
}
.bot-card::before { left: 22px; top: 0; width: 80px; height: 1px; background: linear-gradient(90deg, transparent, #b4a8ff, transparent); box-shadow: 0 0 15px rgba(176,164,255,.5); }
.bot-card:hover { border-color: rgba(174,171,255,.36); }
.bot-stats div { border-color: rgba(153, 163, 225, .1); border-radius: 13px; background: rgba(5, 8, 22, .48); }
.bot-stats div::after { width: 24px; background: #a798ff; }
.webhook { border-color: rgba(147, 161, 231, .14); background: rgba(5, 8, 22, .48); }
.webhook code { color: #a8d9ff; }

input, select {
  border-color: rgba(151, 163, 226, .22);
 
 
  background: rgba(7, 10, 28, .64);
  box-shadow: inset 0 0 22px rgba(105, 95, 192, .025);
}
input::placeholder { color: #5f6688; }
input:focus, select:focus { border-color: rgba(171,155,255,.65); box-shadow: 0 0 0 3px rgba(154,130,255,.08), 0 0 24px rgba(126,104,218,.06); }

.table-wrap { border-color: rgba(152, 163, 225, .18); border-radius: 18px; background: rgba(8, 11, 28, .74); backdrop-filter: blur(18px); }
th { color: #969dbc; background: rgba(21, 25, 54, .9); font-family: "Segoe UI", sans-serif; }
th, td { border-bottom-color: rgba(144, 155, 216, .1); }
tbody tr:hover { background: rgba(112, 99, 199, .08); }

.receiver-status {
  border-color: rgba(150, 163, 229, .2);
  border-radius: 16px;
  background: rgba(6, 10, 26, .58);
}
.receiver-status::after { color: rgba(164, 158, 232, .45); content: 'ORBITAL UPLINK'; }
.copy-field code { border-color: rgba(144, 158, 226, .22); border-radius: 13px; color: #a7dfff; background: rgba(5, 8, 22, .72); }
.notice { border-left-color: #d7b56d; color: #d9c38e; background: rgba(66, 50, 22, .32); }
.json-template { border-color: rgba(134, 160, 255, .25); border-radius: 16px; color: #a9ddff; background: rgba(4, 7, 20, .76); box-shadow: inset 0 0 42px rgba(86,72,159,.07); }
.strategy-route-note { color: #929cc4; }
.delivery-status { border-radius: 999px; }

.account-manager { border-color: rgba(158, 168, 232, .2); border-radius: 24px; background: linear-gradient(145deg, rgba(19,24,52,.82), rgba(8,11,27,.88)); }
.account-manager::before { height: 1px; background: linear-gradient(90deg, transparent, #83dfff 26%, #b18cff 68%, transparent); box-shadow: 0 0 16px rgba(160,139,255,.4); }
.account-title-icon { border-color: rgba(166, 166, 241, .26); border-radius: 50%; color: #aee8ff; background: radial-gradient(circle at 35% 30%, rgba(114,213,255,.34), rgba(82,73,155,.46)); }
.simulation-chip, .secure-chip, .account-status, .account-demo, .account-count { border-radius: 999px; }
.credential-panel { border-right-color: rgba(149,159,219,.13); background: rgba(6,9,24,.3); }
.eyebrow { color: #a996ff; font-family: "Segoe UI", sans-serif; }
.account-card { border-color: rgba(151,162,224,.18); border-radius: 18px; background: rgba(15,20,46,.68); }
.account-card::before { width: 1px; background: linear-gradient(transparent, #9e8fff, transparent); box-shadow: 0 0 12px rgba(158,143,255,.5); }
.account-avatar { border-color: rgba(163,167,236,.2); border-radius: 50%; color: #c5e7ff; background: rgba(76,81,151,.42); }

.media-card, .connection-line, .empty, .account-list-empty { border-radius: 18px; }
.empty, .account-list-empty { border-color: rgba(148, 160, 224, .24); background: rgba(6,9,24,.35); }

dialog {
  border-color: rgba(167, 168, 238, .24);
  border-radius: 26px;
  background:
    radial-gradient(circle at 82% 0%, rgba(119,91,203,.16), transparent 28%),
    linear-gradient(145deg, rgba(20,25,55,.98), rgba(7,10,26,.99));
  box-shadow: 0 38px 130px rgba(0,0,0,.78), 0 0 70px rgba(94,77,185,.1), inset 0 1px rgba(220,220,255,.07);
}
dialog::backdrop { background: rgba(2, 3, 12, .82); backdrop-filter: blur(12px); }
dialog form::before { left: 42%; right: 42%; height: 1px; background: #b3a3ff; box-shadow: 0 0 20px rgba(179,163,255,.7); }
.icon-button { border-color: rgba(160,166,230,.22); border-radius: 50%; background: rgba(42,46,84,.6); }

#toast { border-color: rgba(167,169,239,.3); border-radius: 18px; color: #eff0ff; background: rgba(27,30,68,.94); box-shadow: 0 20px 70px rgba(0,0,0,.64), 0 0 30px rgba(127,107,218,.1); }

@media (prefers-reduced-motion: reduce) {
  .ambient-grid, .ambient-grid::after { animation: none !important; }
}

/* Cinematic orbit presentation */
body {
  background: #02030a;
}

.ambient-grid {
  opacity: 1;
  background:
    linear-gradient(180deg, rgba(1, 3, 12, .16) 0%, rgba(2, 4, 14, .22) 45%, rgba(2, 3, 10, .82) 100%),
    linear-gradient(90deg, rgba(2, 4, 13, .34), transparent 50%, rgba(4, 4, 18, .04)),
    url('/renderer-assets/2820eb82c9728f599d004a95967f5380a89b9505430984c31ee8ad630696faa0/assets/cinematic-orbit-v1.png') center top / cover no-repeat;
  animation: none;
}

.ambient-grid::before {
  inset: 0;
  background:
    radial-gradient(ellipse at center, transparent 28%, rgba(1, 2, 8, .18) 72%, rgba(1, 2, 7, .52) 100%),
    linear-gradient(180deg, rgba(2, 3, 10, .02), rgba(2, 3, 10, .48));
  filter: none;
}

.ambient-grid::after { display: none; }

.tabs {
  background: linear-gradient(90deg, rgba(5, 8, 23, .83), rgba(9, 9, 28, .67));
  border-bottom-color: rgba(175, 187, 242, .14);
}

main {
  padding-top: 64px;
}

.metric {
  border-color: rgba(186, 199, 255, .2);
  /* 2026-08-18：.8/.7 -> .95/.9。放大區塊之後這四張卡覆蓋到背景地球的亮部，
     卡內次要文字幾乎讀不到 —— 是「放大」的直接副作用，不是既有缺陷。
     ⛔ 別改回半透明來「保留質感」：讀不到的資料沒有質感可言。 */
  background:
    linear-gradient(145deg, rgba(16, 22, 47, .95), rgba(5, 8, 22, .9)),
    radial-gradient(circle at 88% 14%, rgba(113, 139, 255, .14), transparent 34%);
  box-shadow: 0 30px 80px rgba(0,0,0,.36), inset 0 1px rgba(235,240,255,.07);
  backdrop-filter: blur(26px) saturate(120%);
}

.metric::after {
  background: radial-gradient(circle at 35% 32%, rgba(181, 207, 255, .19), rgba(75, 91, 164, .08) 40%, transparent 69%);
}

.metric:hover {
  border-color: rgba(196, 196, 255, .42);
  box-shadow: 0 34px 92px rgba(0,0,0,.42), 0 0 38px rgba(121,119,255,.08);
}

.card, .bot-card {
  border-color: rgba(177, 190, 244, .18);
  /* ⛔ 0.3.41 路標：改主題色時**別改這裡**，這一組對現有任何一張卡都不是 cascade 贏家。
     實測（瀏覽器逐元素問出來的，不是讀碼推的）——真正在畫卡片表面的是：
       機器人卡 / 雲端卡 / 設定卡  → `.module-card`（本檔約 1845 行）
                                    ＊app.js:1766 渲染的就是 class="bot-card module-card"
       TradingView 接收卡          → `.receiver-grid .card`（約 891 行，特異性 0,2,0 最高）
       四張指標卡                  → `.metric.telemetry-card`（約 921 行）
       歷史表格容器                → `.module-table`
     index.html 裡每一個 .card 都同時帶 module-card ⇒ 這一組的 background 永遠被蓋掉。
     這正是 VIS-10「沒有單一真相源，改了不知道會不會生效」的實例：0.3.41 修 VIS-11 時
     第一版就改在這裡，量出來四張卡一格都沒動。 */
  background:
    linear-gradient(145deg, rgba(13, 18, 42, .83), rgba(5, 8, 21, .76)),
    radial-gradient(circle at 100% 0%, rgba(123, 108, 224, .08), transparent 30%);
  box-shadow: 0 32px 90px rgba(0, 0, 0, .38), inset 0 1px rgba(230, 235, 255, .055);
  backdrop-filter: blur(27px) saturate(120%);
}

.receiver-grid .card {
  /* 0.3.41 VIS-11 ⚠ 特異性 (0,2,0) ⇒ TradingView 接收頁的卡片表面由**這裡**決定，
     連 `.module-card`（約 1845 行）都蓋不過它。跟著那組一起提亮，否則同一個 app 裡
     只有這一頁的卡片是暗的（半套的一致性改動比不改更糟）。 */
  background: linear-gradient(145deg, rgba(35, 45, 86, .93), rgba(20, 27, 56, .89));
}

.table-wrap {
  border-color: rgba(177, 190, 244, .17);
  background: rgba(5, 8, 21, .78);
  box-shadow: 0 28px 75px rgba(0,0,0,.34), inset 0 1px rgba(230,235,255,.04);
  backdrop-filter: blur(24px);
}

.account-manager {
  background: linear-gradient(145deg, rgba(13, 18, 43, .9), rgba(4, 7, 20, .83));
  box-shadow: 0 35px 100px rgba(0,0,0,.42), inset 0 1px rgba(230,235,255,.06);
}

.empty, .account-list-empty {
  background: rgba(4, 7, 19, .55);
  backdrop-filter: blur(18px);
}

dialog {
  background:
    radial-gradient(circle at 86% 0%, rgba(120, 94, 213, .16), transparent 28%),
    linear-gradient(145deg, rgba(19, 24, 54, .98), rgba(5, 8, 22, .99));
}

/* Orbital telemetry cards */
.metric-grid { gap: 16px; }

.metric.telemetry-card {
 
  min-height: 160px;
  padding: 24px 24px 24px;
  border: 1px solid color-mix(in srgb, var(--tone) 24%, rgba(175, 187, 241, .18));
 
  /* 0.3.41 VIS-11 ⚠ 表面亮度是承重的，⛔ 別為了「更沉穩」再壓暗回去。
     深色介面的層級靠**更亮的表面**表達，不是靠陰影 —— 在 #050611 這種近黑底上，
     黑色陰影與背景的亮度差是 0.00203 → 0.00124，對比 1.015，人眼看不到任何東西
     （全檔 38 條純黑陰影都在付合成層的繪製成本、換不到任何視覺層級）。
     ⇒ 陰影改帶色相（在深底上才浮得出來），層級改由表面亮度扛。
     判準是量出來的：卡面 vs 頁底對比 ≥1.25（改前 1.17）。 */
  background:
    linear-gradient(140deg, color-mix(in srgb, var(--tone) 7%, rgba(26, 33, 68, .90)), rgba(13, 18, 44, .86)),
    rgba(16, 21, 48, .84);
  box-shadow: 0 16px 44px rgba(58, 48, 148, .42), inset 0 1px rgba(239,243,255,.075);
  backdrop-filter: blur(24px) saturate(118%);
}


.metric.telemetry-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 20px;
  width: 68px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--tone), transparent);
  box-shadow: 0 0 15px color-mix(in srgb, var(--tone) 60%, transparent);
}

.metric.telemetry-card::after {
  content: '';
  position: absolute;
  top: -48px;
  right: -38px;
  bottom: auto;
  width: 124px;
  height: 144px;
  border: 0;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--tone) 14%, transparent), transparent 68%);
  box-shadow: none;
}

.metric.telemetry-card:hover {
  border-color: color-mix(in srgb, var(--tone) 43%, rgba(180,190,240,.2));
  box-shadow: 0 28px 80px rgba(0,0,0,.38), 0 0 28px color-mix(in srgb, var(--tone) 7%, transparent);
}

.metric-head {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 16px;
}

.metric-head > .metric-icon {
  width: 36px;
  height: 40px;
  display: grid;
  flex: 0 0 36px;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--tone) 28%, transparent);
  border-radius: 11px;
  color: var(--tone);
  background: color-mix(in srgb, var(--tone) 9%, rgba(7,10,27,.76));
  box-shadow: inset 0 0 14px color-mix(in srgb, var(--tone) 5%, transparent), 0 0 18px color-mix(in srgb, var(--tone) 5%, transparent);
}

.metric-icon svg {
  width: 20px;
  height: 20px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.55;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.metric-label { min-width: 0; flex: 1; }
.metric .metric-label > small { display: block; margin: 4px 0 0; color: color-mix(in srgb, var(--tone) 65%, #646c92); font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: 1.05px; }

.metric-beacon {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  color: var(--tone);
  background: currentColor;
  animation: status-pulse 2.7s ease-in-out infinite;
}

.metric-reading {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: 16px;
}

.metric .metric-reading > strong {
  margin: 0;
  color: #f7f8ff;
  font: 620 36px/1 "Segoe UI Variable", "Segoe UI", sans-serif;
 
  text-shadow: 0 0 24px color-mix(in srgb, var(--tone) 10%, transparent);
}

.metric .metric-reading > small {
  margin: 0;
 /* 0.3.41 VIS-11 連動：卡面提亮後 5.08→4.49 掉破 AA，提亮到 4.82 */
  font: 650 14px/1.2 "Segoe UI", sans-serif;
  letter-spacing: .35px;
}

.metric .metric-signal {
  position: absolute;
  left: 20px;
  right: 20px;
  bottom: 0;
  height: 1px;
  overflow: hidden;
  background: rgba(145, 158, 213, .08);
}

.metric-signal i {
  display: block;
  width: 44%;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--tone), transparent);
  opacity: .58;
  transform: translateX(-30%);
}

.telemetry-card:nth-child(2) .metric-signal i { width: 58%; transform: translateX(22%); }
.telemetry-card:nth-child(3) .metric-signal i { width: 72%; transform: translateX(5%); }
.telemetry-card:nth-child(4) .metric-signal i { width: 55%; transform: translateX(72%); }

/* Unified orbital interface system */
body { color: #eff2ff; }

.section-kicker {
  display: block;
  margin-bottom: 8px;
  color: #8f9ee2;
  font: 750 14px/1 ui-monospace, SFMono-Regular, Consolas, monospace;
  letter-spacing: 1.65px;
}

.section-title { align-items: end; margin: 48px 0 24px; }
.section-title h1, .section-title h2 { margin-bottom: 8px; color: #f4f5ff; font-family: "Segoe UI Variable", "Segoe UI", sans-serif; }
.section-title h1::before, .section-title h2::before { display: none; }
.section-title p { max-width: 760px; line-height: 1.65; }

.module-card {
  position: relative;
  overflow: hidden;
  border-color: rgba(159, 176, 235, .2);
  background:
    linear-gradient(145deg, rgba(12, 17, 40, .89), rgba(4, 7, 19, .82)),
    rgba(7, 10, 26, .8);
  box-shadow: 0 28px 80px rgba(0,0,0,.34), inset 0 1px rgba(236,240,255,.055);
}

.module-card::after {
  content: attr(data-module);
  position: absolute;
  top: 18px;
  right: 20px;
  z-index: 2;
  color: #6974a7;
  font: 700 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1.3px;
}

.module-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 22px;
  width: 74px;
  height: 1px;
  background: linear-gradient(90deg, transparent, #8fa7ff, transparent);
  box-shadow: 0 0 14px rgba(134,157,255,.52);
}

.form-card { padding: 32px; }
.form-card h2 { color: #f0f2ff; }
.muted { color: #8b94b2; font-size: 14px; line-height: 1.6; }

label {
  margin: 24px 0;
 
 
 
 
}
label input, label select { margin-top: 12px; }
/* 0.3.41 VIS-11 連動 ⚠ 這一批「卡片上的淡色說明文字」是跟著卡片表面提亮一起調的，
   ⛔ 別單獨把它們調暗回去。理由：VIS-11 把卡片表面從對比 1.05–1.17 提到 1.33–1.38 之後，
   這些字的對比全部掉破 WCAG AA 的 4.5（實測前後：#717c9f 4.67→4.18、#7e88a9 5.17→3.81、
   #7e87a7 5.09→4.15、#7c86a8 5.46→4.50、#838dac 4.98→4.00、#8593b7 5.70→4.48）——
   它們本來就只有 0.1–0.7 的餘裕，表面一亮就沒了。現值對新表面留 ≥4.75。
   ⇒ 之後若再動任何一個卡片表面亮度，這一批（grep「VIS-11 連動」共 8 處）要重量一次。 */
.field-help { display: block; margin-top: 4px; color: #8693bc; font-size: 14px; font-weight: 550; line-height: 1.5; }

input, select {
  min-height: 52px;
  padding: 0 16px;
  border-color: rgba(151, 166, 224, .2);
 
 
  background: rgba(4, 7, 20, .68);
}
input:hover, select:hover { border-color: rgba(160, 174, 234, .34); }

.receiver-grid { gap: 24px; }
.receiver-grid .form-card { min-height: 100%; }
.receiver-status {
  margin-bottom: 24px;
  padding: 24px 24px;
  border-color: rgba(150, 166, 226, .18);
  border-radius: 13px;
  background: rgba(3, 7, 20, .58);
  box-shadow: inset 0 1px rgba(236,240,255,.035);
}
.receiver-status::after { top: 10px; right: 12px; color: #626d99; font-size: 14px; letter-spacing: 1.25px; }
.receiver-status strong { color: #f0f2ff; font-size: 16px; font-weight: 680; }
.receiver-status small { color: #8993b6; font-size: 14px; } /* 0.3.41 VIS-11 連動 */

.copy-field { gap: 12px; margin-top: 12px; }
.copy-field code {
  padding: 16px 16px;
  border-color: rgba(119, 165, 232, .22);
  border-radius: 11px;
  color: #9ed7ff;
  background: rgba(2, 6, 18, .78);
  font-size: 14px;
}
.strategy-route-note { color: #8590b4; font-size: 14px; }
.strategy-route-note code { color: #b4dfff; }
.notice { padding: 16px 24px; border-left-width: 2px; color: #d4c18d; font-size: 14px; }

.template-head { align-items: start; }
.template-head h2 { margin: 0 0 8px; font-size: 20px; }
.template-head .section-kicker { margin-bottom: 8px; }
.json-template {
  position: relative;
  min-height: 352px;
  margin: 24px 0 16px;
  padding: 64px 24px 24px;
  border-color: rgba(121, 153, 221, .2);
  border-radius: 14px;
  color: #a7d9ff;
  background: rgba(2, 5, 16, .76);
  font-size: 14px;
  line-height: 1.72;
}
.json-template::before {
  content: 'JSON PAYLOAD  /  READ ONLY';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 30px;
  padding: 0 16px;
  border-bottom: 1px solid rgba(127, 145, 207, .12);
  color: #5f6b99;
  background: rgba(19, 24, 51, .36);
  font: 700 14px/51px ui-monospace, Consolas, monospace;
  letter-spacing: 1.25px;
}
.receiver-help { color: #8893b8; font-size: 14px; } /* 0.3.41 VIS-11 連動 */

.module-table {
  position: relative;
  padding-top: 48px;
  border-color: rgba(157, 172, 229, .18);
  border-radius: 16px;
  background: rgba(4, 7, 19, .76);
}
.module-table::before {
  content: attr(data-module);
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 36px;
  padding: 0 24px;
  border-bottom: 1px solid rgba(137, 151, 207, .11);
  color: #65709c;
  background: rgba(18, 22, 47, .36);
  font: 700 14px/55px ui-monospace, Consolas, monospace;
  letter-spacing: 1.35px;
}
th { height: 48px; padding: 16px 24px; color: #8e98b9; background: rgba(15, 20, 44, .75); font-size: 14px; font-weight: 720; letter-spacing: .8px; }
td { height: 56px; color: #cfd4e8; font-size: 14px; }

.filters {
  grid-template-columns: 190px 190px 1fr;
  gap: 12px;
  margin-bottom: 16px;
  padding: 16px;
  border: 1px solid rgba(152, 167, 225, .15);
  border-radius: 15px;
  background: rgba(5, 8, 21, .58);
  backdrop-filter: blur(18px);
}

.bot-card.module-card::after { display: none; }
.bot-card {
  padding: 32px;
 
  /* ⛔ 0.3.41 路標：這一行也不是機器人卡的 cascade 贏家 —— app.js:1766 渲染出來的是
     class="bot-card module-card"，而 `.module-card`（約 1845 行）排在本行之後、
     特異性相同 ⇒ 它贏。想改機器人卡表面請改那裡。 */
  background: linear-gradient(145deg, rgba(11,17,39,.9), rgba(4,7,19,.84));
}
.bot-card::before { left: 24px; width: 76px; background: linear-gradient(90deg, transparent, #84a4ff, transparent); }
.bot-identity { min-width: 0; }
.card-code { display: block; margin-bottom: 8px; color: #7181bd; font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: 1.05px; }
.bot-head h3 { margin-bottom: 8px; color: #f2f4ff; }
.bot-head p { font: 560 14px/1.45 "Segoe UI", sans-serif; letter-spacing: .25px; }
.badge { padding: 8px 12px; letter-spacing: .65px; }

.connection-line {
  align-items: center;
  gap: 16px;
  margin: 24px 0 8px;
  padding: 16px 16px;
  border: 1px solid rgba(147,162,219,.14);
  border-radius: 12px;
  background: rgba(3,7,19,.58);
}
.connection-line .connection-orb { width: 8px; height: 8px; flex: 0 0 8px; border-radius: 50%; background: #7983a5; box-shadow: 0 0 10px #7983a555; }
.connection-line.connected .connection-orb { background: var(--green); box-shadow: 0 0 12px #72f2c388; }
.connection-line.error .connection-orb { background: var(--red); box-shadow: 0 0 12px #ff708e88; }
.connection-line > div { min-width: 0; }
.connection-line small { display: block; color: #68749e; font: 700 14px/1 ui-monospace, Consolas, monospace; letter-spacing: 1.1px; }
.connection-line strong { display: block; margin-top: 4px; overflow: hidden; color: #bfc6dd; font-size: 14px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }

.bot-stats { margin: 16px 0 24px; }
.bot-stats div { min-height: 76px; padding: 16px; border-color: rgba(143,158,214,.1); border-radius: 12px; }
.bot-stats strong { color: #eef1ff; font-size: 16px; font-weight: 650; }
.bot-actions { padding-top: 3px; }
.bot-actions button { min-height: 40px; font-size: 14px; }
.webhook { margin-top: 24px; padding: 16px 16px; }
.webhook span { font: 700 14px/1 ui-monospace, Consolas, monospace; }
.webhook code { margin-top: 8px; color: #96cfff; font-size: 14px; }

.account-manager.module-card::after { top: 21px; right: 25px; }
.account-manager-head { padding: 32px 32px 32px; }
.account-manager-title h2 { margin-bottom: 8px; color: #f2f4ff; font-size: 30px; font-weight: 650; }
.account-manager-title p { color: #8993b4; font-size: 14px; } /* 0.3.41 VIS-11 連動 */
.account-title-icon { width: 46px; height: 52px; flex-basis: 46px; }
.account-title-icon svg { width: 25px; height: 25px; }
.credential-panel, .account-list-panel { padding: 32px; }
.subsection-heading h3 { color: #eef1ff; }
.account-form-hint { color: #8893b7; font-size: 14px; } /* 0.3.41 VIS-11 連動 */
.account-card { border-radius: 16px; }
.account-card-title h4 { color: #f1f3ff; font-size: 18px; }
.account-detail-row dt { color: #7983a4; font-size: 14px; }
.account-detail-row dd { color: #d9deee; font-size: 14px; }

#settingsForm.module-card, .safety-card.module-card { padding-top: 48px; }
#settingsForm.module-card::after, .safety-card.module-card::after { top: 19px; }
#settingsForm h2, .safety-card h2 { margin-bottom: 32px; font-size: 24px; }
.switch-row { border-bottom-color: rgba(139,154,211,.13); }
.switch-row span strong { color: #dce0ef; font-size: 14px; }
.switch-row span small { color: #7781a2; font-size: 14px; }
.safety-card ul { margin: 0; padding-left: 24px; }
.safety-card li { margin: 16px 0; color: #9ca5c2; font-size: 14px; }

.empty-module {
  position: relative;
  overflow: hidden;
  min-height: 208px;
  padding: 48px 32px;
  border-color: rgba(143, 160, 220, .21);
  background: rgba(3, 7, 19, .52);
  backdrop-filter: blur(18px);
}
.empty-module h3 { margin-bottom: 8px; color: #dfe3f3; font-size: 18px; }
.empty-module p { color: #7f89aa; font-size: 14px; }
.empty-orbit { position: relative; width: 44px; height: 52px; display: block; margin: 0 auto 24px; border: 1px solid rgba(139,155,220,.22); border-radius: 50%; }
.empty-orbit::before { content: ''; position: absolute; inset: 19px -9px; border: 1px solid rgba(146,161,226,.4); border-radius: 50%; transform: rotate(-16deg); }
.empty-orbit i { position: absolute; left: 50%; top: 50%; width: 5px; height: 5px; border-radius: 50%; background: #9b91ff; box-shadow: 0 0 12px #9b91ffaa; transform: translate(-50%,-50%); }

dialog { border-radius: 22px; }
dialog form { padding: 32px; }
.dialog-title { align-items: start; padding-bottom: 24px; border-bottom: 1px solid rgba(141,156,211,.13); }
.dialog-title h2 { margin-bottom: 8px; color: #f3f4ff; font-size: 30px; font-weight: 650; }
.dialog-title p { color: #818aa9; font-size: 14px; }
.dialog-actions { padding-top: 24px; border-top: 1px solid rgba(141,156,211,.11); }

button, .button { letter-spacing: .25px; }
.primary { color: #fff; }
.secondary { color: #c7cce0; }
.danger { color: #ffb0c2; }

@media (max-width: 0px) {
/* Disabled mission-deck experiment; retained temporarily for safe rollback. */
:root {
  --deck-cyan: #70dfff;
  --deck-violet: #a98cff;
  --deck-green: #67e5b1;
  --deck-amber: #f0bd68;
  --deck-red: #ff718f;
}

.section-title {
  position: relative;
  min-height: 128px;
  margin: 48px 0 32px;
  padding: 32px 32px 32px 48px;
  overflow: hidden;
  border: 1px solid rgba(152, 172, 239, .18);
  border-left: 3px solid var(--deck-violet);
  border-radius: 4px 24px 4px 4px;
  background:
    linear-gradient(90deg, rgba(22, 28, 62, .9), rgba(7, 10, 29, .68) 58%, rgba(36, 24, 65, .4)),
    rgba(5, 8, 22, .78);
  box-shadow: 0 26px 70px rgba(0, 0, 0, .28), inset 0 1px rgba(235, 240, 255, .05);
  backdrop-filter: blur(24px) saturate(118%);
}

.section-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 20px;
  bottom: 20px;
  width: 2px;
  background: linear-gradient(transparent, #c3b4ff, transparent);
  box-shadow: 0 0 18px rgba(169, 140, 255, .9);
}

.section-title::after {
  content: '';
  position: absolute;
  right: 38px;
  top: 50%;
  width: 104px;
  height: 120px;
  border: 1px solid rgba(154, 169, 235, .1);
  border-radius: 50%;
  box-shadow: 0 0 0 17px rgba(126, 116, 230, .018), 0 0 0 42px rgba(126, 116, 230, .012);
  transform: translateY(-50%);
  pointer-events: none;
}

.section-title > * { position: relative; z-index: 1; }
.section-title h1 { font-size: 36px; line-height: 1.12; letter-spacing: -.65px; }
.section-title h2 { font-size: 24px; line-height: 1.15; }
.section-title p { color: #96a1c3; font-size: 14px; }
.section-title .section-kicker { color: #a99bff; }
.section-title.compact { min-height: 112px; margin-top: 32px; }

button, .button {
  min-height: 48px;
  border-radius: 9px 2px 9px 2px;
  font-size: 14px;
  letter-spacing: .45px;
}

.primary {
  border-color: rgba(172, 183, 255, .46);
  background: linear-gradient(135deg, #5f79e6, #8a5fcf);
  box-shadow: 0 10px 28px rgba(95, 75, 198, .25), inset 0 1px rgba(255, 255, 255, .18);
}
.secondary { background: linear-gradient(145deg, rgba(31, 42, 82, .78), rgba(15, 21, 48, .82)); }
.danger { background: linear-gradient(145deg, rgba(91, 30, 54, .7), rgba(52, 19, 40, .78)); }

.module-card {
  --module-accent: var(--deck-violet);
  border: 1px solid color-mix(in srgb, var(--module-accent) 25%, rgba(146, 163, 222, .17));
  border-left: 4px solid color-mix(in srgb, var(--module-accent) 76%, transparent);
  border-radius: 4px 24px 4px 4px;
  background:
    linear-gradient(115deg, color-mix(in srgb, var(--module-accent) 5%, rgba(13, 18, 42, .94)), rgba(4, 7, 20, .86) 56%),
    rgba(5, 8, 22, .84);
  box-shadow: 0 32px 84px rgba(0,0,0,.38), inset 0 1px rgba(239,243,255,.055);
}

.module-card[data-module^="UPLINK"] { --module-accent: var(--deck-cyan); }
.module-card[data-module^="PAYLOAD"] { --module-accent: var(--deck-violet); }
.module-card[data-module^="IDENTITY"] { --module-accent: var(--deck-green); }
.module-card[data-module^="AUTOMATION"] { --module-accent: var(--deck-amber); }
.module-card[data-module^="SECURITY"] { --module-accent: var(--deck-red); }
.module-card[data-module^="TRADING"] { --module-accent: var(--deck-cyan); }

.module-card::before {
  top: 14px;
  left: -4px;
  width: 4px;
  height: 64px;
  background: var(--module-accent);
  box-shadow: 0 0 22px color-mix(in srgb, var(--module-accent) 72%, transparent);
}

.module-card::after {
  top: 15px;
  right: 17px;
  padding: 8px 12px;
  border: 1px solid color-mix(in srgb, var(--module-accent) 30%, transparent);
  border-radius: 6px 1px 6px 1px;
  color: color-mix(in srgb, var(--module-accent) 72%, #aeb7dc);
  background: color-mix(in srgb, var(--module-accent) 8%, rgba(5,8,22,.82));
  letter-spacing: 1.45px;
}

.receiver-status {
  min-height: 84px;
  border-left: 3px solid var(--module-accent);
  border-radius: 3px 14px 3px 3px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--module-accent) 8%, rgba(3,7,20,.8)), rgba(3,7,20,.6));
}

.template-head {
  min-height: 84px;
  margin: -25px -25px 20px;
  padding: 24px 32px;
  border-bottom: 1px solid rgba(159, 137, 255, .2);
  background: linear-gradient(90deg, rgba(92, 66, 167, .14), rgba(7, 10, 27, .3));
}
.template-head > div { min-width: 0; flex: 1; padding-right: 0; }
.template-head button { position: static; flex: 0 0 auto; margin-top: 32px; }

.json-template {
  border-left: 3px solid rgba(112, 199, 255, .62);
  border-radius: 3px 16px 3px 3px;
  background:
    linear-gradient(rgba(113, 143, 220, .025) 1px, transparent 1px) 0 0 / 100% 24px,
    rgba(2, 5, 16, .82);
}

.module-table {
  --table-accent: var(--deck-cyan);
  padding-top: 64px;
  overflow: hidden;
  border: 1px solid rgba(133, 169, 231, .21);
  border-left: 4px solid rgba(112, 209, 255, .72);
  border-radius: 4px 20px 4px 4px;
  box-shadow: 0 30px 82px rgba(0, 0, 0, .34), inset 0 1px rgba(235, 240, 255, .04);
}
.module-table::before {
  height: 48px;
  padding: 0 24px;
  color: #8ea7df;
  background: linear-gradient(90deg, rgba(40, 73, 120, .34), rgba(15, 20, 45, .6));
  font-size: 14px;
  line-height: 43px;
  letter-spacing: 1.7px;
}
.module-table::after {
  content: '即時資料';
  position: absolute;
  top: 0;
  right: 18px;
  height: 48px;
  color: rgba(110, 224, 255, .6);
  font: 700 14px/74px ui-monospace, Consolas, monospace;
  letter-spacing: 1.3px;
}
th { height: 56px; color: #a8b3d1; background: rgba(24, 31, 65, .86); font-size: 14px; }
td { height: 60px; }

.filters {
  position: relative;
  padding: 64px 16px 16px;
  border-left: 4px solid rgba(169, 140, 255, .66);
  border-radius: 4px 18px 4px 4px;
  background: linear-gradient(100deg, rgba(29, 27, 68, .66), rgba(5, 8, 22, .66));
}
.filters::before {
  content: 'LOG FILTER  /  QUERY CONTROL';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 40px;
  padding: 0 24px;
  border-bottom: 1px solid rgba(158, 143, 230, .15);
  color: #9188c8;
  font: 700 14px/54px ui-monospace, Consolas, monospace;
  letter-spacing: 1.5px;
}

.bot-card.module-card::after { display: block; }
.bot-card {
  padding: 32px;
  border-radius: 4px 24px 4px 4px;
}
.bot-head {
  margin: -24px -24px 0;
  padding: 32px 154px 24px 32px;
  border-bottom: 1px solid rgba(112, 208, 255, .16);
  background: linear-gradient(90deg, rgba(43, 92, 130, .17), rgba(6, 10, 27, .34));
}
.bot-head .badge { position: absolute; top: 55px; right: 22px; }
.bot-head h3 { font-size: 24px; letter-spacing: -.3px; }
.card-code { color: #81c9ec; }
.connection-line { margin-top: 24px; border-left: 3px solid #6bd6ff; border-radius: 3px 12px 3px 3px; }
.bot-stats { gap: 0; overflow: hidden; border: 1px solid rgba(137, 162, 218, .12); border-radius: 3px 14px 3px 3px; }
.bot-stats div { min-height: 84px; border: 0; border-right: 1px solid rgba(137, 162, 218, .12); border-radius: 0; background: rgba(3, 7, 20, .58); }
.bot-stats div:last-child { border-right: 0; }
.bot-stats span { color: #8190b6; }
.webhook { border-left: 3px solid rgba(169, 140, 255, .62); border-radius: 3px 12px 3px 3px; }

.account-manager-head {
  padding: 32px 178px 32px 32px;
  border-bottom: 1px solid rgba(103, 229, 177, .18);
  background: linear-gradient(90deg, rgba(42, 118, 96, .18), rgba(7, 10, 28, .3));
}
.account-manager-head .simulation-chip { position: absolute; top: 55px; right: 25px; }
.credential-panel { background: linear-gradient(145deg, rgba(19, 45, 48, .18), rgba(4, 7, 20, .24)); }
.account-list-panel { background: linear-gradient(145deg, rgba(21, 23, 52, .26), rgba(4, 7, 20, .2)); }
.account-card {
  border-left: 3px solid rgba(103, 229, 177, .65);
  border-radius: 3px 16px 3px 3px;
  background: linear-gradient(110deg, rgba(31, 77, 71, .2), rgba(10, 14, 34, .78));
}

#settingsForm.module-card, .safety-card.module-card { padding-top: 58px; }
#settingsForm.module-card > .section-kicker, .safety-card.module-card > .section-kicker {
  position: absolute;
  top: 18px;
  left: 23px;
}
#settingsForm h2, .safety-card h2 {
  margin: -10px -25px 20px;
  padding: 0 32px 24px;
  border-bottom: 1px solid color-mix(in srgb, var(--module-accent) 20%, transparent);
}
.switch-row {
  padding: 24px 16px;
  border: 1px solid rgba(145, 162, 218, .12);
  border-left: 3px solid color-mix(in srgb, var(--module-accent) 58%, transparent);
  border-radius: 3px 11px 3px 3px;
  background: rgba(3, 7, 20, .48);
}
.safety-card ul { list-style: none; padding: 0; counter-reset: security-step; }
.safety-card li {
  position: relative;
  min-height: 48px;
  margin: 12px 0;
  padding: 16px 16px 16px 64px;
  border: 1px solid rgba(255, 113, 143, .11);
  border-radius: 3px 10px 3px 3px;
  background: rgba(34, 10, 25, .2);
  counter-increment: security-step;
}
.safety-card li::before {
  content: '0' counter(security-step);
  position: absolute;
  left: 12px;
  top: 13px;
  color: rgba(255, 113, 143, .72);
  font: 700 14px/1 ui-monospace, Consolas, monospace;
}

.media-grid:has(.empty) { grid-template-columns: 1fr; }
.media-grid > .empty {
  position: relative;
  min-height: 288px;
  display: grid;
  align-content: center;
  justify-items: start;
  padding: 64px 64px;
  overflow: hidden;
  border: 1px solid rgba(139, 161, 226, .2);
  border-left: 4px solid rgba(112, 223, 255, .68);
  border-radius: 4px 24px 4px 4px;
  background: linear-gradient(105deg, rgba(18, 39, 67, .58), rgba(5, 8, 22, .68));
  text-align: left;
}
.media-grid > .empty::before {
  content: 'ARCHIVE BAY  /  EMPTY';
  position: absolute;
  top: 20px;
  left: 46px;
  color: #78b8dc;
  font: 700 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1.5px;
}
.media-grid > .empty::after {
  content: '';
  position: absolute;
  right: 68px;
  top: 50%;
  width: 116px;
  height: 132px;
  border: 1px solid rgba(112, 223, 255, .16);
  border-radius: 50%;
  box-shadow: 0 0 0 24px rgba(112, 223, 255, .025), 0 0 60px rgba(112, 223, 255, .08);
  transform: translateY(-50%);
}
.media-grid > .empty h3 { margin-bottom: 12px; color: #edf3ff; font-size: 24px; }
.media-grid > .empty p { max-width: 480px; color: #8796bb; }
.media-card { border-left: 3px solid rgba(112, 223, 255, .62); border-radius: 3px 16px 3px 3px; }

dialog {
  border: 1px solid rgba(168, 149, 255, .35);
  border-left: 4px solid rgba(169, 140, 255, .78);
  border-radius: 4px 26px 4px 4px;
}
dialog form { padding: 0 32px 32px; }
dialog form::before { left: -4px; top: 20px; right: auto; width: 4px; height: 64px; background: #b49bff; }
.dialog-title {
  margin: 0 -28px 22px;
  padding: 32px 32px 32px;
  border-bottom: 1px solid rgba(161, 145, 231, .19);
  background: linear-gradient(90deg, rgba(86, 63, 156, .2), rgba(9, 12, 31, .28));
}
.dialog-title h2 { font-size: 30px; }
.dialog-actions { margin: 23px -28px -27px; padding: 24px 32px 24px; background: rgba(4, 7, 20, .4); }

@media (max-width: 760px) {
  .section-title { min-height: auto; padding: 24px; border-radius: 4px 18px 4px 4px; }
  .section-title::after { display: none; }
  .template-head { display: block; padding-bottom: 68px; }
  .template-head > div { padding-right: 0; }
  .template-head button { top: auto; bottom: 18px; left: 24px; right: auto; }
  .bot-head { padding-right: 118px; }
  .account-manager-head { padding-right: 32px; padding-bottom: 68px; }
  .account-manager-head .simulation-chip { top: auto; left: 28px; right: auto; bottom: 20px; }
  .media-grid > .empty::after { opacity: .35; right: -35px; }
}
}

/* QuantWing Webhook and membership console */
.cloud-grid {
  display: grid;
  grid-template-columns: minmax(360px, .82fr) minmax(480px, 1.18fr);
  gap: 24px;
}
.webhook-source-policy { display: grid; gap: 12px; margin-top: 20px; }
.webhook-source-policy label { color: var(--text); font-size: var(--fs-base); }
.webhook-source-policy .webhook-policy-switch { justify-content: flex-start; min-height: 44px; margin: 0; padding: 8px 0; gap: 14px; }
.webhook-source-policy .webhook-policy-switch input { width: 20px; height: 20px; min-height: 0; padding: 0; margin: 0; flex: 0 0 20px; accent-color: #55dfb6; }
.webhook-entry-form { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 10px; align-items: end; }
.webhook-entry-form label { display: grid; gap: 6px; margin: 0; }
.webhook-entry-form input { width: 100%; min-width: 0; box-sizing: border-box; }
.webhook-entry-form button { min-height: 42px; }
.webhook-entry-list { display: grid; gap: 7px; }
.webhook-source-policy { container-type: inline-size; }
.webhook-allowlist-group { container-type: inline-size; padding: 18px; margin: 14px 0; border: 1px solid var(--border); border-radius: 14px; background: var(--surface); }
.webhook-allowlist-group h3 { margin: 0 0 8px; color: var(--text); font-size: 16px; }
.webhook-allowlist-group .collection-toolbar { margin: 10px 0; }
.webhook-entry-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); }
.webhook-entry-row span, .webhook-entry-row code { min-width: 0; overflow-wrap: anywhere; }
.webhook-entry-row code { color: #b9d7ef; }
.webhook-entry-row button { min-height: 34px; }
@media (max-width: 620px) { .webhook-entry-form, .webhook-entry-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } .webhook-entry-form button, .webhook-entry-row button { grid-column: 1 / -1; } }
.webhook-source-policy textarea {
  width: 100%; min-width: 0; box-sizing: border-box; resize: vertical;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); color: var(--text); padding: 12px;
  font: inherit;
}
.webhook-source-policy .actions { align-items: center; flex-wrap: wrap; }
.webhook-source-policy button.copied { color: #092419 !important; background: #9cf0c4 !important; border-color: #9cf0c4 !important; }
.cloud-member-card, .cloud-device-card, .cloud-channel-card {
  position: relative;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 26px;
  background:
    radial-gradient(circle at 88% 4%, rgba(67, 190, 239, .09), transparent 31%),
    linear-gradient(145deg, rgba(13, 25, 54, .92), rgba(4, 7, 20, .9)) padding-box,
    linear-gradient(135deg, rgba(72, 213, 230, .28), rgba(154, 132, 255, .12)) border-box;
  box-shadow: 0 28px 78px rgba(0, 0, 0, .31), inset 0 1px rgba(242, 248, 255, .04);
}
.cloud-member-card { grid-row: span 2; padding: 48px; }
.cloud-device-card, .cloud-channel-card { padding: 48px; }
.cloud-device-card { grid-column: 1 / -1; }
.cloud-member-card { grid-column: 1 / -1; grid-row: auto; }
.webhook-payload-grid { margin-top: 24px; }
.receiver-symbol-field { display: grid; gap: 10px; margin: 24px 0; }
.receiver-symbol-field input { width: 100%; }
.receiver-symbol-field small { color: var(--muted); line-height: 1.6; }
.cloud-webhook-main { flex: 1 1 auto; min-width: 0; }
.cloud-webhook-main code { display: block; margin-top: 10px; overflow-wrap: anywhere; color: #70defa; font: 14px/1.6 ui-monospace, Consolas, monospace; }
.bot-identity-ssot { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.bot-identity-ssot > :last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cloud-webhook-identity { max-width: 100%; }
.cloud-webhook-avatar { width: 42px; min-width: 42px; height: 42px; }
.cloud-webhook-name { color: #f2f6ff; font-size: 20px; font-weight: 760; line-height: 1.25; }
.cloud-member-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; padding-bottom: 32px; border-bottom: 1px solid rgba(136, 169, 223, .13); }
.cloud-member-head h2 { margin: 8px 0 8px; color: #f1f5ff; font-size: 30px; font-weight: 630; }
.cloud-member-head p { margin: 0; color: #8694b8; } /* 0.3.41 VIS-11 連動 */
.cloud-status {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 0 12px;
  border: 1px solid rgba(151, 164, 214, .2);
  border-radius: 999px;
  color: #8a95b4;
  background: rgba(5, 9, 24, .6);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 1.2px;
}
.cloud-status.online { color: #83f1cc; border-color: rgba(89, 229, 185, .32); background: rgba(24, 103, 83, .18); box-shadow: 0 0 24px rgba(52, 216, 175, .08); }
.entitlement-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 32px 0; }
.entitlement-grid span { padding: 24px; border: 1px solid rgba(139, 158, 215, .12); border-radius: 15px; color: #7885a8; background: rgba(3, 7, 20, .44); font-size: 14px; }
.entitlement-grid strong { display: block; margin-top: 12px; color: #e9edff; font-size: 16px; letter-spacing: .4px; }
.member-head { display: flex; align-items: center; gap: 24px; }
.member-identity { flex: 1 1 auto; min-width: 0; }
.member-identity h2 { margin: 4px 0 8px; color: #f1f5ff; font-size: 24px; font-weight: 630; }
.member-identity p { margin: 0; overflow: hidden; color: #8694b8; text-overflow: ellipsis; white-space: nowrap; } /* 0.3.41 VIS-11 連動 */
.member-avatar { width: 56px; height: 64px; flex-basis: 56px; overflow: hidden; font-size: 20px; }
.member-avatar.has-photo { border-color: rgba(139, 158, 215, .22); background: rgba(3, 7, 20, .44); }
.member-avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 頭像要是正圓 —— 正圓的前提是**正方形**。⛔ 以前是 42x48 與 56x64，而佈景把
   border-radius 設成 50%：長方形的 50% 就是橢圓（站長 2026-08-18 指出 Google 登入
   頭像變橢圓）。aspect-ratio 是防呆：日後有人只改其中一邊，比例仍會把它拉回正方。 */
.account-avatar { height: 42px; aspect-ratio: 1 / 1; }
.member-avatar { width: 56px; height: 56px; flex-basis: 56px; aspect-ratio: 1 / 1; }
.member-facts { margin: 24px 0 0; }
.member-execution-note { line-height: 1.6; margin-top: 16px; }
.bot-risk-note { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; line-height: 1.5; }
.bot-risk-note button { font-size: 13px; padding: 6px 10px; }
#tradingRiskDialog { max-width: min(680px, calc(100vw - 32px)); line-height: 1.65; }
#settingsMemberFacts strong { font-variant-numeric: tabular-nums; white-space: nowrap; }
#membershipSubscriptionPrice { font-size: clamp(22px, 3vw, 32px); }
.member-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.login-device-section { margin-top: 24px; padding-top: 22px; border-top: 1px solid rgba(136, 169, 223, .13); }
.login-device-heading { display: flex; align-items: end; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.login-device-heading h3 { margin: 5px 0 0; color: #edf2ff; font-size: 17px; }
.login-device-count { color: #8fa2cc; font-size: 13px; font-weight: 800; }
.login-device-list { display: grid; gap: 8px; }
/* Execution computers share the account theme, but remain separate from login sessions. */
.execution-computer-list { display: grid; gap: 12px; min-width: 0; }
.execution-computer-card { min-width: 0; padding: 16px; border: 1px solid var(--border); border-radius: 16px; background: var(--surface); }
.execution-computer-card.current { border-color: rgba(85,223,182,.3); background: linear-gradient(120deg, rgba(20,92,75,.16), var(--surface)); }
.execution-computer-heading { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; min-width: 0; }
.execution-computer-heading > div:not(.actions) { flex: 1 1 140px; min-width: 0; }
.execution-computer-heading h4 { margin: 4px 0; color: var(--text); font-size: 18px; overflow-wrap: anywhere; }
.execution-computer-heading small { color: var(--muted); overflow-wrap: anywhere; }
.execution-computer-heading button { min-height: 44px; white-space: nowrap; }
.execution-computer-card p { line-height: 1.6; overflow-wrap: anywhere; margin: 12px 0; }
.execution-bot-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(210px,100%),1fr)); gap: 8px; list-style: none; padding: 0; margin: 14px 0 0; }
.execution-bot-list li { display: grid; grid-template-columns: 10px minmax(0,1fr); align-items: center; gap: 4px 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; min-width: 0; }
.execution-bot-list strong { font-size: 15px; overflow-wrap: anywhere; }
.execution-bot-list small { grid-column: 2; color: var(--muted); line-height: 1.5; overflow-wrap: anywhere; }
.vault-activation-pending { margin: 12px 0; padding: 12px 16px; border: 1px solid rgba(112,174,225,.3); border-radius: 12px; background: rgba(13,42,67,.24); overflow-wrap: anywhere; line-height: 1.6; }
.vault-activation-pending ul { margin-bottom: 0; padding-inline-start: 20px; }
.login-device-item { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; align-items: center; gap: 12px; min-height: 58px; padding: 10px 12px; border: 1px solid rgba(139, 158, 215, .13); border-radius: 14px; background: rgba(3, 7, 20, .38); }
.login-device-item.current { border-color: rgba(85, 223, 182, .28); background: linear-gradient(105deg, rgba(20, 92, 75, .18), rgba(3, 7, 20, .4)); }
.login-device-icon { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 10px; color: #7cebc9; background: rgba(43, 151, 125, .14); font-size: 16px; }
.login-device-item strong, .login-device-item small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.login-device-item strong { color: #e9efff; font-size: 14px; }
.login-device-item strong em { margin-left: 5px; color: #6fe2bf; font-size: 11px; font-style: normal; }
.login-device-item small { margin-top: 4px; color: #8290b3; font-size: 12px; }
.login-device-item button { min-height: 34px; padding: 0 12px; font-size: 12px; }
/* 狀態點：⚠ 顏色**不是**唯一的訊息載體——旁邊一定同時有「使用中／閒置中」文字，
   否則對色覺障礙使用者等於沒有資訊（WCAG 1.4.1 不以顏色單獨傳達資訊）。 */
.login-device-dot { display: inline-block; width: 7px; height: 7px; margin-right: 6px; border-radius: 50%; background: #566184; vertical-align: middle; }
.login-device-dot.active { background: #55dfb6; box-shadow: 0 0 0 3px rgba(85, 223, 182, .16); }
/* 就地改名（2026-09-12 站長：「改名直接點名稱 就能在上面直接改」）。
   ⚠ 只有「已授權的桌面節點」那幾列才有這個 span —— 瀏覽器工作階段不能改名，
     所以它們是純文字、沒有任何可點的暗示（⛔ 別給一個按下去會失敗的入口）。
   ⭐ 虛線底線是「這裡可以編輯」唯一的靜態提示：⛔ 不靠 hover 才顯示，
     因為觸控裝置沒有 hover，那等於沒有提示。 */
.login-device-name {
  border-bottom: 1px dashed rgba(165, 175, 196, .45);
  cursor: text;
  border-radius: 2px;
  transition: background .12s ease, border-color .12s ease;
}
.login-device-name:hover { background: rgba(255, 255, 255, .06); border-bottom-color: #a5afc4; }
.login-device-name:focus-visible { outline: 2px solid #55dfb6; outline-offset: 2px; }
/* ⛔ 字級／字重／行高要跟 <strong> 裡的文字一致，否則點下去整列會跳一下。 */
/* 長清單以搜尋、每頁筆數和上一頁／下一頁保持可操作。 */
.login-history-toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; margin: 10px 0; }
.login-history-toolbar label { display: grid; gap: 5px; min-width: min(220px, 100%); font-size: 13px; }
.login-history-toolbar input, .login-history-toolbar select { width: 100%; min-height: 40px; }
.collection-toolbar { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 10px; align-items: end; margin: 12px 0; }
.collection-toolbar:focus-within, .login-history-toolbar:focus-within { position: relative; z-index: 5; }
.collection-toolbar label { display: grid; gap: 5px; min-width: min(180px, 100%); font-size: 13px; }
.collection-toolbar > label { margin: 0; }
.collection-toolbar input, .collection-toolbar select { width: 100%; min-height: 40px; }
.collection-toolbar > .collection-search { grid-column: 1; grid-row: 1; width: min(260px, 100%); min-width: 0; }
.collection-toolbar > .collection-page-size { grid-column: 3; grid-row: 1; justify-self: end; width: 112px; min-width: 0; }
.collection-toolbar > .collection-pagination { grid-column: 1 / -1; grid-row: 1; justify-self: center; display: flex; justify-content: center; margin: 0; padding: 0; border: 0; background: transparent; }
.collection-toolbar > .collection-pagination .collection-pagination-summary { display: none; }
.collection-toolbar > .collection-pagination .collection-pagination-nav { display: inline-flex; }
.collection-pagination, .login-history-pagination { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; margin: 8px 0 12px; padding: 5px 8px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); }
.collection-pagination:empty, .login-history-pagination:empty { display: none; }
.collection-pagination-summary { grid-column: 1; color: var(--muted); font-size: 13px; }
.collection-pagination-nav { grid-column: 2; display: inline-flex; align-items: center; justify-content: center; gap: 8px; white-space: nowrap; }
.collection-pagination-nav strong { font-size: 13px; font-weight: 600; color: var(--text); }
.collection-pagination-nav button { min-height: 36px; }
.collection-search { position: relative; }
.language-picker-control { position: relative; min-width: 0; }
.language-picker-control [hidden] { display: none !important; }
.language-picker-toggle { width: 100%; text-align: start; }
.language-picker-panel { position: relative; margin-top: 8px; min-width: 0; padding: 10px; border: 1px solid var(--border); border-radius: 12px; background: #111b2a; box-shadow: 0 12px 36px #0006; }
.language-picker-search { position: relative; }
.language-picker-search input { width: 100%; padding-inline-end: 42px; }
.language-picker-search input::-webkit-search-cancel-button { -webkit-appearance: none; }
.language-picker-search button { position: absolute; inset-inline-end: 4px; top: 4px; min-width: 36px; min-height: 36px; padding: 0; background: transparent; border: 0; font-size: 24px; }
#qw-language-options { max-height: 280px; overflow-y: auto; margin-top: 8px; }
#qw-language-options > button { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 42px; padding: 8px 10px; border: 0; border-radius: 6px; background: transparent; text-align: start; }
#qw-language-options > button:is(.is-active, :hover) { background: #7bcaff22; }
#qw-language-options > button[aria-selected="true"] { color: var(--cyan, #7bcaff); }
#qw-language-options small { color: var(--muted); }
.language-picker-status { font-size: 13px; color: var(--muted); margin: 8px 0 0; }
.language-picker-status:empty { display: none; }
html[dir="rtl"] :is(input[type="url"], input[type="email"], input[type="number"], code, pre, .api-command-details pre) { direction: ltr; unicode-bidi: isolate; text-align: left; }
.api-command-details pre { overflow: auto; max-width: 100%; max-height: 24rem; direction: ltr; unicode-bidi: isolate; text-align: left; }
.api-command-details summary { cursor: pointer; }
.collection-search input { box-sizing: border-box; }
.collection-suggestions:not([hidden]) { position: absolute; z-index: 80; top: 100%; left: 0; width: 100%; max-height: 240px; overflow-y: auto; box-sizing: border-box; padding: 5px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); box-shadow: 0 14px 32px rgba(0,0,0,.35); }
.collection-suggestions button { display: block; width: 100%; padding: 9px 10px; border: 0; border-radius: 7px; background: transparent; color: var(--text); text-align: left; font: inherit; cursor: pointer; }
.collection-suggestions button:hover, .collection-suggestions button:focus-visible, .collection-suggestions button[aria-selected="true"] { background: rgba(91, 210, 207, .14); outline: none; }
.cloud-device-card, .api-command-card, .account-list-panel, #settingsLoginHistorySection { container-type: inline-size; }
@container (max-width: 800px) { .collection-toolbar { grid-template-columns: minmax(0, 1fr) auto; } .collection-toolbar > .collection-search { grid-column: 1 / -1; grid-row: 1; } .collection-toolbar > .collection-pagination { grid-column: 1 / -1; grid-row: 2; justify-self: center; } .collection-toolbar > .collection-page-size { grid-column: 2; grid-row: 2; } }
@container (max-width: 420px) { .collection-toolbar > .collection-page-size { grid-column: 1 / -1; grid-row: 3; justify-self: center; } .collection-pagination-bottom { grid-template-columns: 1fr; } .collection-pagination-bottom .collection-pagination-summary, .collection-pagination-bottom .collection-pagination-nav { grid-column: 1; text-align: center; } }
/* 保留政策告知。⛔ 這不是裝飾：NIST SP 800-63B-4 要求告知使用者保留政策，
   而我們沒有說明文件 ⇒ 這行是唯一的告知管道。 */
.login-history-note {
  margin: 10px 2px 0;
  color: var(--muted, #8b95a3);
  font-size: 12px;
  line-height: 1.5;
}
.login-device-name-input {
  width: min(220px, 100%);
  min-height: 0;
  margin: 0;
  padding: 0 4px;
  border: 1px solid #55dfb6;
  border-radius: 4px;
  background: rgba(10, 18, 28, .9);
  color: inherit;
  font: inherit;
}
.login-history-item { grid-template-columns: 34px minmax(0, 1fr); }
.login-history-item .login-device-icon { color: #8fa2cc; background: rgba(120, 140, 190, .12); }
.login-device-empty { padding: 16px; border: 1px dashed rgba(139, 158, 215, .16); border-radius: 13px; color: #8290b3; text-align: center; }
@media (max-width: 620px) {
  .login-device-section { margin-top: 16px; padding-top: 16px; }
  .login-device-item { grid-template-columns: 26px minmax(0, 1fr); align-items: start; gap: 6px 10px; min-height: 0; padding: 10px; }
  .login-device-item > .login-device-icon { width: 26px; height: 26px; }
  .login-device-item > div:not(.actions) { min-width: 0; }
  .login-device-item > .actions { grid-column: 2; display: flex; justify-content: flex-start; min-width: 0; }
  .login-device-item > .actions button { width: auto; min-height: 32px; white-space: nowrap; }
}
.cloud-connection { display: flex; align-items: center; gap: 16px; margin-top: 24px; padding: 24px; border: 1px solid rgba(112, 174, 225, .14); border-radius: 16px; background: linear-gradient(110deg, rgba(13, 42, 67, .36), rgba(4, 7, 20, .46)); }
.cloud-connection > span { width: 10px; height: 10px; flex: 0 0 10px; border-radius: 50%; background: #59647f; box-shadow: 0 0 0 5px rgba(89, 100, 127, .08); }
.cloud-connection > span.online { background: #55dfb6; box-shadow: 0 0 0 5px rgba(85, 223, 182, .09), 0 0 18px rgba(85, 223, 182, .55); }
.cloud-connection small { display: block; color: #7d8db7; font-size: 14px; letter-spacing: 1.5px; } /* 0.3.41 VIS-11 連動：改前 4.41 已不及格、卡面提亮後更掉到 3.90，提亮到 4.82（8px 過小仍屬 VIS-13 待辦） */
.cloud-connection strong { display: block; margin-top: 4px; color: #dfe7ff; font-size: 14px; }
.cloud-inline-form { display: grid; grid-template-columns: minmax(180px, 1fr) auto; align-items: end; gap: 12px; margin: 24px 0; }
.cloud-channel-card .cloud-inline-form { grid-template-columns: minmax(170px, .7fr) minmax(220px, 1fr) auto; }
.cloud-inline-form label { margin: 0; }
.cloud-list { display: grid; gap: 12px; }
.cloud-list-item { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 24px; border: 1px solid rgba(137, 157, 214, .12); border-radius: 17px; background: linear-gradient(135deg, rgba(15, 24, 49, .68), rgba(3, 7, 19, .62)); }
.cloud-list-item.revoked { opacity: .58; }
.cloud-list-item > div:first-child { min-width: 0; }
/* Legacy row labels must not restyle the nested, shared bot identity. */
.cloud-list-item > div:first-child > span:not(.bot-identity-ssot) { display: block; color: #6f81b4; font-size: 14px; font-weight: 750; letter-spacing: 1.2px; overflow-wrap: anywhere; }
.cloud-list-item strong { display: block; margin: 8px 0 4px; color: #ecf1ff; font-size: 16px; }
.cloud-list-item small { color: #7e89a8; font-size: 14px; }
.cloud-list-item .actions { flex: 0 0 auto; }
.one-time-secret { margin: 24px 0; padding: 24px; border: 1px solid rgba(83, 224, 184, .32); border-radius: 18px; background: radial-gradient(circle at 95% 0, rgba(67, 214, 180, .12), transparent 31%), rgba(8, 47, 42, .24); box-shadow: 0 0 42px rgba(54, 205, 174, .07); }
.one-time-secret > div:first-child span { color: #65e4bd; font-size: 14px; font-weight: 800; letter-spacing: 1.3px; }
.one-time-secret > div:first-child strong { display: block; margin: 8px 0 16px; color: #def9ef; font-size: 14px; }
.one-time-secret .copy-field { margin-bottom: 16px; }
.cloud-binding { display: grid; grid-template-columns: 1fr auto; align-items: center; }
.cloud-binding > span { grid-column: 1 / -1; }
.cloud-binding button { margin-left: 12px; }

@media (max-width: 1120px) {
  .cloud-grid { grid-template-columns: 1fr; }
  .cloud-member-card { grid-row: auto; }
}
@media (max-width: 760px) {
  .cloud-inline-form, .cloud-channel-card .cloud-inline-form { grid-template-columns: 1fr; }
  .cloud-list-item { align-items: flex-start; flex-direction: column; }
  .cloud-list-item .actions { width: 100%; }
  .entitlement-grid { grid-template-columns: 1fr; }
}

/* Aurora orbital interface — quiet, spacious, cinematic */
:root {
  --aurora-blue: #85c9ff;
  --aurora-violet: #aa9cff;
  --aurora-mint: #7ee6c1;
  --aurora-line: rgba(170, 184, 242, .17);
  --aurora-surface: rgba(9, 13, 34, .76);
}

.section-title {
  position: relative;
  align-items: end;
  margin: 64px 0 32px;
  padding: 0 0 24px 24px;
  border-bottom: 1px solid rgba(153, 167, 224, .13);
}

.section-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 18px;
  width: 2px;
  border-radius: 999px;
  background: linear-gradient(180deg, #8dd7ff, #a48dff 68%, transparent);
  box-shadow: 0 0 20px rgba(143, 159, 255, .48);
}

.section-title::after {
  content: '';
  position: absolute;
  left: 18px;
  bottom: -1px;
  width: 118px;
  height: 1px;
  background: linear-gradient(90deg, #9caeff, transparent);
  box-shadow: 0 0 13px rgba(137, 157, 255, .42);
}

.section-title h1 {
  margin-bottom: 12px;
  color: #f6f7ff;
 
 
 
}

.section-title p { line-height: 1.7; }
.section-title .section-kicker { margin-bottom: 12px; color: #9e9be8; letter-spacing: 1.9px; }
.section-title.compact { margin-top: 48px; }

button, .button {
  min-height: 48px;
 
  font-size: 14px;
  letter-spacing: .25px;
}

/* 0.3.41 VIS-02 ⚠ 這是 .primary 在**活碼**裡的最後一份（前面 61 / 469 / 740 各有一份、
   1389 那份落在 @media (max-width: 0px) 的死碼區 1324–1665 內從不渲染）。
   ⇒ 想改主按鈕外觀請改**這裡**；改前面那幾份不會生效（VIS-10 的根因，⛔ 別再踩）。
   ⛔ 漸層不可再調亮：舊值 #637ce5→#8b69d4 讓白字對比只有 3.79 / 4.00 / 4.14
   （起點 / 中點 / 終點），整段都低於 WCAG AA 的 4.5:1 —— 而 .secondary / .danger /
   .warning 全在 9–11:1，證明這不是深色主題的通病，是這一個色選錯了。
   現值三點量得 5.64 / 5.99 / 6.29；且因為 button:hover 有 filter: brightness(1.12)
   （styles.css:467，全站共用），hover 態會被打亮一截 ⇒ 留了餘裕讓 hover 仍有 4.69。
   ⛔ 別改用加粗字重或文字陰影「看起來清楚」—— 那不會改變任何量測值。
   字級 16px / 字重 690 不符 WCAG「大字」定義（需 18.66px bold 或 24px）⇒ 門檻就是 4.5。
   邊框比舊值提亮，是為了補回壓暗漸層失去的「主行動」躍出感（邊框不覆蓋文字，
   不影響上面那組對比數字）。 */
.primary {
  border-color: rgba(186, 196, 255, .55);
  background: linear-gradient(135deg, #4a5fc4, #6b4bb0);
  box-shadow: 0 12px 32px rgba(74, 62, 160, .30), inset 0 1px rgba(255, 255, 255, .18);
}
.secondary { background: rgba(22, 29, 61, .7); }
.danger { background: rgba(73, 26, 47, .62); }

.module-card {
  --aurora-accent: var(--aurora-violet);
  position: relative;
  overflow: hidden;
  border: 1px solid transparent;
 
  /* 0.3.41 VIS-11 ⚠ 這一組是機器人卡 / 雲端卡 / 設定卡表面的**真正** cascade 贏家
     （app.js:1766 的 class="bot-card module-card"）—— 改卡片外觀請改這裡，
     ⛔ 改 `.card, .bot-card`（約 876 行）或 `.bot-card`（約 1248 行）都不會生效。
     表面亮度是承重的，⛔ 別壓暗回去：深色介面的層級靠更亮的表面表達，不是靠陰影 ——
     舊值配 `0 34px 95px rgba(0,0,0,.38)` 在 #050611 底上實測對比 1.007（人眼看不到），
     等於付了 95px 模糊的合成層成本、換到零視覺層級。陰影已改帶色相（深底上才浮得出來）。
     ⚠ 提亮這個表面會連動所有「疊在卡片上」的低透明度元素（.bot-stats div / .webhook /
     .badge 各態底色）的實際渲染色 ⇒ 動這個值之後要重量一輪那些疊層的文字對比。 */
  background:
    linear-gradient(145deg, rgba(32, 41, 80, .93), rgba(17, 23, 50, .90)) padding-box,
    linear-gradient(135deg, color-mix(in srgb, var(--aurora-accent) 38%, transparent), rgba(133, 160, 223, .08) 42%, rgba(172, 145, 255, .2)) border-box;
  box-shadow: 0 18px 50px rgba(58, 48, 148, .44), inset 0 1px rgba(239, 243, 255, .075);
  backdrop-filter: blur(28px) saturate(118%);
}

.module-card[data-module^="UPLINK"] { --aurora-accent: var(--aurora-blue); }
.module-card[data-module^="PAYLOAD"] { --aurora-accent: var(--aurora-violet); }
.module-card[data-module^="IDENTITY"] { --aurora-accent: var(--aurora-mint); }
.module-card[data-module^="AUTOMATION"] { --aurora-accent: #b7a6ff; }
.module-card[data-module^="SECURITY"] { --aurora-accent: #ff9cac; }
.module-card[data-module^="TRADING"] { --aurora-accent: var(--aurora-blue); }

.module-card::before {
  content: '';
  position: absolute;
  z-index: 0;
  top: -105px;
  right: -88px;
  width: 230px;
  height: 264px;
  border: 1px solid color-mix(in srgb, var(--aurora-accent) 14%, transparent);
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--aurora-accent) 9%, transparent), transparent 67%);
  box-shadow: 0 0 0 32px color-mix(in srgb, var(--aurora-accent) 1.8%, transparent);
  pointer-events: none;
}

.module-card::after {
  content: attr(data-module);
  position: absolute;
  z-index: 3;
  top: 19px;
  right: 22px;
  padding: 8px 12px;
  border: 1px solid color-mix(in srgb, var(--aurora-accent) 24%, transparent);
  border-radius: 999px;
  color: color-mix(in srgb, var(--aurora-accent) 72%, #929bbd);
  background: color-mix(in srgb, var(--aurora-accent) 6%, rgba(6,9,24,.7));
  font: 700 14px/1 ui-monospace, Consolas, monospace;
  letter-spacing: 1.35px;
}

.module-card > * { position: relative; z-index: 1; }
.form-card { padding: 32px; }
 /* 0.3.41 VIS-11 連動 */

/* ⭐ **欄數的單一真相源**（同名規則全檔有數處，這是最後、也就是實際生效的那條）。
   站長 2026-08-20：「右邊東西都拔掉了 版面改一下 不要這麼空」。
   ⚠ 根因：本來是兩欄（左＝中央連線、右＝快訊內容），08-19 依站長指令刪掉左欄後
     **這行沒跟著改** ⇒ 只剩的那張卡被釘在左半邊、右半邊整片空白。
   ⇒ 改成跟著內容走：剩一張就撐滿整寬，將來真要放兩張也不必再回來改。 */
.receiver-grid { grid-template-columns: repeat(auto-fit, minmax(430px, 1fr)); gap: 24px; }
.receiver-status {
  min-height: 88px;
  padding: 24px 24px;
  border: 1px solid rgba(137, 176, 228, .16);
  border-radius: 17px;
  background: linear-gradient(100deg, rgba(19, 46, 68, .3), rgba(4, 8, 22, .52));
}
.receiver-status > span { width: 9px; height: 9px; flex-basis: 9px; }
.receiver-status::after { top: 13px; right: 14px; }

.template-head {
  min-height: 80px;
  margin: -3px 0 18px;
  padding: 3px 0 24px;
  border-bottom: 1px solid rgba(158, 149, 226, .11);
}
.template-head h2 { font-size: 24px; }
.template-head button { position: static; margin-top: 32px; }

.json-template {
  border: 1px solid rgba(126, 156, 222, .18);
  border-radius: 20px;
  background:
    radial-gradient(circle at 92% 6%, rgba(133, 111, 225, .08), transparent 25%),
    rgba(2, 5, 16, .8);
  box-shadow: inset 0 0 55px rgba(74, 74, 153, .06), 0 18px 44px rgba(0,0,0,.16);
}
.json-template::before { border-radius: 20px 20px 0 0; background: rgba(25, 30, 62, .42); }

.copy-field code, .connection-line, .webhook {
  border: 1px solid rgba(137, 159, 218, .14);
 
  background: rgba(3, 7, 20, .54);
}

.module-table {
  position: relative;
  padding-top: 64px;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 23px;
  background:
    rgba(4, 7, 20, .82) padding-box,
    linear-gradient(135deg, rgba(126, 199, 255, .25), rgba(143, 152, 218, .08), rgba(167, 143, 255, .18)) border-box;
  box-shadow: 0 30px 82px rgba(0,0,0,.34), inset 0 1px rgba(238,242,255,.045);
}
.module-table::before {
  height: 48px;
  padding: 0 24px;
  color: #7e8dc2;
  background: linear-gradient(90deg, rgba(31, 46, 85, .58), rgba(14, 18, 42, .42));
  font-size: 14px;
  line-height: 42px;
  letter-spacing: 1.6px;
}
.module-table::after {
  content: '';
  position: absolute;
  top: 20px;
  right: 20px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #79dcb9;
  box-shadow: 0 0 13px rgba(121, 220, 185, .75);
}
th { height: 56px; color: #9ca7c8; background: rgba(19, 24, 52, .78); }
td { height: 60px; }

.filters {
  gap: 12px;
  padding: 16px;
  border: 1px solid rgba(155, 165, 224, .14);
  border-radius: 18px;
  background: rgba(7, 10, 27, .58);
  box-shadow: 0 18px 52px rgba(0,0,0,.2);
}

.bot-card.module-card::after { display: block; }
.bot-card {
  padding: 32px;
 
}
.bot-head { min-height: 92px; }
.bot-head .badge { position: absolute; top: 36px; right: 0; }
.card-code { color: #7aaed0; letter-spacing: 1.35px; }
.bot-head h3 { margin-top: 4px; color: #f3f5ff; }
.connection-line { min-height: 68px; margin-top: 24px; padding: 16px 24px; }
.bot-stats { gap: 12px; }
.bot-stats div {
  min-height: 88px;
  padding: 24px;
  border: 1px solid rgba(137, 158, 216, .11);
  border-radius: 16px;
  background: linear-gradient(145deg, rgba(19, 27, 58, .58), rgba(3, 7, 20, .46));
}
.bot-stats div::after { width: 32px; background: linear-gradient(90deg, transparent, #8fa8ff); }
.bot-stats strong { margin-top: 12px; font-size: 18px; }
.webhook { margin-top: 24px; padding: 16px 24px; }

.account-manager { border-radius: 28px; }
.account-manager-head {
  padding: 48px 48px 32px;
  border-bottom: 1px solid rgba(126, 230, 193, .12);
  background: linear-gradient(90deg, rgba(37, 92, 83, .15), transparent 63%);
}
.account-manager-head .simulation-chip { margin-right: 120px; }
.account-title-icon { box-shadow: 0 0 34px rgba(104, 220, 194, .1); }

/* 0.3.41：關於卡不再 `grid-column: 1 / -1`。量到的實況是它佔滿 1360px 卻只有 431px
   高（全頁內容最少的一張），而旁邊「一般設定」那張半寬卡有 828px 的內容 —— 內容最少的
   卡吃掉最寬的一格＝密度倒置。改半寬之後它正好補上「一般設定」右邊原本空著的一格。
   ⛔ 別把 grid-column 加回來：加回來會再擠出一個空格，設定頁就又出現兩塊大空白。
   align-self 只給這一張：它的鄰居「一般設定」有 828px 的內容，等高拉伸會在關於卡底下
   留約 400px 的卡內空白 —— 有邊框有背景的空白讀起來像「這張卡沒載入完」。同排的
   會員卡與介面卡高度只差 46px，那兩張留著拉伸反而比較齊。 */
.about-card { align-self: start; }
.about-brand { display: flex; align-items: center; gap: 24px; }
.about-brand img { width: 82px; height: 96px; object-fit: contain; filter: drop-shadow(0 0 22px rgba(35, 204, 236, .2)); }
.about-brand h2 { margin: 4px 0 8px; color: #f4f6ff; font-size: 30px; }
.about-brand p, .about-note { color: #8e98b9; }
/* 四個項目排 2×2，不排 3+1：關於卡改半寬後三欄每欄只剩約 190px，「保留舊 TradingWing
   設定」這種長字串會被擠成三行。兩欄也跟會員卡的 .entitlement-grid 對齊（同樣 2 欄）。 */
.product-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 32px; }
.product-facts span { padding: 16px; border: 1px solid rgba(142, 158, 218, .16); border-radius: 12px; color: #7e88a8; background: rgba(7, 12, 30, .38); font-size: 14px; }
.product-facts strong { display: block; margin-top: 8px; color: #e9edff; font-size: 14px; }
.about-note { margin: 24px 0 0; font-size: 14px; }
@media (max-width: 760px) { .product-facts { grid-template-columns: 1fr; } }
.credential-panel, .account-list-panel { padding: 48px; }
.account-card {
  border: 1px solid transparent;
  border-radius: 21px;
  background:
    linear-gradient(145deg, rgba(18, 29, 53, .84), rgba(7, 10, 27, .8)) padding-box,
    linear-gradient(135deg, rgba(110, 229, 192, .24), rgba(140, 153, 219, .1)) border-box;
  box-shadow: 0 20px 50px rgba(0,0,0,.2);
}

#settingsForm.module-card, .safety-card.module-card { padding-top: 58px; }
#settingsForm.module-card > .section-kicker, .safety-card.module-card > .section-kicker { position: absolute; top: 23px; left: 27px; }
#settingsForm h2, .safety-card h2 { margin: -3px 0 20px; padding-bottom: 24px; border-bottom: 1px solid rgba(151, 163, 217, .11); }
.switch-row {
  padding: 24px;
  border: 1px solid rgba(146, 160, 217, .12);
  border-radius: 16px;
  background: rgba(4, 8, 22, .45);
}
.safety-card ul { list-style: none; margin: 0; padding: 0; }
.safety-card li {
  position: relative;
  margin: 12px 0;
  padding: 16px 16px 16px 48px;
  border: 1px solid rgba(153, 164, 217, .1);
  border-radius: 14px;
  background: rgba(4, 8, 22, .4);
}
.safety-card li::before {
  content: '';
  position: absolute;
  left: 14px;
  top: 17px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #9c91ff;
  box-shadow: 0 0 12px rgba(156, 145, 255, .7);
}

.media-grid:has(.empty) { grid-template-columns: 1fr; }
.media-grid > .empty {
  position: relative;
  min-height: 264px;
  display: grid;
  align-content: center;
  justify-items: start;
  padding: 64px 64px;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 26px;
  background:
    linear-gradient(110deg, rgba(12, 22, 48, .78), rgba(4, 7, 20, .7)) padding-box,
    linear-gradient(135deg, rgba(112, 207, 255, .24), rgba(161, 144, 255, .13)) border-box;
  text-align: left;
  box-shadow: 0 30px 82px rgba(0,0,0,.3);
}
.media-grid > .empty::before {
  content: '';
  position: absolute;
  right: 78px;
  top: 50%;
  width: 112px;
  height: 128px;
  border: 1px solid rgba(139, 190, 255, .18);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(143, 155, 255, .08), transparent 65%);
  box-shadow: 0 0 0 24px rgba(130, 142, 255, .018), 0 0 55px rgba(111, 169, 255, .06);
  transform: translateY(-50%);
}
.media-grid > .empty::after {
  content: '';
  position: absolute;
  right: 62px;
  top: 50%;
  width: 144px;
  height: 24px;
  border-top: 1px solid rgba(145, 190, 255, .25);
  border-radius: 50%;
  transform: translateY(-50%) rotate(-14deg);
}
.media-grid > .empty h3 { margin-bottom: 12px; color: #edf1ff; font-size: 24px; }
.media-grid > .empty p { color: #8490b2; }
.media-card { border-radius: 21px; box-shadow: 0 24px 64px rgba(0,0,0,.28); }

dialog {
  border: 1px solid transparent;
  border-radius: 28px;
  background:
    linear-gradient(145deg, rgba(18, 23, 53, .99), rgba(5, 8, 22, .99)) padding-box,
    linear-gradient(135deg, rgba(167, 151, 255, .35), rgba(126, 168, 235, .12)) border-box;
}
dialog form { padding: 48px; }
.dialog-title { padding-bottom: 24px; }
.dialog-title h2 { font-size: 30px; font-weight: 610; }
.dialog-actions { margin-top: 32px; padding-top: 24px; }

/* Login shell ≠ main shell: never paint main UI under a small auth window (white edges / overlap). */
body.auth-locked {
  min-width: 0;
  max-width: 100vw;
  overflow: hidden;
  background: #07111f !important;
}
body.auth-locked .app-shell,
.app-shell[hidden] { display: none !important; }
body.auth-transitioning #appShell,
body.auth-transitioning #authGate { opacity: 0; pointer-events: none; }
#appShell, #authGate { transition: opacity .18s ease; }
@media (prefers-reduced-motion: reduce) {
  #appShell, #authGate { transition: none; }
}
body.auth-locked .ambient-grid { display: none !important; }
.bot-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}
.bot-action-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
.bot-action-trade {
  padding: 12px 12px;
  border: 1px solid rgba(56, 120, 170, .35);
  border-radius: 12px;
  background: rgba(8, 22, 38, .72);
}
.bot-action-trade .trade-buy { border-color: rgba(72, 213, 151, .45); color: #9af0c8; }
.bot-action-trade .trade-sell { border-color: rgba(255, 98, 121, .4); color: #ff9daf; }
.bot-action-trade .trade-hint {
  margin-left: auto;
  color: #7f93b0;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .04em;
}
.internal-browse-grid {
  display: grid;
  gap: 16px;
  min-height: min(70vh, 828px);
}
/* Adaptive: 1 full · 2 split · 3/4 quad */
.internal-browse-grid.cells-0,
.internal-browse-grid.cells-1 {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  min-height: min(72vh, 872px);
}
.internal-browse-grid.cells-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: 1fr;
  min-height: min(68vh, 804px);
}
.internal-browse-grid.cells-4 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(220px, 1fr));
}
.internal-add-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 252px;
  margin: 0;
  padding: 32px;
  border: 1px dashed rgba(90, 160, 210, .45);
  border-radius: 18px;
  background: rgba(6, 18, 34, .55);
  color: #b9cce4;
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .12s;
}
.internal-add-tile:hover {
  border-color: rgba(62, 215, 208, .65);
  background: rgba(12, 36, 58, .72);
  transform: translateY(-1px);
}
.internal-add-plus {
  display: grid;
  place-items: center;
  width: 64px;
  height: 72px;
  border-radius: 50%;
  border: 1px solid rgba(90, 170, 220, .4);
  color: #7ee7d8;
  font-size: 48px;
  font-weight: 300;
  line-height: 1;
  background: rgba(20, 50, 72, .5);
}
.internal-add-tile strong { color: #e8f2ff; font-size: 20px; }
.internal-add-tile small { color: #7f93b0; font-size: 14px; text-align: center; max-width: 220px; }
.internal-empty-hint { grid-column: 1 / -1; margin: 0; padding: 4px 12px; font-size: 14px; }
.internal-pane {
  display: flex;
  flex-direction: column;
  min-height: 252px;
  padding: 24px 24px;
}
.internal-pane-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.internal-pane-head strong { display: block; font-size: 18px; }
.internal-pane-head small { display: block; margin-top: 4px; color: var(--muted); font-size: 14px; }
.internal-pane-body { display: flex; flex: 1; flex-direction: column; gap: 16px; }
.internal-pane-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.internal-pane-metrics span {
  display: block;
  padding: 12px 16px;
  border: 1px solid rgba(90, 120, 160, .25);
  border-radius: 10px;
  color: var(--muted);
  font-size: 14px;
  background: rgba(4, 12, 24, .55);
}
.internal-pane-metrics strong { display: block; margin-top: 4px; color: var(--text); font-size: 16px; }
.internal-pane-preview {
  flex: 1;
  margin: 0;
  padding: 16px;
  border: 1px dashed rgba(90, 140, 180, .35);
  border-radius: 12px;
  color: #9eb3cc;
  font-size: 14px;
  line-height: 1.55;
  background: rgba(6, 16, 30, .65);
}
.internal-browse-toolbar { align-items: center; gap: 12px; }
.internal-page-label {
  min-width: 88px;
  color: #c5d4e8;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
}
.internal-browse-hint { margin-top: 16px; }
.display-mode-field select { width: 100%; }
body.auth-locked { min-width: 0; overflow: hidden; }
.window-drag-region { display: none; }
.window-titlebar-brand { position:fixed; top:0; left:16px; z-index:12000; display:flex; align-items:center; gap: 12px; height: 36px; color:#dce8f5; font:600 14px/1 "Segoe UI Variable","Segoe UI",sans-serif; pointer-events:none; }
/* margin-left:auto 讓三顆鈕永遠靠右。改 .app-header .tabs 的 flex-grow 之後，
   分頁不再吃掉剩餘寬度，少了這行視窗鈕會跟著分頁往左縮回去。
   ⛔ position:static / align-items:center / height:100% 三者被
   electron-packaging.test.js:202 與 runtime-ux-recovery.test.js:126 依序釘死，不可移除或換序。 */
.window-controls { position:static; z-index:1; display:flex; flex:0 0 auto; align-items:center; gap: 2px; height:100%; margin-left: auto; -webkit-app-region:no-drag; }
.window-controls button,
.auth-window-controls button { display:grid; place-items:center; width:42px; height: 36px; min-height: 36px; padding: 0; border:0; border-radius:6px; background:transparent; color:#a5afc4; box-shadow:none; -webkit-app-region:no-drag; }
.window-controls .wc-icon,
.auth-window-controls .wc-icon { width:var(--space-3); height:var(--space-3); overflow:visible; fill:none; stroke:currentColor; stroke-width:1.4; stroke-linecap:butt; stroke-linejoin:miter; }
.window-maximize .wc-icon[hidden] { display:none; }
.window-controls button:hover,
.auth-window-controls button:hover { background:rgba(118,133,164,.16); color:#f2f5ff; }
.window-controls .window-close:hover,
.auth-window-controls .window-close:hover { background:#d83c52; color:#fff; }
.auth-window-controls { position:fixed; top:0; right:0; z-index:12000; display:flex; height: 36px; -webkit-app-region:no-drag; }
.auth-window-controls button { width:46px; border-radius:0; }
/* 站長要求：三顆鈕縮小並固定右上角（靠右由 .window-controls 的 margin-left:auto 負責）。
   只縮產品 header 這一組；登入閘的 .auth-window-controls 是另一條 fixed 列，維持原尺寸。
   26px 高仍符合 WCAG 2.2 的 24×24 最小點擊目標。
   ⛔ 這裡刻意不碰 .window-controls 本身的 height:100%／align-items:center —— 那三個屬性
   被 electron-packaging.test.js:202 與 runtime-ux-recovery.test.js:126 依序釘死。 */
.app-header .window-controls button { width:36px; height: 26px; min-height: 26px; border-radius:5px; }
.app-header .window-controls .wc-icon { width:10px; height: 10px; }
/* header 是拖曳表面：圖片與文字若可被原生拖曳，按住 logo 拖時瀏覽器會啟動
   image drag／文字選取，把滑鼠捕獲搶走，startDragging 就再也收不到 pointermove。 */
.app-header, .app-header .brand, .app-header img { -webkit-user-drag: none; user-select: none; }
body:not(.auth-locked) .auth-window-controls { display:none; }
/* The embedded product header is the only visible chrome after admission. The
   host keeps its own controls solely for startup/blocked states. */
html[data-host="tauri"] .window-controls { display: flex !important; }
html[data-host="tauri"] body:not(.auth-locked) .auth-window-controls { display: none !important; }
html[data-host="tauri"] body.auth-locked .auth-window-controls { display: flex !important; }
body.auth-locked .window-titlebar-brand { color:#dce8f5; }
/* 0.3.35 刪除：這裡原有一條裸 `.app-header{height:64px;justify-content:flex-end;padding:32px 24px 0}`。
   它寫在 auth-locked 區塊裡卻沒有 `body.auth-locked` 前綴，且被檔尾 0.3.20 的 .app-header
   完整覆蓋（同特異性、行序在後）⇒ 三個宣告一個都沒生效過。登入殼本來就把 #appShell 整個
   hidden，header 不會出現，所以它連原本想解的問題都不存在。 */
.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  padding: 32px 24px;
  /* Keep the cinematic Earth/orbit plate; deepen the vignette for enterprise gravity. */
  background:
    radial-gradient(ellipse 70% 55% at 50% 42%, rgba(56, 189, 248, .10), transparent 62%),
    radial-gradient(ellipse 90% 80% at 78% 18%, rgba(99, 102, 241, .14), transparent 48%),
    linear-gradient(155deg, rgba(2,5,16,.92), rgba(6,11,28,.78) 52%, rgba(3,8,20,.70)),
    url('/renderer-assets/2820eb82c9728f599d004a95967f5380a89b9505430984c31ee8ad630696faa0/assets/cinematic-orbit-v1.png') center/cover no-repeat;
  -webkit-app-region: drag;
}
.auth-gate-card, .auth-gate button, .auth-gate a, .auth-gate input { -webkit-app-region: no-drag; }
.auth-gate.hidden { display: none; }
.auth-gate-card {
  position: relative;
  width: min(520px, calc(100% - 36px));
  max-width: 520px;
  min-height: 0;
  padding: 64px 48px 48px;
  border: 1px solid rgba(148, 163, 224, .38);
  border-radius: 28px;
  background:
    linear-gradient(150deg, rgba(12, 18, 44, .96), rgba(5, 9, 26, .93) 62%, rgba(4, 10, 28, .95));
  box-shadow:
    0 32px 90px rgba(0, 0, 0, .58),
    0 0 0 1px rgba(255, 255, 255, .03) inset,
    0 1px 0 rgba(167, 211, 255, .12) inset,
    0 0 80px rgba(56, 189, 248, .08);
  color: #f5f8ff;
  text-align: left;
  backdrop-filter: blur(18px);
}
.auth-gate-card::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(125, 211, 252, .22), transparent 36%, transparent 68%, rgba(129, 140, 248, .18));
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  padding: 1px;
}
.auth-gate-brand {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 32px;
  color: #f5f8ff;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: .01em;
}
.auth-gate-brand img {
  width: 64px;
  height: 72px;
  padding: 0;
  border-radius: 0;
  background: transparent;
  object-fit: contain;
  filter: drop-shadow(0 0 18px rgba(45, 200, 220, .28));
}
.auth-gate-brand b { color: #f7fbff; font-weight: 750; }
.auth-gate-card h1 {
  margin: 0 0 16px;
  color: #f8fbff;
  font-size: 48px;
  line-height: 1.18;
  letter-spacing: -.03em;
  font-weight: 720;
  text-shadow: 0 1px 0 rgba(255, 255, 255, .04);
}
.auth-gate-card > p {
  margin: 0;
  color: #b7c3dc;
  font-size: 20px;
  line-height: 1.72;
  font-weight: 500;
}
.auth-google-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  width: 100%;
  margin: 32px 0 24px;
  padding: 24px 32px;
  min-height: 64px;
  border: 1px solid rgba(116, 135, 180, .45);
  border-radius: 14px;
  background: #f5f7fb;
  color: #151b2b;
  font-size: 20px;
  font-weight: 750;
  letter-spacing: .01em;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .22);
}
.auth-google-button:hover:not(:disabled) {
  border-color: #38d7c1;
  background: #fff;
  box-shadow: 0 12px 32px rgba(32, 198, 223, .16);
}
.auth-remember { display: flex; align-items: center; gap: 10px; margin: 16px 0 6px; cursor: pointer; font-size: 18px; }
.auth-remember input { width: 20px; height: 20px; min-height: 0; padding: 0; margin: 0; flex: 0 0 20px; box-sizing: border-box; accent-color: #a5e2f5; }
.auth-remember-note { display: block; margin-bottom: 16px; }
.auth-sign-out { display: block; margin: 20px auto 0; }
.auth-gate.checking .auth-sign-out { display: none; }
.auth-gate.checking .auth-remember { display: none; }
.auth-google-button img { width: 24px; height: 24px; }
.auth-google-button:disabled { opacity: .58; cursor: not-allowed; }
.auth-gate-card > small {
  display: block;
  color: #93a0bb;
  font-size: 16px;
  line-height: 1.7;
  text-align: center;
}
.auth-gate-progress {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin: 12px 0 16px;
  color: #8ad9c8;
  font-size: 16px;
}
.auth-gate-progress .brand-loader-logo { width: 34px; height: 40px; }
/* 登入閘第三態（不知道有沒有登入）。⛔ 未知不能畫登入畫面：/api/auth/status
   要等交易核心回答，api() 沒有客戶端逾時、失聯走 2s→30s 退避重試，那段期間
   舊版把登入卡連同「可以按」的 Google 鍵一起畫出來 —— 站長其實已經登入，卻
   來得及按到它。⚠ 這不是把閘藏起來：拿到否定答案時 checking 會被移除，整張
   卡照常擋住 app。*/
.auth-gate.checking #authGateTitle,
.auth-gate.checking #authGateMessage,
.auth-gate.checking #authGateSignIn,
.auth-gate.checking #authGateProgress,
.auth-gate.checking .auth-divider,
.auth-gate.checking .auth-gate-card > small { display: none; }
.auth-gate:not(.checking) #authGateChecking { display: none; }
.auth-gate-feedback {
  margin: 16px 0 8px !important;
  padding: 16px 16px;
  border: 1px solid rgba(116, 135, 180, .35);
  border-radius: 12px;
  background: rgba(12, 19, 42, .72);
  color: #c0cadf !important;
  font-size: 16px !important;
  text-align: center;
}
.auth-gate-feedback.error {
  border-color: rgba(239, 115, 137, .45);
  background: rgba(86, 23, 39, .35);
  color: #ffb1c2 !important;
}
.auth-gate-feedback.success {
  border-color: rgba(50, 215, 176, .42);
  background: rgba(23, 62, 59, .52);
  color: #89f4d3 !important;
}
.auth-divider {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 32px 0 24px;
  color: #7b89a8;
  font-size: 16px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-weight: 650;
}
.auth-divider::before, .auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(125, 211, 252, .28), transparent);
}
#toast { z-index:11000; }
/* ⛔ Opacity only — no scale. The 1.8s period is 0.56Hz and begins after a
   400ms delay, so short waits do not flash a loader into existence. */
.brand-loader-logo { object-fit: contain; opacity: 0; animation: brandBreath 1.8s ease-in-out .4s infinite; }
@keyframes brandBreath { 0%, 100% { opacity: .28; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .brand-loader-logo { animation: none; opacity: .82; }
}

@media (max-width: 1050px) {
  .receiver-grid { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .section-title { align-items: stretch; padding-left: 24px; }
  .template-head { padding-right: 0; padding-bottom: 62px; }
  .template-head button { top: auto; left: 0; right: auto; bottom: 14px; }
  .bot-head { padding-right: 112px; }
  .account-manager-head .simulation-chip { margin-right: 0; }
  .media-grid > .empty::before, .media-grid > .empty::after { opacity: .28; right: -20px; }
}

/* 0.3.20 — desktop task navigation: one persistent bar, five user-facing areas, readable type. */
body { font-size: 18px; line-height: 1.55; }
.app-header {
  position: sticky;
  /* The header itself is the draggable title bar. Interactive children carve
     out no-drag islands, so the old empty 32px strip is no longer necessary. */
  --qw-header-h: 88px;
  top: 0;
  margin-top: 0;
  z-index: 9000;
  display: flex;
  min-height: var(--qw-header-h);
  align-items: center;
  justify-content: flex-start;
  gap: 32px;
  padding: 0 16px 0 32px;
  border-bottom: 1px solid rgba(143, 169, 196, .22);
  background: rgba(5, 9, 21, .94);
  box-shadow: 0 16px 40px rgba(0, 0, 0, .32);
  backdrop-filter: blur(24px) saturate(125%);
  -webkit-app-region: drag;
}
.app-header .tabs, .app-header .header-status, .app-header .emergency-controls, .app-header .window-controls, .app-header button, .app-header a { -webkit-app-region: no-drag; }
.app-header .brand { display: flex; flex: 0 0 auto; align-items: center; gap: 16px; min-width: 190px; }
.brand-logo { width: 58px; height: 68px; flex: 0 0 58px; object-fit: contain; filter: drop-shadow(0 0 14px rgba(35, 204, 236, .16)); }
.app-header .brand-text { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.app-header .brand strong { color: #f5f8ff; font: 700 30px/1 "Segoe UI Variable", "Segoe UI", sans-serif; letter-spacing: -.02em; }

/* ── 0.3.35 頂欄：單一聚合狀態燈 ＋ 條件式更新徽章 ──────────────────────────
   依據 `_AI_BRAIN/05_Planning/QuantWing_頂欄UX_業界慣例研究_2026-08-07.md`：
   · 10 個抽樣桌面 app 沒有一個把「檢查更新」常駐頂欄 ⇒ 已搬進「設定 → 關於」。
   · 頂欄只留「有更新才長出來」的徽章（Slack／Spotify／VS Code 的形狀）。
   · 狀態走方案 A：一顆聚合燈（文字 ≤4 字）＋ 點開明細；聚合色取最高警示色（Carbon）。
   · 不可只靠顏色（WCAG 1.4.1）⇒ 色 ＋ 形狀符號 ＋ 文字三者同時帶。 */
/* ── 緊急控制（全平 ／ 停機）────────────────────────────────────────────
   實色紅、最小 36px 高、⛔ 不做成圖示鈕：出事時要找得到、按得中。停用時保留可讀
   的對比（WCAG 1.4.3），因為「為什麼按不下去」得看得懂 title 才問得出下一步。
   兩顆不同形：全平是實心紅（主要動作），停機是外框（次要、且它會擋掉平倉）——
   ⛔ 不可只靠顏色區分（WCAG 1.4.1），所以兩顆的文字本身就寫明白在做什麼。 */
/* ⛔ 不可加 margin-left:auto。header 的剩餘寬度是刻意留給 .window-controls 的
   margin-left:auto 吸收的 —— 那段空隙屬於 .app-header 本身，是視窗唯一可拖曳的
   中性表面（見 .app-header .tabs 的註解）。這裡再放一個 auto 會把它分掉，讓標題列
   變得拖不動。用 0 1 auto：不生長，但窄視窗仍可收縮不溢出。 */
.emergency-controls { display: flex; flex: 0 1 auto; align-items: center; gap: var(--space-2); }
.emergency-flatten,
.emergency-halt {
  min-height: 40px;
  padding: 0 var(--space-3);
  border-radius: 999px;
  /* ⛔ 不可換行。窄視窗實測（900px）字會斷成「全部平／倉」，既難讀又把
     height:76px 的頂欄從內部撐破。緊急按鈕寧可讓分頁列先收縮。 */
  white-space: nowrap;
  flex: 0 0 auto;
  border-width: 1px;
  border-style: solid;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: .04em;
  transition: transform .14s ease, filter .14s ease;
}
.emergency-flatten {
  color: #fff;
  border-color: #ff7188;
  background-color: #9f2945;
  background-image: linear-gradient(135deg, #cf4864, #9f2945);
  box-shadow: inset 0 1px rgba(255, 255, 255, .18), 0 8px 20px rgba(0, 0, 0, .22);
}
.emergency-halt {
  color: #ffc7d1;
  border-color: rgba(255, 113, 136, .55);
  background: rgba(60, 12, 24, .72);
}
.emergency-halt.active {
  color: #fff;
  border-color: #ffd166;
  background: linear-gradient(135deg, #b4531a, #7d3410);
}
.emergency-flatten:hover:not(:disabled),
.emergency-halt:hover:not(:disabled) { filter: brightness(1.12) saturate(1.08); transform: translateY(-1px); }
.emergency-flatten:focus-visible,
.emergency-halt:focus-visible { outline: 3px solid #70d7ff; outline-offset: 3px; }
.emergency-flatten:disabled,
.emergency-halt:disabled { opacity: .58; filter: saturate(.55); cursor: not-allowed; transform: none; }

/* 停機橫幅：全域狀態要有全域提示，⛔ 不能只靠一顆按鈕變色。 */
.halt-banner {
  /* ⛔ position/z-index 不是裝飾。這個外殼裡的 <main> 是 position:relative;z-index:1，
     而定位過的元素會畫在未定位的兄弟之上 —— 橫幅原本是 static，實測（像素取樣）
     底色整條沒被畫出來，連臨時改成 !important 的純紅都畫不出來，只有版面被推開。
     一個佔了位置卻看不見的警示橫幅，比沒有橫幅更糟：它讓人以為全域提示已經有了。 */
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: 12px 32px;
  border-bottom: 1px solid rgba(255, 113, 136, .55);
  color: #ffe0e6;
  background: linear-gradient(135deg, #7d1226, #4a0a17);
  font-size: 14px;
  font-weight: 700;
}
.halt-banner[hidden] { display: none; }
.halt-banner strong { color: #fff; font-size: 16px; letter-spacing: .03em; }
.halt-banner .halt-banner-note { color: #ffc7d1; font-weight: 800; }

.header-status { position: relative; display: flex; flex: 0 0 auto; align-items: center; gap: var(--space-2); min-width: 0; }

.header-update-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid rgba(242, 184, 75, .5);
  border-radius: 999px;
  color: #ffd98f;
  background: rgba(60, 44, 14, .82);
  font-size: var(--text-sm);
  font-weight: 700;
  white-space: nowrap;
  -webkit-app-region: no-drag;
}
.header-update-badge::before { content: '▲'; font-size: 14px; }
.header-update-badge:hover { border-color: rgba(242, 184, 75, .85); color: #fff0cd; }
.header-update-badge[hidden] { display: none; }

.system-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid rgba(143, 169, 196, .3);
  border-radius: 999px;
  color: #cfe0f2;
  background: rgba(12, 24, 41, .72);
  font-size: var(--text-sm);
  font-weight: 700;
  white-space: nowrap;
  -webkit-app-region: no-drag;
}
.system-status:hover { border-color: rgba(143, 169, 196, .6); color: #f1f8ff; }
/* 形狀符號隨狀態改變 —— 色盲與單色列印下仍分得出來 */
.system-status-icon { font-size: 14px; line-height: 1; color: var(--green); }
.system-status.warn .system-status-icon { color: var(--amber); }
.system-status.pending .system-status-icon { color: var(--cyan); }
.system-status.error .system-status-icon { color: var(--red); }
.system-status.warn { border-color: rgba(242, 184, 75, .45); }
.system-status.pending { border-color: rgba(120, 229, 255, .48); background: rgba(20, 69, 94, .2); }
.system-status.error { border-color: rgba(255, 98, 121, .5); }

.system-status-panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: 9500;
  min-width: 268px;
  width: min(320px, calc(100vw - 24px));
  max-width: calc(100vw - 24px);
  box-sizing: border-box;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: rgba(8, 14, 30, .98);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
  -webkit-app-region: no-drag;
}
.system-status-panel[hidden] { display: none; }
/* 緊急控制搬進系統狀態面板（站長 2026-08-18：頂欄太擠）。
   在頂欄時它得跟分頁列搶寬度，所以是 flex:0 0 auto 的窄膠囊；在面板裡沒有競爭者
   ⇒ 改成兩欄等寬撐滿，點擊目標反而比搬家前**更大**，多少補回一點「多一次點擊」的代價。
   ⛔ 分隔線在下緣不在上緣：緊急控制是這個面板的第一區塊，線的作用是把它跟下面
      四行狀態切開，不是替它加一頂帽子。 */
.system-status-panel .emergency-controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
}
.system-status-panel .emergency-flatten,
.system-status-panel .emergency-halt {
  width: 100%;
  min-height: 48px;
  padding: 0 var(--space-2);
}
.system-status-row { display: grid; grid-template-columns: 16px max-content minmax(0, 1fr); align-items: center; gap: var(--space-2); min-width: 0; padding: 8px 0; font-size: var(--text-sm); }
.system-status-row .system-status-icon { flex: 0 0 auto; }
.system-status-row > span:nth-child(2) { color: var(--muted); white-space: nowrap; }
.system-status-row > strong { min-width: 0; font-weight: 700; white-space: normal; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
@media (max-width: 760px) {
  .system-status-panel { box-sizing: border-box; overflow-wrap: anywhere; }
  .system-status-row { align-items: start; }
  .system-status-row > span:nth-child(2) { min-width: 0; }
  .system-status-row > strong { min-width: 0; white-space: normal; }
}
@media (max-width: 360px) {
  .system-status-panel { position: fixed; top: 64px; right: 12px; min-width: 0; }
}
.system-status-row.error {
  margin: 2px -8px;
  padding: 8px 12px;
  border: 1px solid rgba(255, 98, 121, .24);
  border-radius: 8px;
  background: rgba(255, 98, 121, .08);
}
.system-status-row.error .system-status-icon,
.system-status-row.error .system-status-label,
.system-status-row.error > strong { color: var(--red); }
.system-status-row.pending {
  margin: 2px -8px;
  padding: 8px 12px;
  border: 1px solid rgba(120, 229, 255, .22);
  border-radius: 8px;
  background: rgba(39, 122, 154, .08);
}
.system-status-row.pending .system-status-icon,
.system-status-row.pending .system-status-label,
.system-status-row.pending > strong { color: var(--cyan); }
.system-status-link { display: inline-block; margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border); color: #8fc9e8; font-size: var(--text-sm); text-decoration: none; }
.system-status-link:hover { color: #dff3ff; }
/* Fleet card: name always owns exactly 2 lines; meta never steals line 2 */
.bot-identity .bot-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  min-height: calc(1.3em * 2);
  max-height: calc(1.3em * 2);
  margin: 4px 0 8px;
  color: #f3f5ff;
  /* 0.5.0 反熵：font-size / font-weight / letter-spacing 三條移交檔尾的設計系統層。
     ⛔ 這一條的 specificity 是 (0,2,0)，會贏過檔尾的 `.bot-head h3` (0,1,1) ——
        留著就等於檔尾那層對卡片標題**完全沒有效果**，而畫面不會有任何錯誤。
     ⛔ 其餘屬性一個都不能刪：line-clamp 2 行 ＋ min/max-height 是
        「名字永遠佔兩行、meta 不會偷走第二行」的承重機制（見上方註解）。
     ⚠ min/max-height 用 em ⇒ 跟著新的 22px 走（1.3em × 2 = 57.2px），版面自動對齊。 */
  line-height: 1.3;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.bot-identity .bot-meta {
  margin: 0;
  color: #7f88aa;
  font-size: 14px;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bot-identity .card-code {
  display: block;
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.app-header .tabs {
  position: static;
  display: flex;
  /* ⛔ 不可改回 flex-grow:1。分頁列同時在 CSS 的 no-drag 排除集（:2505）與
     shell-host-bridge.js 的 INTERACTIVE_SELECTOR 裡，一旦它吃掉 header 的剩餘寬度，
     中段與右半那片「看起來是空白」的區域命中的其實是 nav.tabs ⇒ 拖不動。
     用 0 1 auto：不生長，但保留收縮（窄視窗才不會溢出）。
     剩餘寬度改由 .window-controls 的 margin-left:auto 吸收，那段空隙屬於
     .app-header 本身，所以是可拖曳的中性表面。 */
  flex: 0 1 auto;
  height: 88px;
  min-width: 0;
  align-items: stretch;
  gap: 4px;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  backdrop-filter: none;
}
.app-header .tab {
  position: relative;
  min-width: 96px;
  height: 88px;
  min-height: 88px;
  padding: 0 24px;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 0;
  color: #9da9c3;
  background: transparent;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: .01em;
}
.app-header .tab::before, .app-header .tab::after { display: none; }
.app-header .tab:hover { color: #f1f5ff; background: rgba(111, 135, 180, .1); }
.app-header .tab.active {
  color: var(--sel-ink);
  border-bottom-color: var(--sel-border);
  background: var(--sel-bg);
  box-shadow: none;
}
.header-status .mode-badge { padding: 12px 16px; font: 750 16px/1 "Segoe UI Variable", "Segoe UI", sans-serif; letter-spacing: .02em; white-space: nowrap; }
main { padding: 64px 48px 72px; }
.section-title { align-items: flex-start; margin: 48px 0 32px; }
.section-title h1 { margin-bottom: 12px; }
.section-title h2 { margin-bottom: 8px; }
.section-title p, .muted { line-height: 1.6; }
.section-kicker, .eyebrow { font-size: 14px; letter-spacing: .1em; }
.module-card::after { font-size: 14px; letter-spacing: .08em; }
.template-head h2 { font-size: 30px; }
.json-template::before { font-size: 14px; line-height: 30px; }
button, .button { min-height: 52px; padding-right: 24px; padding-left: 24px; font-size: 18px; }
input, select { min-height: 56px; }
body small { font-size: 16px; }
/* 0.3.41 VIS-04：這裡原本還有一條 `.metric span { font-size: 16px }`，已刪除。
   它是死規則 —— `.metric .metric-label > span`（styles.css:995，特異性較高）已經把
   指標卡標題釘在 12px，而 `.metric span` 剩下能選到的只有 .metric-icon 與
   .metric-signal 兩個 span，這兩個都是固定 px 尺寸、無文字內容，font-size 對它們
   零視覺效果。留著只會讓下一個想調標題字級的人改到它然後發現沒反應。 */
.metric strong { font-size: 48px; }
.metric small, .metric-label small, .metric-reading small { font-size: 16px; }
/* 0.3.41 VIS-04 ⚠ font-weight: 500 是承重的，⛔ 別「順手」拿掉。
   996 用 `font: 700 8px/1 ui-monospace…` 簡寫把副標釘成 700；這裡只覆蓋 font-size
   時，主標（995：12px/700）與副標會變成**完全相同的 12px/700**，元件內階層歸零 ——
   副標是等寬字 + letter-spacing 1.05px，渲染寬度比主標還長，反而搶走主標的重量。
   ⛔ 降階不要走 font-size：再縮小會掉進 VIS-13 點名的那批 8–9px 過小字。
   ⛔ 降階也不要走 opacity：實測 opacity .85 就把副標對比壓到 4.13（低於 AA 4.5），
   等於一邊修階層一邊製造新的無障礙問題。字重是唯一不動字級也不動對比的通道。 */
.metric .metric-label > small { font-size: 14px; font-weight: 500; }
.bot-head p, .account-manager-title p, .account-form-hint, .receiver-status small, .strategy-route-note, .notice { font-size: 16px; }
.bot-stats strong, .account-detail-row dd, .account-username { font-size: 18px; }
.bot-actions button, .account-card-actions button { min-height: 48px; font-size: 16px; }
.webhook code, .copy-field code, .json-template { font-size: 16px; }
th, td { padding: 24px 24px; font-size: 16px; }
/* Enterprise scale — keep above base auth-gate rules (do not shrink). */
.auth-gate-card h1 { font-size: 48px; }
.auth-gate-card > p { font-size: 20px; }
.auth-google-button { font-size: 20px; }
.auth-gate-card > small, .auth-gate-progress, .auth-gate-feedback { font-size: 16px !important; }
.auth-divider { font-size: 16px !important; }
.api-safety-badge { display: inline-flex; align-items: center; min-height: 48px; padding: 0 16px; border: 1px solid rgba(72, 213, 151, .35); border-radius: 999px; color: #9af0c8; background: rgba(20, 54, 45, .7); font-size: 14px; font-weight: 800; letter-spacing: .06em; white-space: nowrap; }
.api-layout { display: grid; grid-template-columns: minmax(390px, .78fr) minmax(560px, 1.22fr); gap: 24px; align-items: start; }
.api-key-card, .api-command-card { overflow: hidden; }
.api-service-field { display: grid; gap: 8px; min-width: 0; }
.api-service-heading { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.api-service-heading label { margin: 0; }
.api-service-heading input { width: 7em; min-width: 0; margin: 0; }
.api-service-heading button { margin: 0; }
.api-service-field > label, .api-service-field > p { margin: 0; }
.api-key-status { display: flex; align-items: center; gap: 16px; min-height: 88px; margin-bottom: 24px; padding: 24px 24px; border: 1px solid rgba(137, 176, 228, .18); border-radius: 16px; background: rgba(4, 10, 26, .58); }
.api-key-status > span { width: 12px; height: 12px; flex: 0 0 12px; border-radius: 50%; background: var(--red); box-shadow: 0 0 15px rgba(255, 98, 121, .55); }
.api-key-status > span.online { background: var(--green); box-shadow: 0 0 15px rgba(72, 213, 151, .6); }
.api-key-status small, .api-key-status strong { display: block; }
.api-key-status small { color: var(--muted); font-size: 16px; }
.api-key-status strong { margin-top: 3px; font-size: 20px; }
.api-key-actions { margin: 24px 0 24px; }
.api-key-dialog { width: min(720px, calc(100vw - 40px)); }
.api-key-dialog form { padding: 48px; }
.api-key-full-value { margin-top: 32px; padding: 24px; border: 1px solid rgba(126, 170, 235, .28); border-radius: 15px; background: rgba(2, 6, 18, .86); }
.api-key-full-value code { display: block; color: #a7dfff; font: 700 18px/1.7 ui-monospace, Consolas, monospace; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-all; user-select: all; }
.api-command-head { display: flex; align-items: end; justify-content: space-between; gap: 24px; margin-bottom: 24px; padding-bottom: 24px; border-bottom: 1px solid rgba(153, 167, 224, .14); }
.api-command-head h2 { margin: 4px 0 8px; font-size: 30px; }
.api-command-head p { margin: 0; color: var(--muted); font-size: 18px; }
.api-command-head label { width: 180px; flex: 0 0 180px; margin: 0; }
.api-command-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 16px; }
.api-command-item { padding: 24px; border: 1px solid rgba(137, 159, 218, .16); border-radius: 15px; background: rgba(4, 9, 24, .62); }
.api-command-item.critical { border-color: rgba(242, 184, 75, .42); background: rgba(57, 42, 15, .34); }
.api-command-title { display: flex; align-items: center; gap: 16px; }
.api-command-title strong, .api-command-title small { display: block; }
.api-command-title strong { font-size: 20px; }
.api-command-title small { margin-top: 2px; color: var(--muted); font-size: 14px; }
.api-method { min-width: 68px; padding: 8px 12px; border-radius: 8px; color: #c9eaff; background: rgba(31, 91, 126, .54); font: 800 14px/1 ui-monospace, Consolas, monospace; text-align: center; }
.api-method.post, .api-method.patch, .api-method.put { color: #bff4d9; background: rgba(28, 101, 75, .48); }
.api-method.delete { color: #ffbcc8; background: rgba(119, 43, 62, .48); }
.api-command-item p { margin: 16px 0; color: #a8b5cd; font-size: 16px; }
.api-command-item .copy-field code { white-space: pre-wrap; overflow-wrap: anywhere; }

/* 頂欄多了兩顆緊急按鈕（約 168px），分頁列的收縮斷點要跟著提早。
   下面那條 1180px 是按「沒有這兩顆」算出來的：實測（量 scrollWidth − clientWidth）
   1200px 時分頁文字就會溢出 .tabs 自己的框 145px 而壓到緊急按鈕上 —— flex 兄弟
   不會互相重疊，但「內容溢出自己的框」會，兩者在版面上長得一模一樣。
   ⛔ 這裡只縮分頁列，不動 1180px 那段的其他規則（api-layout 等）。
   ⛔ 這個斷點跟緊急按鈕的寬度綁在一起：改按鈕文字或 padding 要回頭重量一次。 */
@media (max-width: 1400px) {
  .app-header { gap: 24px; }
  .app-header .tab { min-width: 84px; padding-right: 16px; padding-left: 16px; font-size: 16px; }
}

/* 只縮 padding 救不了：.tabs 這個容器會收縮（flex 0 1 auto），但裡面每顆 .tab 有
   min-width 不收縮 ⇒ 內容照樣溢出容器、視覺上壓在右邊的鄰居身上。實測 1200px 仍
   溢出 89px。放不下就捲動是分頁列的通用做法（VS Code／Chrome 都是），⛔ 不用
   overflow:hidden —— 那會直接切掉最右邊的「設定」，看不到又點不到。
   捲軸隱藏：這是桌面殼的標題列，一條橫捲軸會把 76px 的頂欄壓掉一截。 */
.app-header .tabs {
  overflow-x: auto;
  scrollbar-width: none;
}
.app-header .tabs::-webkit-scrollbar { display: none; }

@media (max-width: 1180px) {
  .app-header { gap: 16px; padding-right: 12px; padding-left: 24px; }
  .app-header .brand { min-width: 170px; }
  .header-status .mode-badge { display: none; }
  .app-header .tab { min-width: 88px; padding-right: 16px; padding-left: 16px; }
  .api-layout { grid-template-columns: 1fr; }
}

@media (max-width: 900px) {
  .app-header { gap: 12px; }
  .app-header .brand { min-width: auto; }
  .app-header .brand strong { display: none; }
  .brand-logo { width: 54px; height: 64px; flex-basis: 54px; }
  /* 研究 §2 方案 C：極窄才降級成 icon-only，且必須靠 aria-label 補文字（見 app.js
     renderSystemStatus）。⛔ 0.3.34 以前這裡是 `.header-status{display:none}`，
     狀態在窄視窗直接消失、連 aria 都拿不到。 */
  .system-status { padding: 0 12px; }
  .system-status-text { display: none; }
  .app-header .tab { flex: 1 1 0; min-width: 0; padding-right: 12px; padding-left: 12px; }
  main { padding-right: 32px; padding-left: 32px; }
}

@media (max-width: 520px) {
  .app-header {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: 48px 48px;
    gap: 0 6px;
    min-height: 96px;
    padding: 0 6px;
  }
  .app-header .brand { grid-column: 1; grid-row: 1; min-width: 0; gap: 0; }
  .brand-logo { width: 38px; height: 44px; flex-basis: 38px; }
  .app-header .brand-text { display: none; }
  .header-status { grid-column: 2; grid-row: 1; justify-self: end; }
  .app-header .window-controls { grid-column: 3; grid-row: 1; margin-left: 0; }
  .app-header .tabs { grid-column: 1 / -1; grid-row: 2; width: 100%; height: 48px; }
  .app-header .tab { flex: 1 0 72px; height: 48px; min-height: 48px; padding: 0 8px; font-size: 13px; }
  .app-header .tab.active::after { bottom: 0; }
  main { padding: 24px 14px 48px; }
}

/* ── 0.3.32 Workbench（案 A：一次一機主焦點）＋ ⋯ 選單 ＋ Order Ticket ── */

/* ⛔ display 必須綁在 .active 上，且特異性要贏 .panel.active{display:block}（0,2,0）。
   0.3.32 原寫 `.workbench-panel{display:flex}`（0,1,0）造成兩個 bug：
   ① 排在 .panel{display:none}(45行) 之後 ⇒ 沒 active 也永遠顯示，與當前分頁疊在一起，
      使用者點分頁時畫面看起來沒變＝「分頁點不動／整個混一起」（0.3.33 站長回報）。
   ② 輪到自己 active 時反被 .panel.active(0,2,0) 蓋成 display:block ⇒ flex 直向版面失效。 */
.workbench-panel { flex-direction: column; gap: var(--space-3); min-height: 0; }
.panel.workbench-panel.active { display: flex; }

.workbench-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  /* 3:2 畫布比視窗高時整頁會捲。頁籤不跟著捲走，才看得出選中哪台。 */
  position: sticky;
  top: var(--qw-header-h, 88px);
  z-index: 50;
}
.workbench-picker-stack {
  position: relative;
  display: grid;
  grid-template-columns: minmax(112px, .72fr) minmax(210px, 1.28fr);
  flex: 0 1 clamp(360px, 34vw, 440px);
  min-width: 340px;
  border: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
  border-radius: 14px;
  background: linear-gradient(145deg, color-mix(in srgb, var(--surface-2) 92%, #19234f), var(--surface));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04), 0 10px 30px rgba(0,0,0,.14);
}
.workbench-group-picker {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  align-content: center;
  gap: 0;
  min-height: 54px;
  margin: 0;
  padding: 5px 9px 4px;
  border-right: 1px solid color-mix(in srgb, var(--cyan) 16%, var(--border));
  color: var(--muted);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .08em;
}
.workbench-group-picker select {
  width: 100%;
  min-width: 0;
  max-width: none;
  min-height: 27px;
  margin: 0;
  padding: 0 22px 0 4px;
  border: 0;
  background-color: transparent;
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
}
.workbench-group-picker select:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; border-radius: 7px; }
.workbench-bot-picker { position: relative; }
.workbench-bot-picker > summary {
  position: relative;
  display: block;
  min-height: 54px;
  padding: 7px 34px 7px 10px;
  list-style: none;
  cursor: pointer;
  border-radius: 0 13px 13px 0;
  transition: background .14s ease, box-shadow .14s ease;
}
.workbench-bot-picker > summary::-webkit-details-marker { display: none; }
.workbench-bot-picker > summary::after {
  content: '';
  position: absolute;
  right: 13px;
  top: 50%;
  width: 7px;
  height: 7px;
  border-right: 1.7px solid var(--muted);
  border-bottom: 1.7px solid var(--muted);
  transform: translateY(-65%) rotate(45deg);
  transition: transform .16s ease, border-color .16s ease;
}
.workbench-bot-picker[open] > summary { background: color-mix(in srgb, var(--cyan) 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 24%, transparent); }
.workbench-bot-picker[open] > summary::after { border-color: var(--cyan); transform: translateY(-30%) rotate(225deg); }
.workbench-bot-picker > summary:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.workbench-tabs {
  position: absolute;
  z-index: 90;
  top: calc(100% + 8px);
  left: -1px;
  display: grid;
  gap: 4px;
  width: min(340px, calc(100vw - 48px));
  max-height: min(420px, 62vh);
  overflow: auto;
  padding: 7px;
  border: 1px solid color-mix(in srgb, var(--cyan) 30%, var(--border));
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface) 96%, #050816);
  box-shadow: 0 24px 70px rgba(0,0,0,.52), inset 0 1px 0 rgba(255,255,255,.05);
}
.workbench-bot-picker:not([open]) .workbench-tabs { display: none; }
.wb-bot-option {
  width: 100%;
  min-height: 54px;
  padding: 6px 9px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  text-align: left;
}
.wb-bot-option:hover, .wb-bot-option:focus-visible { background: var(--surface-2); border-color: color-mix(in srgb, var(--cyan) 22%, transparent); }
.wb-bot-option.active { background: color-mix(in srgb, var(--cyan) 10%, var(--surface-2)); border-color: color-mix(in srgb, var(--cyan) 42%, transparent); }
.wb-bot-picker-row { display: grid; grid-template-columns: 8px 36px minmax(0, 1fr); align-items: center; gap: 9px; width: 100%; min-width: 0; }
.wb-bot-picker-row.is-all { grid-template-columns: 36px minmax(0, 1fr); }
.wb-bot-picker-copy { display: grid; gap: 2px; min-width: 0; }
.wb-bot-picker-name, .wb-bot-picker-meta { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); min-width: 0; }
.wb-bot-picker-name { overflow: hidden; color: var(--text); font-size: 13px; font-weight: 720; white-space: nowrap; text-overflow: ellipsis; }
.wb-bot-picker-name small { flex-shrink: 0; color: var(--muted); font-size: 10px; font-weight: 550; letter-spacing: .03em; }
.wb-bot-picker-meta { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.wb-bot-picker-meta strong { color: color-mix(in srgb, var(--text) 88%, var(--cyan)); font-weight: 650; }
.wb-bot-all-icon { display: grid; grid-template-columns: repeat(2, 6px); grid-auto-rows: 6px; gap: 3px; place-content: center; width: 36px; height: 36px; border-radius: 50%; background: color-mix(in srgb, var(--cyan) 9%, var(--surface-2)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 25%, transparent); }
.wb-bot-all-icon i { display: block; border-radius: 2px; background: color-mix(in srgb, var(--cyan) 68%, var(--muted)); }
.wb-bot-option-all { display: grid; grid-template-columns: 36px minmax(0, 1fr); align-items: center; gap: 17px; }
.workbench-bar-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); flex: 1 1 auto; min-width: 0; }
.wb-layout-switch { display: inline-flex; padding: 3px; gap: 2px; border: 1px solid var(--border); border-radius: 11px; background: var(--surface-2); }
.wb-layout-switch[hidden] { display: none !important; }
.wb-layout-switch button { width: 34px; min-width: 34px; height: 34px; min-height: 34px; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--muted); }
.wb-layout-switch svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; }
.wb-layout-switch button[aria-pressed="true"] { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 14%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 45%, transparent); }
.workbench-panel[data-layout="grid"] .workbench-robot-trade,
.workbench-panel[data-layout="grid"] #workbenchMoreBtn { display: none; }
.workbench-trade { min-width: 112px; min-height: 52px; font-size: 18px; letter-spacing: .06em; }
/* 「機器人操作・市價」小標：一組兩顆按鈕共用一行字。
   ⛔ 不做成每顆按鈕各寫一次 —— 同一件事在相鄰兩顆鍵上講兩遍就是視覺雜訊。
   ⛔ 也不把它做成一整段說明：它要在不擠壓版面的前提下，把「這是機器人下的
   市價單」跟畫面裡 Tradovate 網頁自己的買賣鍵分開。 */
.workbench-robot-trade { display: flex; flex-direction: column; gap: 4px; }
/* ⚠ 12px 不是隨手挑的：11px 實測（verify-ui2-connected.png）淡到要湊近才看得清，
   而這行字的整個作用就是讓人一眼分出「機器人下的單」和「網頁上自己按的單」——
   看不清就等於沒有。⛔ 但也不再放大：它不該跟兩顆主按鈕搶注意力。 */
/* ⛔ 顏色只用 --muted：這支 CSS 有三組主題各自重寫調色盤（第 7／252／585 行），
   寫死色碼的那一版會在另外兩個主題下失準。 */
.wb-trade-label { font-size: 14px; line-height: 1; letter-spacing: .04em; color: var(--muted); text-align: center; white-space: nowrap; }
.wb-trade-row { display: flex; gap: var(--space-2); }

/* 瀏覽方式切換（外部／背景／內部）：分段控制，當前那格反白。 */

/* 舞台空狀態裡的操作列（啟動連線／改為內建瀏覽）。 */
.wb-stage-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); }

.wb-tab { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-3); border-radius: 999px; background: transparent; border: 1px solid transparent; color: var(--muted); font-size: var(--text-sm); white-space: nowrap; cursor: pointer; }
.wb-tab-select { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 28px; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.wb-tab .bot-avatar-button { width: 28px; min-width: 28px; height: 28px; min-height: 28px; }
.wb-tab:hover { background: var(--surface-2); color: var(--text); }
.wb-tab.active {
  background: var(--sel-bg);
  border-color: var(--sel-border);
  color: var(--sel-ink);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sel-border) 55%, transparent);
}
.wb-tab-name { max-width: 12ch; overflow: hidden; text-overflow: ellipsis; }
.wb-tab-pnl { font-variant-numeric: tabular-nums; font-size: 14px; }
.wb-tab-empty { font-size: var(--text-sm); }

.wb-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex-shrink: 0; }
.wb-dot.running { background: var(--green); box-shadow: 0 0 0 3px rgba(72, 213, 151, .18); }
.wb-dot.connecting, .wb-dot.awaiting_verification { background: var(--amber); }
.wb-dot.error { background: var(--red); }

.workbench-stage { position: relative; flex: 1 1 64%; min-height: 300px; display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.workbench-stage.is-single-fullscreen { position: fixed; inset: 0; z-index: 9500; width: 100dvw; height: 100dvh; min-height: 0; margin: 0; overflow: hidden; border: 0; border-radius: 0; background: var(--bg); box-shadow: none; }
.wb-stage-head { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--border); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.wb-stage-identity { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.wb-stage-identity-copy { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.wb-stage-identity-copy strong { max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.wb-stage-identity-copy small { color: var(--muted); }
.wb-stage-metrics { display: flex; align-items: center; gap: var(--space-2); flex: 1 1 auto; min-width: 0; }
.wb-stage-head-spacer { flex: 1 1 auto; min-width: 0; }
.wb-pane-tabs { display: inline-flex; align-items: center; gap: 2px; padding: 2px; border-radius: 9px; background: var(--surface-2); }
.wb-pane-tabs button { width: 30px; min-width: 30px; height: 28px; min-height: 28px; padding: 0; border: 0; border-radius: 7px; background: transparent; color: var(--muted); }
.wb-pane-tabs button[aria-selected="true"] { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 14%, transparent); }
.wb-pane-tabs svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.bot-avatar-frame {
  position: relative;
  box-sizing: border-box;
  aspect-ratio: 1 / 1;
  overflow: visible;
  border: 0;
  border-radius: 50%;
  padding: 2px;
  background: conic-gradient(from 215deg, #57e6d1 0 20%, #6ccfff 34%, #8d78ff 58%, #ff78c8 77%, #57e6d1 100%);
  box-shadow: 0 0 0 1px rgba(115,224,255,.18), 0 0 14px rgba(78,185,255,.20), inset 0 0 0 1px rgba(255,255,255,.28);
  flex: 0 0 auto;
}
.bot-avatar-frame::before {
  content: '';
  position: absolute;
  inset: 2px;
  z-index: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 24%, rgba(128,232,255,.20), rgba(8,13,33,.92) 72%);
}
.bot-avatar-frame img { position: relative; z-index: 1; display: block; width: 100%; height: 100%; aspect-ratio: 1 / 1; border-radius: 50%; object-fit: cover; background: #0b1024; }
.bot-avatar-button { width: 40px; min-width: 40px; max-width: 40px; height: 40px; min-height: 40px; max-height: 40px; cursor: pointer; }
.bot-avatar-display { width: 36px; min-width: 36px; max-width: 36px; height: 36px; min-height: 36px; max-height: 36px; }
.bot-avatar-button::after {
  content: attr(data-avatar-tooltip);
  position: absolute;
  z-index: 80;
  left: 50%;
  top: calc(100% + 8px);
  bottom: auto;
  width: max-content;
  max-width: 160px;
  padding: 6px 9px;
  border: 1px solid rgba(151, 166, 224, .38);
  border-radius: 8px;
  background: rgba(17, 21, 48, .98);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .38);
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 4px);
  transition: opacity .14s ease, transform .14s ease;
}
.bot-avatar-button:hover::after, .bot-avatar-button:focus-visible::after { opacity: 1; transform: translate(-50%, 0); }
.bot-avatar-button:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
.bot-head .bot-card-avatar {
  width: clamp(68px, 6vw, 82px);
  min-width: clamp(68px, 6vw, 82px);
  max-width: clamp(68px, 6vw, 82px);
  height: clamp(68px, 6vw, 82px);
  min-height: clamp(68px, 6vw, 82px);
  max-height: clamp(68px, 6vw, 82px);
  flex: 0 0 clamp(68px, 6vw, 82px);
  border-width: 2px;
  box-shadow: 0 0 0 4px rgba(10, 18, 43, .72), 0 10px 28px rgba(0, 0, 0, .32);
}
.bot-head-main { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.bot-record-cell { display: inline-flex; align-items: center; gap: 8px; }
.bot-record-cell .bot-avatar-button { width: 28px; min-width: 28px; max-width: 28px; height: 28px; min-height: 28px; max-height: 28px; }
.wb-stage-symbol { font-weight: 600; color: var(--text); }
.wb-stage-side, .wb-stage-price { color: var(--muted); }
.wb-stage-pnl { margin-left: auto; font-weight: 600; }
.wb-stage-resource-toggle {
  position: relative;
  flex: 0 0 36px;
  width: 36px;
  height: 32px;
  min-width: 36px;
  min-height: 32px;
  padding: 0;
  border: 1px solid rgba(151, 166, 224, .28);
  border-radius: 10px;
  background: rgba(24, 30, 65, .62);
  color: #83d9bd;
}
.wb-stage-resource-toggle svg { width: 20px; height: 20px; overflow: visible; }
.wb-stage-resource-toggle .battery-shell,
.wb-stage-resource-toggle .battery-cap { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
.wb-stage-resource-toggle .battery-level { fill: currentColor; transform-origin: left center; transition: transform .16s ease, color .16s ease; }
.wb-stage-resource-toggle.is-saving { border-color: rgba(255, 198, 90, .35); color: #ffd06d; background: rgba(72, 50, 16, .42); }
.wb-stage-resource-toggle.is-saving .battery-level { transform: scaleX(.28); }
.wb-stage-resource-toggle:hover { border-color: currentColor; }
.wb-stage-fullscreen {
  flex: 0 0 36px; width: 36px; height: 32px; min-width: 36px; min-height: 32px;
  padding: 0; border: 1px solid rgba(151, 166, 224, .28); border-radius: 10px;
  background: rgba(24, 30, 65, .62); color: var(--text);
}
.wb-stage-fullscreen svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.wb-stage-fullscreen:hover { border-color: var(--cyan); color: var(--cyan); }
.wb-stage-fullscreen[aria-pressed="true"] {
  border-color: var(--cyan); color: var(--cyan);
  background: rgba(40, 193, 212, .2);
  box-shadow: inset 0 0 0 1px currentColor;
}
.rescue-dialog { width: min(880px, calc(100vw - 24px)); max-height: calc(100dvh - 32px); overflow: auto; padding: 24px; border: 1px solid var(--border); border-radius: 16px; color: var(--text); background: var(--panel, #10192a); }
.rescue-dialog::backdrop { background: rgba(0,0,0,.65); }
.rescue-chat-header { display: flex; justify-content: space-between; align-items: center; gap: 16px; }
.rescue-chat-header h2 { margin: 0; }
.rescue-chat-close { width: 36px; min-height: 36px; padding: 0; font-size: 26px; background: transparent; border: 1px solid var(--border); }
.rescue-chat-toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0; }
.rescue-chat-toolbar select { flex: 1 1 180px; min-width: 0; }
.rescue-chat-layout { display: grid; grid-template-columns: minmax(120px, 180px) minmax(0, 1fr); gap: 16px; }
.rescue-conversation-list { display: flex; flex-direction: column; gap: 8px; max-height: 320px; overflow: auto; }
.rescue-chat-messages { min-height: 140px; height: clamp(180px, 30dvh, 320px); max-height: 360px; overflow: auto; display: flex; flex-direction: column; }
.rescue-chat-empty { margin: auto; text-align: center; color: var(--muted); padding: 16px; max-width: 36ch; }
.rescue-chat-history summary { cursor: pointer; padding: 8px 0; }
.rescue-chat-message { padding: 12px; margin-bottom: 8px; white-space: pre-wrap; overflow-wrap: anywhere; border-radius: 10px; background: rgba(120,150,190,.1); }
.rescue-chat-message[data-role="user"] { border-left: 3px solid var(--cyan); }
.rescue-chat-form { display: grid; grid-template-columns: minmax(0,1fr); gap: 8px; margin: 16px 0 0; padding: 0; }
.rescue-chat-form textarea { width: 100%; min-width: 0; min-height: 76px; max-height: 144px; box-sizing: border-box; resize: vertical; padding: 12px; border: 1px solid var(--border); border-radius: 10px; background: rgba(5,12,25,.7); color: inherit; }
.rescue-chat-send { justify-self: end; min-height: 36px; padding: 6px 18px; }
.notification-bell { position: relative; min-width: 40px; }
.notification-badge { position: absolute; top: -5px; right: -5px; min-width: 18px; padding: 1px 4px; border-radius: 10px; background: var(--red); color: white; font-size: 11px; line-height: 16px; }
.notification-badge[hidden] { display: none; }
.notification-toolbar { display: flex; justify-content: flex-end; padding: 0 0 10px; }
.notification-toolbar > button { min-height: 36px; }
.notification-read-label { color: var(--muted); font-size: 12px; }
.notification-items { display: grid; gap: 12px; }
.notification-item { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 8px; padding: 12px; border-bottom: 1px solid var(--border); }
.notification-item time { color: var(--muted); font-size: 12px; }
.notification-item button { grid-column: 1 / -1; justify-self: start; }
@media (max-width: 600px) { .rescue-dialog { padding: 16px; } .rescue-chat-layout { grid-template-columns: minmax(0,1fr); } .rescue-conversation-list { max-height: 100px; } .notification-item { grid-template-columns: minmax(0,1fr); } }
.wb-stage-resource-tooltip {
  position: absolute;
  z-index: 30;
  top: 50%;
  right: calc(100% + 8px);
  width: max-content;
  max-width: min(260px, calc(100vw - 24px));
  padding: 8px 10px;
  border: 1px solid rgba(151, 166, 224, .38);
  border-radius: 8px;
  color: var(--text);
  background: rgba(17, 21, 48, .98);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .42);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transform: translate(4px, -50%);
  transition: opacity .14s ease, transform .14s ease;
}
.wb-stage-resource-toggle:hover .wb-stage-resource-tooltip,
.wb-stage-resource-toggle:focus-visible .wb-stage-resource-tooltip {
  opacity: 1;
  transform: translate(0, -50%);
}
.wb-stage-canvas { position: relative; flex: 1; display: grid; place-items: center; padding: var(--space-5); }
.wb-stage-problem-strip {
  position: static;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid rgba(255, 191, 71, .82);
  border-radius: 10px;
  color: #fff4d0;
  background: rgba(45, 34, 14, .92);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .34);
  backdrop-filter: blur(12px);
  font-size: 13px;
  line-height: 1.45;
}
.wb-stage-problem-strip strong { flex: 0 0 auto; color: #ffd56a; }
.wb-stage-problem-strip { flex-wrap: wrap; height: auto; max-height: none; white-space: normal; }
.wb-stage-problem-strip > span { flex: 1 1 240px; min-width: 0; overflow-wrap: anywhere; white-space: normal; }
/* 需要人在畫面完成的步驟：同一份母版，右側一顆「已完成」（app.js OPERATOR_ACTION_GUIDES）。 */
.wb-stage-problem-strip .wb-operator-action-done,
.wb-stage-problem-strip .wb-broker-signin { flex: 0 0 auto; min-height: 30px; padding: 4px 16px; pointer-events: auto; }
.wb-stage-problem-strip .wb-broker-signin.is-idle { background: #2f7cf6; border-color: #2f7cf6; color: #fff; }
.wb-stage-problem-strip .wb-broker-signin.is-waiting { background: #d4a017; border-color: #d4a017; color: #1d1606; }
.wb-stage-problem-strip .wb-broker-signin.is-busy { background: #5b6472; border-color: #5b6472; color: #fff; cursor: progress; }
.wb-stage-problem-strip .wb-broker-signin.is-done { background: #1f9d55; border-color: #1f9d55; color: #fff; opacity: 1; }
.wb-stage-problem-strip .wb-broker-signin.is-failed { background: #c0392b; border-color: #c0392b; color: #fff; }
/* 按下「已完成」之後：框線轉綠，說明改成機器人的回覆（app.js operatorActionAcks）。 */
.wb-stage-problem-strip.is-acknowledged { border-color: rgba(74, 222, 128, .85); }
.wb-stage-problem-strip.is-acknowledged strong { color: #86efac; }

.wb-stage-state { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.wb-stage-state strong { font-size: var(--text-xl); color: var(--text); }
.wb-stage-state span { max-width: 42ch; font-size: var(--text-sm); }
.wb-stage-resource-state { max-width: 580px; padding: var(--space-5); }
.wb-stage-resource-state strong { color: var(--cyan); }

.workbench-stage[data-layout="split"] { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(360px, 1fr); gap: var(--space-3); padding: 0; overflow: visible; border: 0; background: transparent; min-height: min(760px, calc(100vh - 190px)); }
.wb-focus-pane { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 360px; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); }
.wb-focus-pane .wb-stage-head { flex-wrap: wrap; gap: 8px; padding: 8px 10px; }
.wb-focus-pane .wb-stage-identity { margin-right: auto; }
.wb-focus-pane .wb-stage-metrics { display: flex; align-items: center; gap: 8px; order: 3; width: 100%; }
.wb-focus-pane .wb-stage-pnl { margin-left: auto; }
.wb-focus-pane .wb-stage-canvas { min-height: 0; padding: 0; }
.wb-focus-pane .wb-stage-live, .wb-focus-pane .wb-stage-img { width: 100%; height: 100%; min-height: 0; object-fit: contain; }
.wb-focus-pane.is-fullscreen { position: fixed; inset: 0; z-index: 9500; width: 100dvw; height: 100dvh; min-height: 0; margin: 0; overflow: hidden; border: 0; border-radius: 0; background: var(--bg); box-shadow: none; }
.workbench-stage.has-fullscreen .wb-focus-pane:not(.is-fullscreen) { visibility: hidden; }
.wb-pane-record { width: 100%; height: 100%; min-height: 0; overflow: auto; align-self: stretch; }
.wb-pane-record-table { min-width: 520px; }
.wb-pane-record-table td:last-child { max-width: 28ch; overflow: hidden; text-overflow: ellipsis; }

.workbench-stage[data-layout="grid"] {
  position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--space-3); padding: 0; overflow: visible; border: 0; background: transparent;
  /* 頁首＋標題＋統一單行選擇列約占 325px；保留 5px 安全邊界，
     讓 1600×1000 的四格完整落在第一屏，不把紀錄列偷偷推到視埠外。 */
  height: clamp(520px, calc(100vh - 330px), 760px); min-height: 520px;
}
.wb-grid-tile { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); transition: transform 140ms cubic-bezier(.2,0,0,1), border-color .14s ease, box-shadow .14s ease; }
.wb-grid-tile.is-focused, .wb-grid-empty.is-focused { border-color: color-mix(in srgb, var(--cyan) 72%, var(--border)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 28%, transparent); }
.wb-grid-tile.is-dragging { opacity: .96; border-color: var(--cyan); box-shadow: 0 18px 50px rgba(0,0,0,.44); transition: none; }
.wb-grid-tile.is-shifting, .wb-grid-empty.is-shifting { transition: transform 140ms cubic-bezier(.2,0,0,1); }
.wb-grid-drop-line { position: absolute; z-index: 40; width: 3px; border-radius: 999px; background: var(--cyan); box-shadow: 0 0 14px color-mix(in srgb, var(--cyan) 70%, transparent); pointer-events: none; }
.wb-grid-drop-line.is-horizontal { width: auto; height: 3px; }
.wb-grid-tile .wb-stage-head { cursor: grab; flex-wrap: wrap; gap: 8px; padding: 8px 10px; }
.wb-grid-tile.is-dragging .wb-stage-head { cursor: grabbing; }
.wb-grid-tile .wb-stage-identity { margin-right: auto; }
.wb-grid-tile .bot-avatar-button { width: 32px; min-width: 32px; max-width: 32px; height: 32px; min-height: 32px; max-height: 32px; }
.wb-grid-tile .wb-stage-identity-copy strong { max-width: 12ch; }
.wb-grid-tile .wb-stage-metrics { display: flex; align-items: center; gap: 8px; order: 3; width: 100%; }
.wb-grid-tile .wb-stage-pnl { margin-left: auto; }
.wb-grid-tile .wb-grid-trade { display: flex; align-items: center; gap: 5px; }
.wb-grid-tile .wb-grid-trade .qt-side { min-height: 34px; padding: 0 12px; }
.wb-grid-tile .wb-grid-trade .qt-qty input { width: 40px; }
.wb-grid-tile .wb-stage-canvas { min-height: 0; padding: 0; }
.wb-grid-tile .wb-stage-live, .wb-grid-tile .wb-stage-img { width: 100%; height: 100%; min-height: 0; object-fit: contain; }
.wb-grid-tile.is-fullscreen { position: fixed; inset: 0; z-index: 9500; width: 100dvw; height: 100dvh; min-height: 0; margin: 0; overflow: hidden; border: 0; border-radius: 0; background: var(--bg); box-shadow: none; }
.workbench-stage.has-fullscreen .wb-grid-tile:not(.is-fullscreen) { visibility: hidden; }
.wb-grid-empty {
  display: grid;
  place-items: center;
  min-height: 0;
  padding: 0;
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  color: var(--muted);
}
.wb-grid-empty > .wb-grid-add-mark { display: grid; place-items: center; width: 72px; height: 72px; border: 1px solid var(--border); border-radius: 50%; }
.wb-grid-empty > .wb-grid-add-mark svg { display: block; width: 32px; height: 32px; overflow: visible; fill: none; stroke: currentColor; stroke-width: 1.45; stroke-linecap: round; }
.wb-grid-empty:hover, .wb-grid-empty:focus-visible { border-color: var(--cyan); color: var(--cyan); background: color-mix(in srgb, var(--cyan) 7%, var(--surface)); }
.bot-avatar-dialog { width: min(580px, calc(100vw - 32px)); }
.bot-avatar-crop { width: min(360px, calc(100vw - 80px)); aspect-ratio: 1; margin: 0 auto var(--space-3); overflow: hidden; border-radius: 50%; border: 2px solid var(--cyan); background: #090c13; box-shadow: 0 0 0 8px rgba(25, 221, 255, .06), 0 20px 56px rgba(0, 0, 0, .34); touch-action: none; }
.bot-avatar-crop canvas { display: block; width: 100%; height: 100%; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
.bot-avatar-crop canvas.is-dragging { cursor: grabbing; }
.bot-avatar-crop canvas:focus-visible { outline: 3px solid #fff; outline-offset: -5px; }
.bot-avatar-controls { display: grid; grid-template-columns: 42px minmax(0, 1fr) 42px auto; align-items: center; gap: 8px; }
.bot-avatar-zoom { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--space-3); min-width: 0; }
.bot-avatar-zoom input { width: 100%; }
#botAvatarZoom { appearance: none; -webkit-appearance: none; height: 24px; padding: 0; border: 0; border-radius: 0; background: transparent; --avatar-zoom-fill: 0%; }
#botAvatarZoom::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: linear-gradient(to right, #91d9f6 0 var(--avatar-zoom-fill), #39404d var(--avatar-zoom-fill) 100%); }
#botAvatarZoom::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 20px; height: 20px; margin-top: -7px; border: 2px solid #090c13; border-radius: 50%; background: #91d9f6; }
#botAvatarZoom::-moz-range-track { height: 6px; border-radius: 3px; background: linear-gradient(to right, #91d9f6 0 var(--avatar-zoom-fill), #39404d var(--avatar-zoom-fill) 100%); }
#botAvatarZoom::-moz-range-thumb { width: 16px; height: 16px; border: 2px solid #090c13; border-radius: 50%; background: #91d9f6; }
.bot-avatar-zoom-button { width: 42px; min-width: 42px; height: 42px; min-height: 42px; padding: 0; font-size: 22px; line-height: 1; }

@media (max-width: 640px) {
  .history-management-panel .section-title { flex-wrap: wrap; }
  .history-management-panel .section-title > div:first-child { flex: 1 1 100%; }
  .history-management-panel .section-title p { max-width: none; }
  .bot-head .bot-card-avatar {
    width: 64px;
    min-width: 64px;
    max-width: 64px;
    height: 64px;
    min-height: 64px;
    max-height: 64px;
    flex-basis: 64px;
  }
  .bot-avatar-controls { grid-template-columns: 40px minmax(0, 1fr) 40px; }
  #botAvatarReset { grid-column: 1 / -1; }
}

@media (max-width: 720px) {
  .wb-stage-head { gap: var(--space-2); padding-right: var(--space-2); padding-left: var(--space-2); }
  .wb-stage-resource-tooltip { max-width: min(220px, calc(100vw - 24px)); }
  .workbench-stage[data-layout="grid"] { grid-template-columns: 1fr; grid-template-rows: none; height: auto; min-height: 0; }
  .wb-grid-tile, .wb-grid-empty { min-height: 300px; }
  .workbench-stage[data-layout="split"] { grid-template-columns: 1fr; }
}

/* ── 0.3.60 舊版控制艙（0.3.61 已由檔尾單一規則取代）──────────────────────
   一個左側控制艙承接機器人、畫面工具、買賣口數與損益；右側只留完整券商畫面。
   窗格本身才是真正可用寬度，所以用 container query，不能只看 app viewport。
   2×2 會縮小控制艙，但不把下單列拆到畫面下方，也不生成有大片空白的第三欄。 */
@media not all {
:is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) {
  container-type: inline-size;
}

.wb-stage-rail {
  grid-area: rail;
  z-index: 42;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: auto;
  border-right: 1px solid var(--border);
  background: var(--surface);
}
.wb-stage-rail > .wb-stage-head.wb-stage-head {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  min-width: 0;
  min-height: 0;
  padding: 8px;
  overflow: visible;
  border: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary {
  position: static;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  margin-top: 0;
  padding: 8px;
  gap: 7px;
  overflow: visible;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 72%, var(--surface)), var(--surface));
}
.wb-stage-rail > .wb-trade-summary .wb-grid-trade {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 38px;
  grid-template-areas:
    "buy sell lock"
    "qty qty lock";
  gap: 6px;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .qt-buy { grid-area: buy; }
.wb-stage-rail > .wb-trade-summary .qt-sell { grid-area: sell; }
.wb-stage-rail > .wb-trade-summary .qt-qty { grid-area: qty; }
.wb-stage-rail > .wb-trade-summary .qt-lock { grid-area: lock; width: 38px; min-width: 38px; height: 100%; }
.wb-stage-rail > .wb-trade-summary .wb-grid-trade .qt-side { min-width: 0; min-height: 40px; padding-inline: 6px; }
.wb-stage-rail > .wb-trade-summary .wb-grid-trade .qt-qty { min-width: 0; height: 36px; }
.wb-stage-rail > .wb-trade-summary .wb-grid-trade .qt-qty input { min-width: 32px; width: 100%; }
.wb-stage-rail > .wb-trade-summary .wb-stage-metrics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
  width: 100%;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 7px 9px;
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--surface-2) 88%, var(--surface));
  text-align: left;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric small { font-size: clamp(10px, 4.8cqi, 12px); }
.wb-stage-rail > .wb-trade-summary .wb-stage-metric strong {
  max-width: 100%;
  overflow: hidden;
  font-size: clamp(12px, 6.2cqi, 17px);
  text-align: right;
  text-overflow: ellipsis;
}

@container (min-width: 901px) {
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) {
    display: grid;
    grid-template-columns: clamp(240px, 22cqi, 304px) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "rail notices"
      "rail canvas";
    align-items: stretch;
  }
  .wb-stage-head > .wb-pane-drag-handle { align-self: flex-start; height: 30px; }
  .wb-stage-head > .wb-pane-picker {
    display: grid;
    grid-template-columns: 1fr;
    align-content: start;
    gap: 7px;
    width: 100%;
    min-width: 0;
    height: auto;
    max-height: min(52cqh, 460px);
    overflow: hidden;
    border: 0;
    background: transparent;
  }
  .wb-stage-head .wb-pane-group {
    width: 100%;
    min-width: 0;
    height: 38px;
    border: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
    border-radius: 9px;
    background: var(--surface-2);
  }
  .wb-stage-head .wb-pane-picker > .bot-avatar-button { display: none; }
  .wb-stage-head .wb-pane-bot-picker { width: 100%; min-width: 0; }
  .wb-stage-head .wb-pane-bot-picker > summary { display: none; }
  .wb-stage-head .wb-pane-bot-picker > .workbench-tabs,
  .wb-stage-head .wb-pane-bot-picker:not([open]) > .workbench-tabs {
    position: static;
    display: grid;
    width: 100%;
    max-height: min(44cqh, 360px);
    overflow: auto;
    padding: 4px;
    border-color: var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    box-shadow: none;
  }
  .wb-stage-head .wb-bot-option { min-height: 42px; padding: 5px 7px; }
  .wb-stage-head .wb-bot-picker-row { grid-template-columns: 8px 30px minmax(0, 1fr); gap: 6px; }
  .wb-stage-head .wb-bot-picker-name { font-size: clamp(11px, 7cqi, 13px); }
  .wb-stage-head > .wb-stage-tools {
    display: grid;
    grid-template-columns: repeat(3, minmax(34px, 1fr));
    gap: 5px;
    width: 100%;
    margin-top: 0;
  }
  .wb-stage-head .wb-pane-tabs { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; }
  .wb-stage-head .wb-pane-tabs button,
  .wb-stage-head > .wb-stage-tools > button { width: 100%; min-width: 0; }

  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) > .wb-stage-notices { grid-area: notices; min-width: 0; }
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) > :is(.wb-stage-viewer-layer, .wb-stage-record-layer) {
    grid-area: canvas;
    align-self: stretch;
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
  }
}

/* 左右 1:1 與 2×2：仍維持同一個左側控制艙，只把它收窄。 */
@container (min-width: 521px) and (max-width: 900px) {
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) {
    display: grid;
    grid-template-columns: clamp(176px, 34cqi, 220px) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "rail notices"
      "rail canvas";
    align-items: stretch;
  }
  .wb-stage-head .wb-pane-picker { display: grid; width: 100%; min-width: 0; height: auto; gap: 6px; border: 0; background: transparent; }
  .wb-stage-head .wb-pane-group { width: 100%; min-width: 0; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); }
  .wb-stage-head .wb-pane-picker > .bot-avatar-button { display: none; }
  .wb-stage-head .wb-pane-bot-picker > summary { padding-inline: 7px 22px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); }
  .wb-stage-head .wb-pane-current strong { font-size: clamp(10px, 8cqi, 13px); }
  .wb-stage-head .wb-pane-bot-picker > .workbench-tabs { inset: calc(100% + 5px) auto auto 0; width: min(300px, calc(100vw - 24px)); }
  .wb-stage-head > .wb-stage-tools { display: grid; grid-template-columns: repeat(2, minmax(34px, 1fr)); gap: 5px; margin-top: 0; }
  .wb-stage-head .wb-pane-tabs { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; }
  .wb-stage-head .wb-pane-tabs button,
  .wb-stage-head > .wb-stage-tools > button { width: 100%; min-width: 0; }
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) > .wb-stage-notices { grid-area: notices; min-width: 0; }
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) > :is(.wb-stage-viewer-layer, .wb-stage-record-layer) { grid-area: canvas; width: 100%; height: 100%; min-width: 0; min-height: 0; }
  .wb-stage-rail > .wb-trade-summary { padding: 6px; gap: 5px; }
  .wb-stage-rail > .wb-trade-summary .wb-grid-trade { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 34px; gap: 4px; }
  .wb-stage-rail > .wb-trade-summary .qt-lock { width: 34px; min-width: 34px; }
  .wb-stage-rail > .wb-trade-summary .wb-stage-metric { padding: 5px 7px; }
}

/* 手機：把同一個控制艙置頂；內容仍是一塊，不再拆成前後兩套操作列。 */
@container (max-width: 520px) {
  :is(.workbench-stage[data-layout="single"], .wb-focus-pane, .wb-grid-tile) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(280px, 1fr);
    grid-template-areas: "rail" "notices" "canvas";
  }
  .wb-stage-rail {
    overflow: visible;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .wb-stage-rail > .wb-stage-head.wb-stage-head {
    display: grid;
    flex: 0 0 auto;
    grid-template-columns: 28px minmax(0, 1fr);
    overflow: visible;
  }
  .wb-stage-head > .wb-stage-tools { grid-column: 1 / -1; grid-template-columns: repeat(3, minmax(34px, 1fr)); }
  .wb-stage-head .wb-pane-tabs { grid-column: 1 / -1; }
  .wb-stage-rail > .wb-trade-summary { margin-top: 0; }
}
}

.workbench-log { flex: 0 1 36%; min-height: 160px; overflow: auto; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); }
.workbench-table { width: 100%; border-collapse: collapse; font-size: 14px; font-variant-numeric: tabular-nums; }
.workbench-table th, .workbench-table td { padding: 6px var(--space-3); text-align: left; white-space: nowrap; }
.workbench-table thead th { position: sticky; top: 0; background: var(--surface-2); color: var(--muted); font-weight: 500; z-index: 1; }
.workbench-table tbody tr:nth-child(even) { background: rgba(255, 255, 255, .02); }
.workbench-table td.empty { text-align: center; color: var(--muted); padding: var(--space-5); }

/* ── 紀錄工具列（2026-08-18：「交易紀錄」分頁併進內部瀏覽後的動作＋篩選列）──────
   ⛔ 不塞進 .workbench-bar：那條已經有分組選單＋機器人頁籤＋買賣鍵，站長明講太擠。
   ⚠ 尺寸對齊**這個面板自己的**刻度（.workbench-group-picker select 是 40px），⛔ 不用
      全域的 56px／18px —— 那是給總覽那種一頁一件事的版面用的，貼在表格上方會壓垮表。
   ⚠ 最小字級 14px（--text-sm）：2026-08-18 上午才把全 app 的 9px 拉到 12px，⛔ 別倒退。
   ⚠ 間距全走 8px 網格的 --space-* token，⛔ 不寫裸數字。 */
.record-bar {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.record-bar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}
/* ⛔ 明寫字級：它不在 .section-title 裡，拿不到那層的 30px，也不該拿 —— 這是表格的
   標題不是分頁的標題，比舞台上方那排小一階才讀得出從屬關係。 */
.record-bar-title {
  margin: 0;
  color: var(--text);
  font-size: var(--text-xl);
  font-weight: 650;
  line-height: 1.2;
  letter-spacing: .01em;
}
.record-bar-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* ── 操作紀錄 ⇄ 交易紀錄 的左右切換（站長 2026-08-26）────────────────────────
   逐字：「將他們做成 左右切換的那種方式 如機器人內建瀏覽畫面」。
   ⇒ 沿用 .wb-tab 的視覺（就是他指的那一種），這裡只補容器的排列與間距，
     ⛔ 不複製一份 .wb-tab 的顏色／圓角 —— 那會在下一次改主題時分岔。
   ⛔ 這一排取代了原本的 <h2>成交明細</h2>，所以它要吃掉標題原本的垂直節奏，
      否則工具列會比表格上緣矮一截。 */
.record-tabs { display: inline-flex; align-items: center; gap: 2px; flex-wrap: nowrap; padding: 3px; border: 1px solid var(--border); border-radius: 11px; background: var(--surface-2); }
.record-tabs .record-tab { min-height: 34px; padding: 0 var(--space-3); border: 0; border-radius: 8px; white-space: nowrap; }

/* 操作紀錄的「結果」欄：失敗才上色。⛔ 成功不上色 —— 一整欄都是綠字等於沒有訊號，
   而使用者掃這一欄要找的正是那少數幾筆失敗。 */
.operation-table .record-failed { color: var(--danger, #f87171); font-weight: 600; }
.record-bar-actions button, .record-bar-actions .button {
  min-height: 40px;
  padding: 0 var(--space-4);
  font-size: var(--text-sm);
}
/* 三欄：方向／觸發窄，搜尋吃剩下的。⛔ 用 minmax 不用固定 px —— 視窗一窄固定值會
   把搜尋框擠成負寬度，然後整個 body 出現水平捲軸。 */
.record-bar-filters {
  display: grid;
  grid-template-columns: minmax(150px, 190px) minmax(150px, 210px) minmax(180px, 1fr);
  gap: var(--space-2);
}
.record-bar-filters.is-operation { grid-template-columns: minmax(150px, 210px) minmax(0, 1fr); }
.record-bar-filters select, .record-bar-filters input {
  width: 100%;
  min-height: 40px;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
}
@media (max-width: 900px) {
  .record-bar-filters:not(.is-operation) { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .record-bar-filters.is-operation { grid-template-columns: minmax(0, 1fr); }
}

/* ── 交易紀錄分頁列 ────────────────────────────────────────────────────────
   ⚠ 跟 .record-bar 同一套刻度：8px 網格的 --space-* token、最小字級 14px
      (--text-sm)、外框與底色沿用同一組，⛔ 不寫裸數字也不自創顏色。
   ⚠ 唯一的強調是「第 N／M 頁」那一格（--text 亮色）；按鈕一律 .secondary。
   ⛔ flex-wrap 必開：視窗一窄，三組東西擠不下時要換行，⛔ 不是讓 body 出現水平捲軸。 */
.record-pager {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--muted);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
/* 一筆紀錄都沒有時 renderHistoryPager 寫入空字串 ⇒ 整條收起來，不留一排空框。 */
.record-pager:empty { display: none; }
.record-pager-range { grid-column: 1; }
.record-pager-nav { grid-column: 2; display: flex; align-items: center; justify-content: center; gap: var(--space-1); }
.record-pager-size { grid-column: 3; justify-self: end; }
/* ⛔ 覆寫全域 button 的 48px：這排比 .record-bar-actions 的 40px 再小一階，
   讀得出「它是表格的附屬控制項」而不是又一組主要動作。32 = 8×4，仍在網格上。 */
.record-pager-nav button {
  min-height: 32px;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
}
.record-pager-nav button[disabled] { opacity: .45; cursor: default; }
.record-pager-page { padding: 0 var(--space-2); color: var(--text); font-weight: 600; }
.record-pager-size { display: flex; align-items: center; gap: var(--space-2); }
.record-pager-size select {
  min-height: 32px;
  padding: 0 var(--space-2);
  font-size: var(--text-sm);
}
@media (max-width: 700px) {
  .record-pager { grid-template-columns: minmax(0, 1fr) auto; }
  .record-pager-range { grid-column: 1; grid-row: 1; }
  .record-pager-nav { grid-column: 1 / -1; grid-row: 2; justify-self: center; }
  .record-pager-size { grid-column: 2; grid-row: 1; }
}

/* 頁籤列最前面的「全部」：它不是一台機器人，所以跟後面那排之間要有一道分隔，
   ⛔ 但不能用 border（.wb-tab 的 1px transparent border 是它對齊 .active 的基準，
   加一邊實線會讓這一格比鄰居高／寬一點點）。用絕對定位的 ::after 畫線。 */
.wb-tab-all { position: relative; margin-right: var(--space-3); flex-shrink: 0; }
.wb-tab-all::after {
  content: '';
  position: absolute;
  top: 20%;
  right: -6px;
  width: 1px;
  height: 60%;
  background: var(--border);
}
.wb-tab-count { font-size: 14px; font-variant-numeric: tabular-nums; color: var(--muted); }

/* 全部態＝純紀錄視圖：舞台與機器人操作鍵收起來，表格吃掉整個高度。
   ⚠ 特異性 (0,3,0) 要贏 .workbench-stage(0,1,0) 與 .workbench-log(0,1,0)。 */
.workbench-panel[data-scope="all"] .workbench-stage { display: none; }
.workbench-panel[data-scope="all"] .workbench-bar-actions { display: none; }
.workbench-panel[data-scope="all"] .workbench-log { flex: 1 1 auto; }
.workbench-panel[data-scope="all"] {
  overflow: visible;
}

/* 分組與機器人下拉共用 details／workbench-tabs 的主題框、陰影與選項語彙。
   分組不再交給 Windows 原生 select 畫出另一種白底選單。 */
.wb-stage-head .wb-pane-group-picker { position: relative; width: 100%; min-width: 0; }
.wb-stage-head .wb-pane-group-picker > summary {
  display: flex;
  align-items: center;
  width: 100%;
  min-width: 0;
  height: 42px;
  min-height: 42px;
  padding: 2px 28px 2px 9px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--cyan) 28%, var(--border));
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
}
.wb-pane-group-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; }
.wb-stage-head .wb-pane-group-picker > .workbench-tabs {
  inset: auto;
  display: grid;
  position: fixed;
  z-index: 20030;
  width: min(300px, calc(100vw - 24px));
  max-height: min(52vh, 420px);
  overflow: auto;
  padding: 5px;
}
.wb-pane-group-options .wb-bot-option { display: flex; align-items: center; min-height: 38px; width: 100%; padding: 7px 10px; text-align: left; }
.wb-pane-group-options .wb-bot-option.active { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 13%, var(--surface-2)); }
/* 單機器人、全部紀錄與內建畫面共用同一個文件捲軸。完整紀錄表可能超過視窗；
   這裡明確保留垂直捲動，避免多窗格的一屏 overflow 規則外溢到單格紀錄。 */
body[data-active-panel="internal-browse"][data-workbench-layout="single"] {
  overflow-y: auto;
}
/* 單一機器人的窗格只提供最近紀錄摘要；下方完整紀錄表必須保留搜尋、分頁與每頁筆數。
   以前把 record-bar/workbench-log/record-pager 全藏掉，窗格又硬切最近 7／14 筆，
   造成較早成交仍在帳本中卻沒有任何 UI 路徑可以看到。摘要與完整帳本用途不同，兩者都保留。 */

/* ── 交易紀錄頁：內建瀏覽＋下單佔滿一屏，紀錄往下捲（站長 2026-08-20 交辦）────────
   站長原話：「交易紀錄頁直接呈現內建瀏覽+下單操作佔滿畫面（紀錄往下滑）」。

   ⛔ 舊寫法 `.workbench-stage { flex: 1 1 64%; min-height: 300px }` 做不到，而且**壞得很安靜**：
      `flex-basis: 64%` 要有「確定的父層高度」才解析得出來，而 .workbench-panel 沒有高度
      （body 只有 min-height:100vh，整頁是文件流捲動）⇒ 64% 解析成 auto
      ⇒ 舞台實際只吃到 min-height 的 **300px**。
   ⚠ 這就是為什麼「看起來像設定過比例、實際上完全沒有生效」—— 兩條規則都在，
      瀏覽器只用得到其中一條，而畫面上看不出任何錯誤。

   改法＝給舞台**視埠相對**的確定高度（⛔ 不再依賴解析不出來的百分比）：
     78vh + 上方 chrome（頂欄＋分頁標題＋工作台工具列＋main 上留白，1080p 約 16vh）
     ≈ 94vh ⇒ 舞台盡量吃滿一屏，紀錄自然被推到下面。
   ⚠ min-height 420px 是給「視窗被拉到最小 620px 高」那種情況的地板。

   ⛔ .workbench-log 的 overflow 從 auto 改成 visible ＝ 讓表格長出來、由**頁面**捲，
      ⛔ 不是在表格內部再開一個小捲軸（那正是站長說的「沒佔滿」的另一半：
      畫面被切成上下兩個各自捲動的小框）。
   ⚠ [data-scope="all"]（純紀錄視圖）那三條是 (0,3,0)，仍然贏這裡的 (0,1,0) ——
      舞台照樣收起來、表格照樣吃滿，⛔ 本段不影響它。 */
/* 內建瀏覽：舞台與紀錄同寬；畫布鎖 3:2 由寬推高，紀錄文件流緊貼下方。
   ⛔ 不可再用 height: calc(100vh - chrome) —— 寬 ~1496 時 3:2 要 ~997 高，
      鎖 960 就把 Tradovate 底部時間軸裁掉。
   ⭐ 高度跟寬走。預設視窗 1360×1200＝從 1520×1340 等比例縮小，上下 padding
      留給呼吸感（站長 08-26：「整體視窗太大了 上下方有空間」）。 */
.panel.workbench-panel.active {
  --qw-browse-chrome: 292px;
  /* 紀錄頁的標題與版面切換已合成一條工具列；不再套全站 48px 標題前留白。 */
  padding-top: 0;
}
body[data-active-panel="internal-browse"] main {
  padding: 20px 16px 28px;
  max-width: none;
}
body[data-qw-window="maximized"] main {
  padding: 4px 4px 8px;
  max-width: none;
}
body[data-qw-window="maximized"] .panel.workbench-panel.active {
  --qw-browse-chrome: 200px;
}
body[data-qw-window="maximized"] .workbench-log,
body[data-qw-window="maximized"] .record-bar,
body[data-qw-window="maximized"] .record-pager {
  max-width: none;
}
#internal-browse.panel.active .section-title.panel-head {
  margin-bottom: 8px;
}
#internal-browse.panel.active .section-title.panel-head p {
  display: none;
}
#internal-browse.panel.active .section-title.panel-head h1 {
  margin: 0;
  font-size: 24px;
  line-height: 1.2;
}
.workbench-stage {
  flex: 0 0 auto;
  width: 100%;
  height: auto;
  min-height: 0;
  max-height: none;
  margin-inline: 0;
  margin-block: 8px 16px;
}
.workbench-stage:not(:has(.wb-stage-live)) {
  min-height: 300px;
}

/* 即時推送斷線橫幅。⛔ 常駐不是 toast —— 這是狀態不是事件。
   ⚠ 用 sticky 不用 fixed：fixed 會蓋住捲動中的內容，sticky 只在頂端佔一條。 */
#streamHealthBanner {
  position: sticky;
  top: 0;
  z-index: 60;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  text-align: center;
  color: #2b1500;
  background: linear-gradient(180deg, #ffcf70 0%, #ffb648 100%);
  border-bottom: 1px solid rgba(0, 0, 0, .25);
}
.workbench-log { flex: 0 0 auto; overflow: visible; }

/* ── 方向欄（買／賣）─────────────────────────────────────────────────────
   交易紀錄與內建瀏覽共用。買賣是掃這張表時第一個要找的東西，所以給它顏色和
   一個框，讓一列是進場還是出場不必逐字讀。
   ⛔ 沿用既有的 --green／--red（就是 .positive／.negative 和下單按鈕在用的那
   兩個），不另立一套買賣配色 —— 同一個系統裡的綠色必須都是同一個綠色。
   ⚠ 顏色不是唯一訊號：字本身就寫著「買進」「賣出」，色盲或單色列印都讀得到。 */
.account-restriction { min-width: 0; padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-md); }
.account-restriction p { margin: 8px 0; overflow-wrap: anywhere; font-size: 13px; }
.account-restriction summary { cursor: pointer; font-weight: 600; }
.wb-stage-problem-strip.is-account-restriction { display: flex; flex-wrap: nowrap; min-width: 0; }
.wb-stage-problem-strip.is-account-restriction > strong { flex: 0 0 auto; white-space: nowrap; }
.wb-stage-problem-strip.is-account-restriction > span { display: block; flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.account-restriction label, .account-restriction select { display: block; width: 100%; min-width: 0; }
.account-restriction-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.account-restriction-actions button { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
.side-cell { white-space: nowrap; }
/* ⚠ text-align 是 **left** 不是 center（2026-08-18）：整張紀錄表統一走業界慣例
   ——文字欄左、數值欄右、表頭跟著它那一欄走，⛔ 沒有任何一處置中。
   min-width 留著是為了讓買/賣兩顆膠囊等寬（欄看起來才整齊），但字一律靠左起。
   ⚠ 膠囊的**字**會比表頭的字右 13px（＝下面的 padding 12px ＋ border 1px）——
      那是 badge 本來就有的內距，貼齊儲存格左緣的是膠囊的**框**（實測 0px），
      ⛔ 不是對齊沒做好。要連字都對齊得給負 margin 把膠囊拉出儲存格內距，
      那會讓它貼死在表格框線上，不划算。 */
.side-tag {
  display: inline-block; min-width: 4em; padding: 1px 12px;
  border: 1px solid transparent; border-radius: 999px;
  font-size: var(--text-sm); font-weight: 600; text-align: left; letter-spacing: .02em;
}
.side-tag.side-buy { color: var(--green); border-color: rgba(72, 213, 151, .45); background: rgba(72, 213, 151, .12); }
.side-tag.side-sell { color: var(--red); border-color: rgba(255, 98, 121, .42); background: rgba(255, 98, 121, .12); }
/* 平倉：方向照樣顯示（平一口多單送出去的是賣單，那是事實），但要看得出它是
   出場不是新開一口 —— 這也是為什麼 side 和 intent 是兩個欄位。 */
.side-note { margin-left: 8px; font-size: 14px; color: var(--muted); }
/* 沒有方向的列：生命週期事件（啟動／截圖）本來就沒有方向，舊紀錄則是在這個
   欄位出生前寫下的。⛔ 不猜、不回填 —— 空格是對「不知道」的誠實陳述。 */
.side-none { color: var(--muted); }

.wb-menu { position: fixed; z-index: 90; min-width: 144px; display: flex; flex-direction: column; padding: var(--space-1); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: 0 18px 40px rgba(0, 0, 0, .5); }
.wb-menu button { all: unset; box-sizing: border-box; width: 100%; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); font-size: var(--text-sm); color: var(--text); cursor: pointer; }
.wb-menu button:hover { background: rgba(53, 164, 255, .16); }
.wb-menu button:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }
.wb-menu button:disabled { cursor: not-allowed; opacity: .42; background: transparent; }
.wb-menu .wb-menu-radio.checked::after { content: "✓"; float: right; color: var(--blue); }
.wb-menu .wb-menu-danger { color: var(--red); }
.wb-menu-sep { height: 1px; margin: var(--space-1) 0; background: var(--border); }
.wb-menu-label { padding: var(--space-1) var(--space-3); font-size: 14px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
/* 錨點（卡片上的 ⋯ 按鈕）被捲出可視範圍時整個藏起來。⛔ 用 visibility 不用 display：
   display:none 會讓 offsetWidth 歸零，下次算位置時寬度取到 0 而貼錯邊。 */
.wb-menu-detached { visibility: hidden; pointer-events: none; }
.wb-submenu-host { position: relative; display: flex; flex-direction: column; }
.wb-menu .wb-submenu-trigger { display: flex; align-items: center; justify-content: flex-start; text-align: left; gap: var(--space-2); }
.wb-menu .wb-submenu-caret { margin-left: auto; color: var(--muted); font-size: var(--text-sm); }
/* 子選單貼在父選單右側。⚠ 這裡刻意不再開一個 fixed 浮層 —— 它跟著父選單一起
   被 trackAnchoredMenu 移動，所以不需要自己一份跟隨邏輯。 */
/* ⚠ 子選單要放得下一個能打字的輸入框 —— 200px 扣掉內距後只剩不到 180px，中文分組
   名稱打三四個字就看不到前面。240px 是「不擋住父選單」與「打得了字」的折衷。 */
.wb-submenu { position: absolute; left: 100%; top: 0; margin-left: 4px; min-width: 240px; max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; padding: var(--space-1); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: 0 18px 40px rgba(0, 0, 0, .5); z-index: 1; }
.wb-submenu[hidden] { display: none; }
.wb-submenu-flip { left: auto; right: 100%; margin-left: 0; margin-right: 4px; }
.wb-menu .wb-submenu-new { color: var(--blue); }
/* ⛔ min-width:0 不能省：flex item 預設的最小寬度是「內容本身的寬度」（CSS 規格的
   intrinsic minimum size，不是 bug）⇒ 輸入框會把子選單撐開、跑出水平捲軸，而輸入框
   自己被擠到幾乎看不見（站長 2026-08-18 截圖）。子選單是 flex column，所以這一列與
   裡面的 input 都要解除。 */
.wb-submenu-input { min-width: 0; padding: var(--space-1) var(--space-2); }
.wb-menu .wb-submenu-input input { width: 100%; min-width: 0; box-sizing: border-box; padding: var(--space-2) var(--space-3); font-size: var(--text-sm); color: var(--text); background: var(--surface-1); border: 1px solid var(--blue); border-radius: var(--radius-sm); }

.bot-more { min-width: 40px; }
.bot-cloud { margin: 0; font-size: 14px; }
.startup-visual-status { display: flex; align-items: center; gap: 12px; margin: 12px 0 4px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-md); background: rgba(10, 18, 34, .72); }
.startup-visual-status > span { width: 9px; height: 9px; flex: 0 0 9px; border-radius: 50%; }
.startup-visual-status.ready > span { background: var(--green); box-shadow: 0 0 12px rgba(114, 242, 195, .58); }
.startup-visual-status.missing > span { background: var(--amber); box-shadow: 0 0 12px rgba(255, 202, 101, .48); }
.startup-visual-status div { min-width: 0; }
.startup-visual-status strong, .startup-visual-status small { display: block; }
.startup-visual-status strong { color: var(--text); font-size: var(--text-sm); }
.startup-visual-status small { margin-top: 3px; color: var(--muted); font-size: 14px; }

.ticket-dialog { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); color: var(--text); padding: 0; }
.ticket-form { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-5); min-width: 320px; }
.ticket-form h3 { margin: 0; font-size: var(--text-xl); }
.ticket-target { display: flex; flex-direction: column; gap: 2px; margin: 0; }
.ticket-field { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); font-size: var(--text-sm); }
.ticket-field input, .ticket-field select { flex: 0 0 150px; }
.ticket-type-value {
  flex: 0 0 150px;
  box-sizing: border-box;
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  padding: 0 16px;
  border: 1px solid rgba(141, 165, 205, .24);
  border-radius: 10px;
  color: #dbe8f8;
  background: rgba(17, 26, 52, .72);
  font-weight: 700;
}
.ticket-note { margin: 0; font-size: 14px; }
.ticket-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }
.ticket-actions .trade-buy,
.ticket-actions .trade-sell { min-width: 148px; min-height: 56px; font-size: 18px; }

/* Trading convention: buy is green and sell is red. Text remains present, so
   colour is reinforcement rather than the only way to identify the action. */
.trade-buy,
.trade-sell {
  min-width: 104px;
  color: #fff;
  border-width: 1px;
  border-style: solid;
  box-shadow: inset 0 1px rgba(255, 255, 255, .18), 0 8px 20px rgba(0, 0, 0, .22);
  transition: transform .14s ease, filter .14s ease, box-shadow .14s ease;
}
.trade-buy {
  border-color: #55dda6;
  background-color: #087448;
  background-image: linear-gradient(135deg, #159564, #087448);
}
.trade-sell {
  border-color: #ff7188;
  background-color: #9f2945;
  background-image: linear-gradient(135deg, #cf4864, #9f2945);
}
.trade-buy:hover:not(:disabled),
.trade-sell:hover:not(:disabled) {
  filter: brightness(1.12) saturate(1.08);
  transform: translateY(-1px);
}
.trade-buy:focus-visible,
.trade-sell:focus-visible {
  outline: 3px solid #70d7ff;
  outline-offset: 3px;
}
.trade-buy:disabled,
.trade-sell:disabled {
  cursor: not-allowed;
  opacity: .48;
  filter: grayscale(.35);
  box-shadow: none;
  transform: none;
}

@media (max-width: 768px) {
  .workbench-bar { align-items: stretch; flex-wrap: wrap; }
  .workbench-picker-stack { flex: 1 1 100%; width: 100%; min-width: 0; }
  .workbench-tabs { width: 100%; }
  .workbench-bar-actions { width: 100%; flex-wrap: wrap; }
  /* 固定欄寬的紀錄表保留可讀寬度，但捲動只發生在表框內，不把整個 app 撐寬。 */
  .workbench-log { width: 100%; max-width: 100%; overflow-x: auto; overflow-y: visible; }
  /* 兩顆交易鍵包了一層「機器人操作」群組後，要讓群組先撐開，裡面那排才長得回來。
     少了這行，窄畫面上兩顆鍵會縮回 112px 的最小寬度、擠在右邊。 */
  .workbench-robot-trade { flex: 1 1 auto; min-width: 0; }
  .wb-trade-row { width: 100%; }
  .workbench-trade { flex: 1 1 0; min-width: 0; }
}

/* 0.3.35 設定 → 介面（語言）與關於區塊 */
.interface-card .language-note { margin: var(--space-2) 0 0; }
.about-card .product-facts + .actions { margin-top: var(--space-3); }

/* 0.3.32 live view: MJPEG from the bot's own Chrome fills the stage.
   畫布 width:100% + aspect-ratio:16/9 + height:auto：子層百分比高度要父層有確定高，
   所以 live 用 absolute inset 0（業界影片 16:9 盒的寫法）。 */
.wb-stage-canvas:has(.wb-stage-live) {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  padding: 0;
  background: #000;
}
.wb-stage-live {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: #000;
  box-sizing: border-box;
  padding: 0;
}
/* 畫布鎖 16:9、遠端也是 16:9：contain＝填滿且不裁底。比例萬一漂移只會出黑邊，
   ⛔ 不再用 fill 把扁盒子裡的底部時間軸壓沒。 */
.wb-stage-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}
.wb-stage-live [hidden] { display: none !important; }
.brand-loading-state { position: absolute; inset: 0; z-index: 2; display: none; place-items: center; align-content: center; gap: 16px; color: #c7d9ed; background: radial-gradient(circle at 50% 42%, #173458 0%, #0b1c35 48%, #071427 100%); }
.brand-loading-state .brand-loader-logo { width: 72px; height: 84px; }
.wb-stage-live.is-loading .brand-loading-state { display: grid; }
.wb-stage-live.is-loading .wb-stage-img { opacity: 0; }
.wb-stage-live .wb-stage-state { position: absolute; inset: 0; z-index: 3; display: grid; place-items: center; align-content: center; background: var(--surface); }
.wb-stage-live.has-frame.is-reconnecting .wb-stage-img { opacity: .78; }
.wb-stage-live.has-frame.is-reconnecting .wb-stage-state {
  inset: auto 18px 18px;
  width: min(460px, calc(100% - 36px));
  min-height: 0;
  padding: 16px 24px;
  border: 1px solid rgba(255, 98, 121, .55);
  border-radius: var(--radius-md);
  background: rgba(23, 10, 20, .92);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .42);
}
.wb-stage-live.has-frame.is-reconnecting .wb-stage-state strong { color: var(--red); font-size: var(--text-base); }
/* ⛔ 這裡曾經寫死 `cursor: crosshair`，於是整張遠端畫面 —— 工具列、下拉選單、
   下單按鈕、表單欄位，每一個像素 —— 在本地都變成十字游標。十字只有在圖表畫布
   上才是對的，而圖表只佔畫面的一部分，所以那個寫法對「大多數」區域都是錯的。

   ⚠ 本地無從得知遠端那一點底下是什麼元素：這是一張 MJPEG 影格，不是 DOM。
   要真的做到「圖表內十字、其他地方各歸各的」，唯一的來源是遠端頁面自己的
   getComputedStyle(...).cursor，得由截圖串流那端隨影格回傳（後端的事）。

   在那之前，`default` 是誠實的預設：TradingView／Tradovate 的十字準線是遠端
   *畫進畫面裡* 的線，會跟著影格一起送回來，所以圖表區的十字視覺不依賴這個
   CSS 屬性；而選單與按鈕區則終於拿回它們本來就該有的箭頭。 */
.wb-stage-img { cursor: default; }
.wb-stage-img:focus { outline: 2px solid var(--blue); outline-offset: -2px; }

/* ── 內建畫面唯讀開關（使用者自己按，預設關閉）────────────────────────────
   後端的唯讀是「點了沒反應」，畫面本身一個像素都不會變 —— 所以這裡的視覺
   是承重的，不是裝飾：沒有它，操作者只會以為程式當掉。故兩態各給三個訊號
   （文字／圓點顏色／整顆按鈕的底色與邊框），再加畫面上一條常駐標示。
   ⛔ 唯讀只擋人；機器人自己的下單不經過這條路徑。 */
.workbench-viewer-mode { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 52px; white-space: nowrap; }
.viewer-mode-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--green); box-shadow: 0 0 0 3px rgba(72, 213, 151, .18); }
.workbench-viewer-mode.is-read-only { border-color: var(--amber); color: var(--amber); background: rgba(242, 184, 75, .16); font-weight: 600; }
.workbench-viewer-mode.is-read-only .viewer-mode-dot { background: var(--amber); box-shadow: 0 0 0 3px rgba(242, 184, 75, .22); }
.workbench-viewer-mode[disabled] .viewer-mode-dot { background: var(--muted); box-shadow: none; }

/* 唯讀時整個畫面套一圈琥珀色內框，游標也換掉 —— 在點下去之前就看得出來。 */
.wb-stage-live.is-read-only::after {
  content: ''; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  border: 2px solid rgba(242, 184, 75, .62); border-radius: 2px;
}
.wb-stage-live.is-read-only .wb-stage-img { cursor: not-allowed; }
/* 整條橫幅（跟同一格上方的 .bot-reconciling-warning 同一種），⛔ 不做成蓋在畫面
   上的浮層：實測頂端置中會蓋掉 Tradovate 的淨值／保證金那一列，貼底部又會被捲到
   摺線以下。橫幅排在畫面之上、永遠在視野裡，而且一個 Tradovate 像素都不擋。 */
.wb-stage-readonly {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  margin: 0 var(--space-3) var(--space-2); padding: 12px 16px;
  border: 1px solid rgba(242, 184, 75, .5); border-radius: 11px;
  background: linear-gradient(90deg, rgba(94, 66, 16, .34), rgba(44, 33, 12, .2));
  color: #d9b97f; font-size: 14px; line-height: 1.45;
}
.wb-stage-readonly[hidden] { display: none; }
.wb-stage-readonly strong { color: #ffe5b8; font-weight: 600; }
.wb-readonly-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--amber); box-shadow: 0 0 0 3px rgba(242, 184, 75, .22); }

/* 0.3.41 VIS-01 ⛔ 不要把 .stopped 再塗回紅色 —— 這是刻意的，不是漏改。
   0.3.40 的理由（stopped/disconnected 是「連線不可用」不是中性裝飾）只對了一半：
   它把 stopped 塗成 #ff9daf，而 .badge.error（styles.css:79）用的就是同一個 #ff9daf
   ⇒ 兩態前景色 ΔE2000 = 0.00（同一個顏色），顏色通道對這兩態的鑑別力等於零。
   而「我按了停止」（不用動作）與「它自己壞了」（要立刻處理）在自營交易情境下
   是完全相反的資訊 —— 兩者的 class 來源也不同：
     .stopped  ← botVisualStatus() = bot.status，是使用者自己按停的（app.js:1596/1634）
     .error / .disconnected / .closed ← connectionStatus，是非我意願的失敗
   ⇒ 紅色**只留給非自願的失敗態**；自願停止一律走中性藍灰。
   ⚠ 選色不是隨手挑的：舊的中性灰 #b5c5d7 / #8ba2b2 在**紅色盲（protanopia）**模擬下
   與 #ff9daf 只差 ΔE 9.4（幾乎又黏回去）；現用的 #aeb8e8 偏藍，同條件下 ΔE 16.1。
   改色前請用 CIEDE2000 + 色覺缺陷模擬量過，⛔ 別靠肉眼「看起來不一樣」。 */
.badge.stopped { color: #aeb8e8; background: rgba(40, 52, 74, .78); }
.wb-dot.stopped { background: #8f9cd0; box-shadow: 0 0 0 3px rgba(143, 156, 208, .16); }
.connection-line.disconnected,
.connection-line.closed {
  color: #ff9daf;
  border: 1px solid rgba(255, 112, 142, .48);
  border-left: 3px solid var(--red);
  background: rgba(72, 20, 39, .28);
}
.connection-line.disconnected .connection-orb,
.connection-line.closed .connection-orb { background: var(--red); box-shadow: 0 0 12px #ff708e88; }
.connection-line.disconnected strong,
.connection-line.closed strong { color: #ffb2c1; }
/* ⚠ 順序承重：機器人停掉時，app.js:1596 會同時給出 connectionStatus（closed/
   disconnected）與 ' stopped' 兩個 class，兩者特異性都是 (0,2,0) ⇒ 誰在後面誰贏。
   ⛔ 不要把這一組移到上面那組之前，否則「使用者自己按停」又會被畫成紅色錯誤。 */
.connection-line.stopped {
  color: #aeb8e8;
  border: 1px solid rgba(150, 165, 215, .34);
  border-left: 3px solid #8f9cd0;
  background: rgba(34, 44, 66, .30);
}
.connection-line.stopped .connection-orb { background: #8f9cd0; box-shadow: 0 0 12px #8f9cd088; }
.connection-line.stopped strong { color: #ccd4ee; }

/* An order click with an unconfirmed broker result is a safety exception, not
   "running" or "stopped". Keep diagnosis visible while making the lock clear
   in text and colour. */
.badge.reconciling {
  color: #ffd38a;
  border-color: rgba(255, 184, 77, .58);
  background: rgba(91, 48, 15, .78);
}
.wb-dot.reconciling {
  background: var(--amber);
  box-shadow: 0 0 0 3px rgba(255, 184, 77, .18), 0 0 12px rgba(255, 184, 77, .5);
}
.connection-line.reconciling {
  color: #ffd38a;
  border: 1px solid rgba(255, 184, 77, .5);
  border-left: 3px solid var(--amber);
  background: rgba(91, 48, 15, .3);
}
.connection-line.reconciling .connection-orb {
  background: var(--amber);
  box-shadow: 0 0 12px rgba(255, 184, 77, .78);
}
.connection-line.reconciling strong { color: #ffe0a8; }
/* ⛔ 2026-09-17：這張卡原本是三行直排（標題／說明／按鈕）＋16px 內距，實測 162.6px，
   而它所在的 notices 格上限是 128px ⇒ 按鈕整顆在裁切線外，使用者按不到。
   站長三條要求要同時成立：①警示一定要出現 ②⛔不能擋住券商畫面 ③確認鍵要按得到。
   ⇒ 改成「左邊文字、右邊按鈕」的單條橫幅：高度 162.6 → 50.1px，notices 反而從 64px
      降到 62.1px，canvas（券商畫面）**變大**而不是變小。 */
.bot-reconciling-warning {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "title  inspect confirm"
                       "detail inspect confirm";
  align-items: center;
  column-gap: 10px;
  row-gap: 1px;
  margin: 6px 8px;
  padding: 6px 10px;
  border: 1px solid rgba(255, 184, 77, .46);
  border-radius: 11px;
  color: #ffd38a;
  background: rgba(91, 48, 15, .32);
  font-size: 13px;
  line-height: 1.35;
}
.bot-reconciling-warning > strong { grid-area: title; color: #ffe5b8; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wb-stage-notices .bot-reconciling-warning > strong {
  white-space: normal;
  overflow-wrap: anywhere;
  overflow: visible;
  text-overflow: clip;
}
.bot-reconciling-warning > span { grid-area: detail; color: #d9b97f; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⛔ 全域 button 是 min-height:52px。不覆蓋它，橫幅就矮不下來。
   這條選擇器 (0,1,1) 贏過全域的 (0,0,1)，⛔ 不需要 !important。 */
.bot-reconciling-warning > button {
  align-self: center;
  min-height: 34px;
  padding: 0 12px;
  font-size: 13px;
  white-space: nowrap;
}
/* 唯讀橫幅一起縮：否則「待確認 ＋ 唯讀」同時出現會頂到 128px 上限而冒出捲軸。 */
.wb-stage-readonly { margin: 0 8px 6px; padding: 6px 10px; font-size: 13px; line-height: 1.35; }
/* ⭐ 620px 以下改直排、按鈕撐滿整列。
   ⚠ 斷點刻意訂在 620 而不是 420：站長的 2×2 窗格實測 594px，在橫排下說明文字只顯示
   84%（英文 41%），被省略號吃掉的正好是「畫面仍可操作、未知訂單須先核對」的關鍵說明 ——
   ⛔ 那半句是這張卡存在的理由，不能省。直排後 notices 約 105px，仍在 128 上限內。 */
@container (max-width: 620px) {
  .bot-reconciling-warning {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "title" "detail" "inspect" "confirm";
    row-gap: 5px;
  }
  .bot-reconciling-warning > span { white-space: normal; }
  .bot-reconciling-warning > button { justify-self: stretch; }
  .wb-stream-notice { flex-wrap: wrap; }
}
.wb-menu-warning {
  display: block;
  max-width: 260px;
  padding: 12px 12px;
  color: #ffd38a;
  font-size: 14px;
  line-height: 1.35;
  white-space: normal;
}

/* 0.3.38 更新確認框 —— 版面沿用 .brand-dialog，警告塊沿用既有 .notice（它已在
   每個主題區塊各自重定義過 --amber 與底色，所以自動跟著主題走）。這裡只補
   dialog 內的留白，⛔ 不重畫一套警告樣式。 */
.brand-dialog .update-dialog-warning { margin: 0 24px 4px; }
.brand-dialog #updateDialogMessage { color: var(--muted); line-height: 1.5; margin: 0; }
.brand-dialog .update-progress { margin: 14px 24px 4px; display: grid; gap: 10px; }
.brand-dialog .update-progress[hidden] { display: none; }
.update-progress-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.update-progress-head span, #updateProgressDetail { color: var(--muted); font-size: 13px; }
.update-progress progress { width: 100%; height: 10px; accent-color: var(--accent); }
#updateProgressDetail { margin: 0; line-height: 1.45; }
/* 0.3.39 settings disclosure: four common cards stay visible; advanced options
   live in one non-nested disclosure. Search is the escape hatch for anything
   that is collapsed, so "hidden" never means "undiscoverable". */
.settings-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 320px) auto minmax(0, 1fr);
  align-items: end;
  gap: 12px;
  margin: 32px 0 24px;
}
.settings-search { display: grid; gap: 8px; min-width: 0; margin: 0; color: var(--muted); font-size: 14px; }
.settings-search input { width: 100%; }
.settings-search-count { grid-column: 3; grid-row: 1; align-self: end; min-width: 0; min-height: 22px; padding-bottom: 12px; color: #9fb3cb; font-size: 14px; overflow-wrap: anywhere; }
.settings-search-count:empty { display: none; }
#openOnboarding { grid-column: 2; grid-row: 1; justify-self: start; align-self: end; white-space: nowrap; }
.settings-item[hidden] { display: none !important; }
/* Module numbers and faux telemetry headers duplicate the real headings. Keep
   data-module as internal metadata for colour hooks, but do not paint it. */
.module-card::after, .module-table::before, .module-table::after { display: none !important; content: none !important; }
.module-table { padding-top: 0; }
.advanced-settings { grid-column: 1 / -1; padding: 0 !important; overflow: clip; }
.advanced-settings > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 32px 32px;
  cursor: pointer;
  list-style: none;
}
.advanced-settings > summary::-webkit-details-marker { display: none; }
.advanced-settings > summary::after { content: '›'; color: #a9b9cf; font-size: 36px; transform: rotate(90deg); transition: transform .18s ease; }
.advanced-settings[open] > summary::after { transform: rotate(-90deg); }
.advanced-settings > summary span { display: grid; gap: 8px; }
.advanced-settings > summary strong { color: #eef5ff; font-size: 24px; }
.advanced-settings > summary small { color: var(--muted); font-size: 14px; }
.advanced-settings-body {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
  padding: 0 32px 32px;
  border-top: 1px solid rgba(143, 169, 196, .16);
}
.advanced-settings-body > section { padding-top: 32px; }
.advanced-settings-body h3 { margin: 0 0 16px; color: #e9f2ff; }
.advanced-safety ul { margin: 0; padding-left: 24px; }
.advanced-safety li { margin: 12px 0; color: #9caec3; font-size: 14px; }

.onboarding-dialog { width: min(880px, calc(100vw - 32px)); }
.onboarding-steps { display: grid; gap: 12px; margin: 24px 0 0; padding: 0; list-style: none; }
.onboarding-steps li {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border: 1px solid rgba(122, 155, 194, .22);
  border-radius: 14px;
  background: rgba(6, 17, 32, .58);
}
.onboarding-steps li > span { display: grid; place-items: center; width: 34px; height: 40px; border-radius: 50%; color: #bff7ec; background: rgba(41, 171, 150, .18); font-weight: 800; }
.onboarding-steps strong { display: block; color: #eef5ff; }
.onboarding-steps p { margin: 3px 0 0; color: var(--muted); font-size: 14px; }

@media (max-width: 760px) {
  .settings-toolbar { grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 8px; margin: 16px 0; }
  .settings-search-count { grid-column: 1 / -1; grid-row: 2; padding-bottom: 0; }
  #openOnboarding { grid-column: 2; grid-row: 1; justify-self: end; }
  .advanced-settings-body { grid-template-columns: 1fr; }
  .onboarding-steps li { grid-template-columns: 34px minmax(0, 1fr); }
  .onboarding-steps li > button { grid-column: 1 / -1; }
}

/* Webhook 快訊設定卡：先格式、後範例。
   ⛔ 放在檔尾是刻意的：.json-template 在前面三層主題各定義過一次，寫在這裡才不用
   逐層去追誰蓋誰。放大範圍只綁 #tradingview 這一節 —— 全域字級一動，設定頁、交易紀錄
   等十幾個版面都會跟著跑位，這些規則只綁定 Webhook 的快訊設定。 */
#cloud .receiver-grid { gap: 32px; align-items: start; }
#cloud .receiver-grid .card.form-card { padding: 32px; }
#cloud .receiver-grid .template-head h2 { font-size: 30px; }
#cloud .receiver-grid .template-head .muted { font-size: 18px; }
#cloud .receiver-grid label { font-size: 18px; }
#cloud .receiver-grid .receiver-help { font-size: 18px; line-height: 1.8; }
#cloud .receiver-grid .notice, #cloud .receiver-grid .strategy-route-note { font-size: 16px; line-height: 1.75; }

.alert-block { margin-top: 32px; }
.alert-block + .alert-block { margin-top: 32px; padding-top: 32px; border-top: 1px solid var(--border); }
.alert-block-head { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 16px; }
.alert-block-head h3 { margin: 0; font-size: 24px; font-weight: 800; letter-spacing: .5px; }
.alert-block-head button { margin-left: auto; }
.alert-tag { padding: 8px 16px; border-radius: 999px; font-size: 16px; font-weight: 700; line-height: 1.4; }
.alert-tag-required { border: 1px solid rgba(255, 148, 173, .38); color: #ffb3c4; background: rgba(120, 26, 48, .38); }
.alert-tag-sample { border: 1px solid rgba(134, 200, 240, .3); color: #9ecfee; background: rgba(18, 52, 78, .5); }

/* 格式圖：每一行左邊釘一個「第幾行」的標籤，右邊才是內容。 */
.alert-shape { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 16px 16px; margin: 0 0 24px; padding: 24px; border: 1px solid rgba(25, 221, 255, .32); border-radius: 11px; background: rgba(0, 10, 18, .9); font: 18px/1.7 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: normal; overflow-wrap: anywhere; }
.alert-shape-tag { padding: 3px 12px; border-radius: 6px; color: #8fd6ff; background: rgba(23, 70, 104, .8); font-size: 16px; font-weight: 700; white-space: nowrap; }
.alert-shape-free { color: #cfe4f2; }
.alert-shape-code { color: #7ff0c4; font-weight: 700; }

/* ⚠ 卡片撐滿寬度後，若欄位表仍是單欄，每一行會被拉到破千 px ⇒ 反而更難讀
   （行長超過 75 字元眼睛會找不到下一行的開頭）。⇒ 寬度用在**並排**。 */
.alert-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 16px; margin: 0 0 24px; }
.alert-fields > div { display: grid; grid-template-columns: minmax(150px, auto) minmax(0, 1fr); gap: 8px 24px; align-items: baseline; padding: 16px 16px; border: 1px solid var(--border); border-radius: 9px; background: rgba(6, 20, 33, .55); }
.alert-fields dt { display: flex; align-items: center; gap: 12px; margin: 0; }
.alert-fields dt code { color: #7ff0c4; font-size: 18px; font-weight: 800; }
.alert-fields dd { margin: 0; color: var(--muted); font-size: 18px; line-height: 1.7; }
.alert-fields dd code { color: #84d9ff; font-size: 16px; }
.alert-need { padding: 2px 12px; border-radius: 5px; font-size: 14px; font-weight: 700; }
.alert-need-must { color: #ffc0cd; background: rgba(120, 26, 48, .55); }
.alert-need-opt { color: #a9bdd0; background: rgba(46, 66, 87, .6); }

.alert-rules { display: grid; gap: 12px; margin: 0; padding: 24px 24px 24px 48px; border-left: 3px solid var(--amber); border-radius: 2px 8px 8px 2px; background: rgba(89, 60, 15, .22); color: #e7cf9e; font-size: 18px; line-height: 1.7; }
.alert-rules code { padding: 0 8px; border-radius: 4px; color: #ffd9a0; background: rgba(0, 0, 0, .35); font-weight: 800; }

/* 範例框本來留了 315px 的空白高度給一份很短的範例；格式區搬進來之後改成貼齊內容。 */
.alert-block-example .json-template { min-height: 0; margin: 0 0 16px; padding: 24px; font-size: 18px; line-height: 1.8; }
.alert-block-example .receiver-help strong { color: #ffc9a2; }

@media (max-width: 760px) {
  .alert-shape { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .alert-fields > div { grid-template-columns: minmax(0, 1fr); }
}

/* type floor */
/* <small> 與 <sub>/<sup> 的 UA 預設是相對縮小（smaller ≈ .8em），會繞過所有以 px
   重建的型階 —— 實測畫面最小字停在 9px 就是這條路徑。企業儀表板的 caption 下限
   是 12px（lollypop.design 2026-07），所以在這裡把地板釘死。
   ⛔ 不要改成 font-size: inherit：那會讓 <small> 完全失去「次要資訊」的視覺分級。 */
small { font-size: max(12px, .875em); }

/* 系統詳細狀態分頁（2026-08-18 取代獨立的 /status 頁面）。
   ⛔ 刻意複用既有的 .section-title / var(--space-*) / 色彩 token —— 舊的 status.html
   自己帶了一整套 700 行的行內樣式，那是第二套設計系統，改一邊另一邊永遠不會跟上。
   auto-fit + minmax 讓卡片數從 4 張長到十幾張都不必改 CSS（站長問的「未來十幾張」）。 */
.status-page-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
  margin-bottom: var(--space-6);
}
.status-page-section { margin-top: var(--space-6); }
.status-page-section h2 { margin: 0 0 var(--space-4); font-size: 20px; font-weight: 600; }
.status-page-card {
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: rgba(13, 17, 39, .93);
}
.status-page-card.ok { border-color: rgba(70, 244, 170, .34); }
.status-page-card.pending { border-color: rgba(120, 229, 255, .34); }
.status-page-card.error { border-color: rgba(255, 85, 120, .46); }
.status-page-card.ok .system-status-icon { color: var(--green); }
.status-page-card.pending .system-status-icon { color: var(--cyan); }
.status-page-card.error .system-status-icon { color: var(--red); }
.status-page-line { display: flex; align-items: center; gap: var(--space-2); }
.status-page-line h3 { margin: 0; font-size: 16px; font-weight: 600; }
.status-page-value { margin: var(--space-3) 0 var(--space-1); font-size: 20px; font-weight: 700; overflow-wrap: anywhere; }
.status-page-message { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
/* 這顆以前是 <a>，改成 <button> 之後要把按鈕的預設外觀清掉，維持原本的連結樣子 */
button.system-status-link { width: 100%; border: 0; border-top: 1px solid var(--border); background: none; text-align: left; cursor: pointer; }

/* ── 機器人分組 ─────────────────────────────────────────────────────────── */
.bot-group-bar { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-4); }
.bot-group-picker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
}
/* ⛔ 寬度要有上限也要有下限：組名可以到 40 字，讓它撐開會把頁籤擠出畫面；
   而太窄則連「未分類」都顯示不完。 */
.bot-group-picker select {
  width: auto;
  min-width: 160px;
  max-width: 260px;
  min-height: 40px;
  margin: 0;
  padding: 0 var(--space-3);
}
.bot-group-count { font-size: var(--text-sm); }
/* 紀錄切換與其他沿用 .wb-tab 的地方，名稱仍需截斷。 */
.wb-tab-name {
  display: inline-block;
  max-width: 14ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* ── 歷史表格：固定欄寬 ＋ 單行截斷 ＋ 可拖曳 ────────────────────────────────
   站長 2026-08-18：「每個欄位要有固定寬度，超出的部分要截斷，表頭可以手動拖曳調整」。

   ⛔ 這段放檔尾是刻意的：欄寬要蓋過前面每一套主題層（105/524/793/1244/1519/2014
      各自重寫過 th,td），插在中間會被後面的層吃掉，而那種失效不會報錯 —— 畫面照
      渲染，只是寬度不是你寫的那個。
   ⛔ 只認 .history-table 這一個 class：交易紀錄與內建瀏覽兩張表講同一批紀錄、列由
      同一個 historyRowHtml 產生，欄寬自然也只該有一份。⛔ 訊號紀錄（SIGNAL LOG）
      欄位不同，故意不套。
   ⚠ 真正的欄寬由 JS 注入的 <colgroup> 決定（app.js applyHistoryColumnWidths），
      這裡的 nth-child 只是 colgroup 還沒掛上前的預設，兩邊的數字要一致。 */
.history-table { table-layout: fixed; }
.history-table th, .history-table td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 預設寬度按內容特性給：口數／方向最窄，動作最寬。
   ⚠ 第 5 欄（動作）刻意不給寬度 —— 它是彈性欄，吸收剩餘空間。給了它寬度，剩餘
      空間就會被平均分攤到每一欄，使用者拖到的值與看到的值從此對不上。 */
/* ⚠ 這些數字必須逐一等於 app.js 的 HISTORY_COLUMN_DEFAULT_WIDTHS（第 5 欄是彈性欄，
      兩邊都不指定）。2026-08-26 加「商品」「原因」兩欄：非彈性欄合計 1078px。
      ⛔ 只改一邊＝colgroup 掛上前後會跳一次寬度。 */
.history-table th:nth-child(1), .history-table td:nth-child(1) { width: 180px; }

.history-table th:nth-child(2), .history-table td:nth-child(2) { width: 96px; }
.history-table th:nth-child(3), .history-table td:nth-child(3) { width: 96px; }
.history-table th:nth-child(5), .history-table td:nth-child(5) { width: 158px; }
.history-table th:nth-child(6), .history-table td:nth-child(6) { width: 96px; }
.history-table th:nth-child(7), .history-table td:nth-child(7) { width: 104px; }
.history-table th:nth-child(8), .history-table td:nth-child(8) { width: 120px; }
.history-table th:nth-child(9), .history-table td:nth-child(9) { width: 160px; }
/* 數值靠右、等寬數字。價格／口數／損益三欄（第 5/6/7）都是數值。 */
.history-table th:nth-child(5), .history-table td:nth-child(5),
.history-table th:nth-child(6), .history-table td:nth-child(6),
.history-table th:nth-child(7), .history-table td:nth-child(7) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* 空狀態那一列橫跨整表，⛔ 不能被上面的 nth-child 綁死成第一欄的寬度。 */
.history-table td.empty, .history-table td[colspan] { width: auto; white-space: normal; text-overflow: clip; }

/* 拖曳把手：由 app.js 注入到每個 th 裡，⛔ 不寫進手寫的 <thead>（那有兩份，
   會變成第三個要記得同步的地方）。4-6px 是業界常見的命中寬度。 */
/* ⛔ 把手放欄「內側」不是騎在邊界上：騎邊界要 th overflow:visible，那會把上面
   剛設的表頭截斷整條取消掉（表頭一長就撐破欄寬，而且不會報錯）。th 本來就有
   24px 水平 padding，6px 的把手正好落在留白裡，不會壓到字。 */
.history-table th > .col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 6px;
  height: 100%;
  cursor: col-resize;
  user-select: none;
  touch-action: none;
  z-index: 2;
}
.history-table th > .col-resizer::after {
  content: '';
  position: absolute;
  top: 25%;
  left: 2px;
  width: 2px;
  height: 50%;
  border-radius: 1px;
  background: transparent;
  transition: background .12s ease;
}
.history-table th > .col-resizer:hover::after,
.history-table th > .col-resizer.dragging::after { background: var(--blue, #35a4ff); }
/* 鍵盤也要能調 —— 只有滑鼠拖得動等於這個功能對鍵盤使用者不存在。 */
.history-table th > .col-resizer:focus-visible { outline: 2px solid var(--cyan, #78e5ff); outline-offset: -1px; }
.history-table th > .col-resizer:focus-visible::after { background: var(--cyan, #78e5ff); }
/* 拖曳中：全域游標不要跟著儲存格變回 text，否則手感像斷掉。 */
body.history-col-resizing, body.history-col-resizing * { cursor: col-resize !important; user-select: none !important; }

/* 「紀錄」是使用者進入這一頁的定位點；版面切換是同一列的次要控制。 */
.workbench-page-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 44px;
  margin: 0 0 8px;
  padding: 0 2px;
}
.workbench-page-heading h1 { margin: 0; color: var(--text); font-size: 22px; line-height: 1.15; }
.workbench-page-heading p { margin: 2px 0 0; color: var(--muted); font-size: 12px; }
.workbench-page-heading .wb-layout-switch { flex: 0 0 auto; }
.workbench-page-heading .wb-layout-switch button { width: 38px; min-width: 38px; height: 36px; min-height: 36px; }
.workbench-page-heading .wb-layout-switch svg { width: 21px; height: 21px; }
.wb-stage-head {
  position: relative;
  z-index: 30;
  display: grid;
  grid-template-columns: 28px minmax(220px, 1fr) auto;
  align-items: center;
  gap: 6px;
  min-height: 56px;
  padding: 8px;
  overflow: visible;
}
.wb-pane-drag-handle {
  display: grid;
  place-items: center;
  width: 28px;
  height: 40px;
  border-radius: 8px;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.wb-pane-drag-handle:hover, .wb-pane-drag-handle:focus-visible { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 12%, transparent); outline: none; }
.wb-pane-drag-handle:active { cursor: grabbing; }
.wb-pane-drag-handle svg { width: 18px; height: 24px; fill: currentColor; }
.wb-grid-tile .wb-stage-head, .wb-focus-pane .wb-stage-head { display: grid; gap: 6px; padding: 8px; }
.wb-pane-picker {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  min-width: 220px;
  max-width: none;
  height: 40px;
  border: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
  border-radius: 10px;
  background: var(--surface-2);
}
.wb-pane-group {
  width: clamp(88px, 31%, 132px);
  min-width: 88px;
  height: 38px;
  padding: 0 20px 0 8px;
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 9px 0 0 9px;
  background-color: transparent;
  color: var(--muted);
  font-size: 12px;
}
.wb-pane-picker > .bot-avatar-button {
  width: 30px;
  min-width: 30px;
  max-width: 30px;
  height: 30px;
  min-height: 30px;
  max-height: 30px;
  margin-left: 7px;
  flex: 0 0 30px;
}
.wb-pane-bot-picker { position: static; min-width: 0; flex: 1 1 auto; }
.wb-pane-bot-picker > summary {
  min-height: 38px;
  padding: 0 26px 0 7px;
  border-radius: 0 9px 9px 0;
  display: flex;
  align-items: center;
}
.wb-pane-bot-picker > summary::after { right: 10px; }
.wb-pane-current { display: flex; align-items: center; gap: 7px; min-width: 0; }
.wb-pane-current strong { overflow: hidden; color: var(--text); font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
.wb-pane-bot-picker > .workbench-tabs { top: calc(100% + 6px); left: clamp(88px, 31%, 132px); width: min(320px, calc(100vw - 32px)); }
.wb-stage-tools { display: flex; align-items: center; justify-content: flex-end; gap: 5px; min-width: 0; }
.wb-stage-tools > .wb-stage-resource-toggle,
.wb-stage-tools > .wb-stage-fullscreen,
.wb-stage-tools > .wb-stage-more { display: grid; place-items: center; width: 36px; min-width: 36px; height: 36px; min-height: 36px; padding: 0; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); }
.wb-stage-more {
  width: 34px; min-width: 34px; height: 34px; min-height: 34px; padding: 0;
  border-radius: 9px; color: var(--text); background: rgba(24, 30, 65, .62);
  transition: color .14s ease, border-color .14s ease, background .14s ease, transform .14s ease;
}
.wb-stage-more:hover { color: var(--cyan); border-color: var(--cyan); background: color-mix(in srgb, var(--cyan) 10%, rgba(24, 30, 65, .72)); }
.wb-stage-more:active { transform: translateY(1px); }

/* 畫面／操作／交易在每個窗格都要看得到，和版面切換共用同一種分段控制語彙。 */
.wb-pane-tabs { display: inline-flex; align-items: center; gap: 2px; padding: 3px; border: 1px solid var(--border); border-radius: 11px; background: var(--surface-2); }
.wb-pane-tabs button { display: grid; place-items: center; width: 38px; min-width: 38px; height: 36px; min-height: 36px; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--muted); touch-action: none; cursor: grab; transition: color 140ms ease, background 140ms ease, transform 140ms cubic-bezier(.2,.8,.2,1); }
.wb-pane-tabs button:active { cursor: grabbing; transform: scale(.94); }
.wb-pane-tabs svg { width: 22px; height: 22px; }
.wb-stage-record-layer { flex: 1 1 0; min-height: 0; width: 100%; overflow: hidden; display: grid; place-items: stretch; }
.wb-stage-viewer-layer[hidden], .wb-stage-record-layer[hidden] { display: none !important; }

/* 按住哪顆內容圖示，就讓那顆原按鈕本身浮起跟手；placeholder 只守住原列寬度。
   不再另生右下角 ghost，避免看起來像同時有兩顆按鈕。 */
.wb-pane-tabs button.is-mode-drag-source {
  position: fixed;
  inset: 0 auto auto 0;
  z-index: 13000;
  width: var(--wb-mode-drag-width);
  min-width: var(--wb-mode-drag-width);
  height: var(--wb-mode-drag-height);
  min-height: var(--wb-mode-drag-height);
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--cyan) 76%, white);
  border-radius: 10px;
  color: #eaffff;
  background: color-mix(in srgb, var(--surface-2) 78%, transparent);
  box-shadow: 0 16px 46px rgba(0,0,0,.48), 0 0 28px color-mix(in srgb, var(--cyan) 34%, transparent);
  backdrop-filter: blur(16px) saturate(1.25);
  pointer-events: none;
  will-change: transform;
  transform: translate3d(var(--wb-mode-drag-x), var(--wb-mode-drag-y), 0) scale(1.08);
  transition: none;
}
.wb-mode-drag-placeholder { display: inline-block; flex: 0 0 auto; border-radius: 8px; background: color-mix(in srgb, var(--cyan) 10%, transparent); }
.workbench-mode-dragging { cursor: grabbing; user-select: none; }
.is-mode-drop-target {
  isolation: isolate;
  border-color: color-mix(in srgb, var(--cyan) 84%, white) !important;
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--cyan) 46%, transparent), 0 0 32px color-mix(in srgb, var(--cyan) 24%, transparent) !important;
}
.is-mode-drop-target::after {
  content: '放開即可覆蓋';
  position: absolute;
  inset: 50% auto auto 50%;
  z-index: 95;
  transform: translate(-50%,-50%) scale(1);
  padding: 10px 15px;
  border: 1px solid color-mix(in srgb, var(--cyan) 72%, white);
  border-radius: 999px;
  color: #eaffff;
  background: rgba(5,25,38,.84);
  box-shadow: 0 12px 36px rgba(0,0,0,.38);
  backdrop-filter: blur(12px);
  font-size: 13px;
  font-weight: 800;
  pointer-events: none;
  animation: wb-mode-drop-pulse 760ms ease-in-out infinite alternate;
}
@keyframes wb-mode-drop-pulse { from { transform: translate(-50%,-50%) scale(.96); opacity: .82; } to { transform: translate(-50%,-50%) scale(1.04); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .is-mode-drop-target::after { animation: none; } }
.workbench-panel[data-layout="grid"] .wb-pane-picker {
  min-width: 220px;
  max-width: none;
}
.workbench-panel[data-layout="grid"] .wb-pane-group {
  width: clamp(88px, 31%, 120px);
  min-width: 88px;
  padding-inline: 8px 20px;
}
.workbench-panel[data-layout="grid"] .wb-pane-bot-picker > .workbench-tabs { left: clamp(88px, 31%, 120px); }

.wb-trade-summary {
  /* 硬限制：交易控制列永遠留在文件流自己的列，不能用 absolute／sticky
     疊到券商畫面上。畫面可以縮放，控制列不可以拿它當背景。 */
  position: static;
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(320px, 1.1fr) minmax(330px, .9fr);
  gap: 1px;
  padding: 1px;
  border-bottom: 1px solid var(--border);
  background: var(--border);
}
.wb-trade-summary .wb-grid-trade {
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
  padding: 6px 8px;
  background: var(--surface-2);
}
.wb-trade-summary .wb-grid-trade .qt-side { flex: 1 1 72px; min-width: 0; min-height: 38px; padding: 0 clamp(6px, 1.2vw, 12px); }
.wb-trade-summary .wb-grid-trade .qt-qty { flex: 0 1 116px; min-width: 92px; }
.wb-trade-summary .wb-grid-trade .qt-qty button { width: 28px; min-width: 28px; }
.wb-trade-summary .wb-grid-trade .qt-qty input { width: 42px; min-width: 38px; }
.wb-stage-metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  flex: 0 0 auto;
  padding: 1px;
  background: var(--border);
  font-variant-numeric: tabular-nums;
}
.wb-trade-summary > .wb-stage-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); order: initial; width: 100%; min-width: 0; gap: 1px; border: 0; }
.wb-stage-metric { container-type: inline-size; display: grid; gap: 2px; min-width: 0; padding: 7px clamp(4px, 1vw, 10px); background: var(--surface-2); text-align: center; }
.wb-stage-metric small { overflow: visible; color: var(--muted); font-size: clamp(9px, 12cqi, 12px); line-height: 1.15; white-space: nowrap; }
.wb-stage-metric strong { overflow: visible; color: var(--text); font-size: clamp(10px, 14cqi, 16px); line-height: 1.2; letter-spacing: -.02em; white-space: nowrap; }
.wb-stage-metric strong.positive { color: var(--green); }
.wb-stage-metric strong.negative { color: var(--danger); }

@container (max-width: 480px) {
  .wb-stage-head { grid-template-columns: 28px minmax(0, 1fr); }
  .wb-stage-tools { grid-column: 1 / -1; justify-content: flex-start; }
  .wb-pane-picker { min-width: 0; }
  .wb-pane-tabs button { width: 34px; min-width: 34px; height: 34px; min-height: 34px; }
  .wb-pane-tabs svg { width: 20px; height: 20px; }
  .wb-stage-tools > .wb-stage-resource-toggle,
  .wb-stage-tools > .wb-stage-fullscreen,
  .wb-stage-tools > .wb-stage-more { width: 34px; min-width: 34px; height: 34px; min-height: 34px; }
  .wb-trade-summary { grid-template-columns: minmax(0, 1fr); }
  .wb-trade-summary .wb-grid-trade .qt-side { font-size: 12px; }
}

/* 0.3.70 工作台窗格工具：四顆固定尾端動作共用同一外觀；關閉只有在靠近時轉紅，
   資源節省在未啟動時仍保留位置並降階，避免工具列隨狀態左右跳動。 */
.wb-stage-head .wb-stage-window-tools > .wb-stage-close {
  display: grid;
  place-items: center;
  width: 32px;
  min-width: 32px;
  height: 36px;
  min-height: 36px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--muted);
  transition: color .14s ease, border-color .14s ease, background .14s ease, transform .14s ease;
}
.wb-stage-close svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.wb-stage-close:hover,
.wb-stage-close:focus-visible { color: #ff718e; border-color: #ff5579; background: color-mix(in srgb, #ff315f 16%, var(--surface-2)); }
.wb-stage-close:active { transform: scale(.94); }
.wb-stage-resource-toggle:disabled { opacity: .42; cursor: not-allowed; filter: saturate(.35); }
.wb-stage-resource-toggle:disabled:hover { border-color: var(--border); color: var(--muted); }

/* 空窗格只選既有機器人，不再把使用者送去建立流程。清單採分組＋大頭照＋名稱的
   單欄選擇器，觸控與滑鼠都有足夠命中面積。 */
.wb-empty-pane {
  position: relative;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 8px;
  width: 100%;
  height: 100%;
  min-height: 220px;
  padding: 24px;
  color: var(--muted);
  text-align: center;
  background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--cyan) 8%, transparent), transparent 42%);
}
.wb-empty-pane > strong { color: var(--text); font-size: 15px; }
.wb-empty-pane > span { font-size: 12px; }
.wb-empty-picker { position: relative; }
.wb-empty-picker > summary {
  display: grid;
  place-items: center;
  width: 74px;
  height: 74px;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--cyan) 35%, var(--border));
  border-radius: 50%;
  background: color-mix(in srgb, var(--cyan) 7%, var(--surface-2));
  color: var(--cyan);
  cursor: pointer;
  list-style: none;
  transition: transform .18s cubic-bezier(.2,.8,.2,1), border-color .18s ease, box-shadow .18s ease;
}
.wb-empty-picker > summary::-webkit-details-marker { display: none; }
.wb-empty-picker > summary:hover,
.wb-empty-picker > summary:focus-visible { transform: scale(1.06); border-color: var(--cyan); box-shadow: 0 0 30px color-mix(in srgb, var(--cyan) 24%, transparent); }
.wb-empty-picker > summary svg { width: 34px; height: 34px; fill: none; stroke: currentColor; stroke-width: 1.55; stroke-linecap: round; }
.wb-empty-picker-menu {
  position: fixed;
  z-index: 21050;
  top: 50%;
  left: 50%;
  width: min(380px, calc(100vw - 28px));
  max-height: min(70vh, 560px);
  padding: 10px;
  overflow: auto;
  border: 1px solid color-mix(in srgb, var(--cyan) 28%, var(--border));
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  box-shadow: 0 24px 80px rgba(0,0,0,.55);
  backdrop-filter: blur(22px) saturate(1.25);
  transform: translate(-50%, -50%);
  text-align: left;
}
.wb-empty-picker:not([open]) > .wb-empty-picker-menu { display: none; }
.wb-empty-picker-group + .wb-empty-picker-group { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.wb-empty-picker-group h4 { margin: 0 0 6px; padding: 0 8px; color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.wb-empty-bot-option { display: block; width: 100%; min-height: 58px; padding: 7px 9px; border: 0; border-radius: 10px; background: transparent; color: var(--text); text-align: left; }
.wb-empty-bot-option:hover,
.wb-empty-bot-option:focus-visible { background: color-mix(in srgb, var(--cyan) 12%, transparent); }
.wb-empty-bot-option .wb-bot-picker-row { grid-template-columns: 9px 42px minmax(0, 1fr); gap: 10px; }
.wb-empty-bot-option .bot-avatar-display { width: 42px; min-width: 42px; max-width: 42px; height: 42px; min-height: 42px; max-height: 42px; }
.wb-empty-bot-option .wb-bot-picker-name { font-size: 15px; font-weight: 760; }

/* 身分選擇器把大頭照與名稱視為同一組，尺寸比一般工具圖示大一級。 */
.wb-pane-identity-row { grid-template-columns: 42px minmax(0, 1fr); gap: 7px; }
.wb-pane-identity-row > .bot-avatar-button { width: 42px; min-width: 42px; max-width: 42px; height: 42px; min-height: 42px; max-height: 42px; }
.wb-stage-head .wb-pane-bot-picker > summary { min-height: 42px; }
.wb-stage-head .wb-pane-current strong { font-size: 14px; }
.wb-stage-head .wb-bot-option { min-height: 54px; }
.wb-stage-head .wb-bot-picker-row { grid-template-columns: 9px 38px minmax(0, 1fr); gap: 8px; }
.wb-stage-head .wb-bot-option .bot-avatar-display { width: 38px; min-width: 38px; max-width: 38px; height: 38px; min-height: 38px; max-height: 38px; }

/* 四格仍使用同一個摘要元件，但 480px 以上維持同一列，避免控制列吃掉畫面的高度。 */
.wb-grid-tile .wb-trade-summary { grid-template-columns: minmax(230px, .95fr) minmax(240px, 1.05fr); }
.wb-grid-tile .wb-stage-metrics { display: grid; order: initial; width: auto; }

/* 四格／上下格的外框高度固定時，live 畫布必須只吃「控制列之外」的剩餘空間。
   ⛔ 若沿用單格的 16:9 固定高度，控制列 + 畫布會高過 tile，再被 overflow:hidden
      裁掉底部，看起來就像買賣列蓋住券商畫面。這裡改成 flex 剩餘空間，影像本身
      仍由 object-fit:contain 保證四邊完整顯示。 */
.wb-grid-tile > .wb-stage-canvas:has(.wb-stage-live),
.wb-focus-pane > .wb-stage-canvas:has(.wb-stage-live) {
  flex: 1 1 0;
  width: 100%;
  height: auto;
  min-height: 0;
  aspect-ratio: auto;
  overflow: hidden;
}

@media (max-width: 820px) {
  .workbench-page-heading p { display: none; }
  .wb-trade-summary { grid-template-columns: minmax(0, 1fr); }
  .wb-trade-summary .wb-grid-trade { gap: 4px; padding-inline: 6px; }
}

/* 1×1 是上／下兩格，預設給上方寬螢幕較多空間；2×2 的整體改成桌面橫向比例。 */
.workbench-stage[data-layout="split"] {
  --wb-split-ratio: 50%;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, var(--wb-split-ratio)) 8px minmax(0, 1fr);
  gap: 0;
  /* 兩格都要有足夠的實際畫布；寬螢幕時依寬度增高，寧可讓頁面捲動，也不把
     Tradovate 與紀錄壓成兩張縮圖。使用者拖過的 1:1 比例仍完整保留。 */
  height: clamp(1400px, max(135vh, calc((100vw - 32px) * 1.22)), 2360px);
}
.workbench-stage[data-layout="split"][data-split-axis="horizontal"] {
  grid-template-columns: minmax(0, var(--wb-split-ratio)) 8px minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  height: clamp(620px, calc(100vh - 118px), 900px);
}
.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-split-resizer { cursor: col-resize; }
.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-split-resizer::after { inset: 12px 3px; }
.workbench-stage[data-layout="grid"] {
  --wb-grid-x: 50%;
  --wb-grid-y: 50%;
  width: 100%;
  height: clamp(1280px, calc((100vw - 32px) * 1.04), 2000px);
  min-height: 0;
  aspect-ratio: auto;
  align-self: center;
  grid-template-columns: minmax(0, var(--wb-grid-x)) minmax(0, 1fr);
  grid-template-rows: minmax(0, var(--wb-grid-y)) minmax(0, 1fr);
}
.wb-grid-tile { container-type: inline-size; }
.wb-snap-overlay {
  position: fixed;
  inset: auto;
  z-index: 80;
  pointer-events: none;
  border-radius: inherit;
  background: color-mix(in srgb, var(--bg) 28%, transparent);
  backdrop-filter: blur(2px);
}
.wb-snap-preview {
  position: absolute;
  display: grid;
  place-items: center;
  min-width: 72px;
  min-height: 72px;
  border: 2px solid color-mix(in srgb, var(--cyan) 78%, white);
  border-radius: 14px;
  color: var(--text);
  background: color-mix(in srgb, var(--cyan) 22%, rgba(8, 17, 34, .82));
  box-shadow: 0 18px 55px rgba(0, 0, 0, .42), inset 0 0 0 1px rgba(255,255,255,.12);
  opacity: .72;
  transition: left 110ms cubic-bezier(.2,0,0,1), top 110ms cubic-bezier(.2,0,0,1), width 110ms cubic-bezier(.2,0,0,1), height 110ms cubic-bezier(.2,0,0,1), opacity 90ms ease, box-shadow 90ms ease;
}
.wb-snap-preview strong { padding: 8px 12px; border-radius: 999px; background: rgba(3, 8, 19, .78); font-size: 13px; }
.wb-snap-preview.is-armed {
  opacity: 1;
  box-shadow: 0 18px 55px rgba(0, 0, 0, .42), inset 0 0 0 2px color-mix(in srgb, var(--cyan) 82%, white), 0 0 34px color-mix(in srgb, var(--cyan) 34%, transparent);
}
.wb-focus-pane.is-snap-dragging, .wb-grid-tile.is-snap-dragging {
  opacity: .92;
  box-shadow: 0 24px 70px rgba(0,0,0,.55);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .wb-snap-preview { transition: none; }
}
.wb-pane-resizer { touch-action: none; user-select: none; z-index: 45; }
.wb-split-resizer { cursor: row-resize; position: relative; }
.wb-split-resizer::after,
.wb-grid-resizer-x::after,
.wb-grid-resizer-y::after {
  content: '';
  position: absolute;
  border-radius: 999px;
  background: color-mix(in srgb, var(--cyan) 38%, var(--border));
  transition: background .12s ease, box-shadow .12s ease;
}
.wb-split-resizer::after { inset: 3px 12px; }
.wb-grid-resizer-x,
.wb-grid-resizer-y { position: absolute; }
.wb-grid-resizer-x { top: 0; bottom: 0; left: calc(var(--wb-grid-x) - 5px); width: 10px; cursor: col-resize; }
.wb-grid-resizer-x::after { top: 12px; bottom: 12px; left: 4px; width: 2px; }
.wb-grid-resizer-y { left: 0; right: 0; top: calc(var(--wb-grid-y) - 5px); height: 10px; cursor: row-resize; }
.wb-grid-resizer-y::after { left: 12px; right: 12px; top: 4px; height: 2px; }
.wb-pane-resizer:hover::after,
.wb-pane-resizer:focus-visible::after,
.wb-pane-resizer.is-dragging::after { background: var(--cyan); box-shadow: 0 0 10px color-mix(in srgb, var(--cyan) 55%, transparent); }
body.workbench-pane-resizing { user-select: none; }

/* Nine trade columns share the JS defaults, colgroup and persisted widths. */
.history-table th:nth-child(n), .history-table td:nth-child(n) { width: auto; text-align: left; }
.history-table th:nth-child(6), .history-table td:nth-child(6),
.history-table th:nth-child(7), .history-table td:nth-child(7),
.history-table th:nth-child(8), .history-table td:nth-child(8) { text-align: left; font-variant-numeric: tabular-nums; }

.resizable-table { table-layout: fixed; }
.resizable-table th, .resizable-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.history-table td.side-cell { text-overflow: clip; padding-inline: 4px; }
.history-table td.side-cell > .side-tag { min-width: 0; padding-inline: 4px; }
.resizable-table th { position: relative; }
.resizable-table th > .col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 4;
  width: 7px;
  height: 100%;
  cursor: col-resize;
  touch-action: none;
}
.resizable-table th > .col-resizer::after { content: ''; position: absolute; top: 24%; bottom: 24%; right: 2px; width: 2px; border-radius: 2px; background: transparent; }
.resizable-table th > .col-resizer:hover::after,
.resizable-table th > .col-resizer:focus-visible::after,
.resizable-table th > .col-resizer.dragging::after { background: var(--cyan); }

.pnl-heading { position: relative; display: inline-flex; align-items: center; justify-content: flex-end; gap: 5px; }
.pnl-info { display: inline-grid; place-items: center; width: 16px; height: 16px; border: 1px solid currentColor; border-radius: 50%; color: var(--muted); font: 700 11px/1 sans-serif; cursor: help; }
.pnl-tooltip {
  position: fixed;
  z-index: 10020;
  top: 112px;
  right: 24px;
  width: min(360px, calc(100vw - 32px));
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 14px 40px rgba(0,0,0,.45);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  text-align: left;
  white-space: normal;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}
.pnl-info:hover + .pnl-tooltip, .pnl-info:focus-visible + .pnl-tooltip { visibility: visible; opacity: 1; }

/* 這兩條放在既有摘要規則之後，封住相同 specificity 的舊橫排設定。 */
@container (min-width: 901px) {
  .wb-trade-summary .wb-grid-trade {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(86px, .9fr) minmax(0, 1fr) 38px;
  }
  .wb-trade-summary > .wb-stage-metrics { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 980px) {
  .wb-stage-head { grid-template-columns: 28px minmax(210px, 1fr) auto; }
  .wb-pane-picker { max-width: none; }
}

@media (max-width: 720px) {
  .workbench-page-heading { align-items: flex-start; }
  /* 沿用原38px版面鍵；窄手機讓裝飾圖示讓位給右上真實異常狀態藥丸。 */
  #internal-browse .workbench-page-heading { gap: 6px; }
  #internal-browse .workbench-route-title { font-size: 18px; }
  #internal-browse .workbench-route-title > .page-heading-icon { display: none; }
  .workbench-layout-rail { justify-content: flex-start; margin: 0 0 8px; }
  .workbench-stage[data-layout="grid"] { display: flex; flex-direction: column; width: 100%; aspect-ratio: auto; }
  .workbench-stage[data-layout="split"] { height: auto; min-height: 0; grid-template-rows: none; }
  .workbench-stage[data-layout="split"][data-split-axis="horizontal"] { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; height: auto; }
  .workbench-stage[data-layout="split"] .wb-focus-pane { min-height: 440px; }
  .wb-pane-resizer { display: none; }
  .wb-stage-head { grid-template-columns: 28px minmax(0, 1fr); }
  .wb-stage-tools { grid-column: 1 / -1; justify-content: flex-start; flex-wrap: wrap; }
  .wb-pane-picker { min-width: 0; }
}

/* ── 建立／編輯機器人對話框（0.4.3：同一個表單兩種模式）─────────────────────
   ⛔ 間距一律取既有 --space-* 網格、圓角取 --radius-*、顏色取既有 token，
      ⛔ 不新增一次性數值 —— 這個檔已經有五處各寫一份 .app-header 的前例。 */

/* 編輯模式的說明條。橘色那版沿用 .bot-reconciling-warning 的語彙（警示但非錯誤）；
   剛建立完那一次改用綠色 —— 那是成功回饋，用警示色會讓人以為出事了。 */
.dialog-note {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid rgba(255, 184, 77, .46);
  border-radius: var(--radius-md);
  color: #ffd38a;
  background: rgba(91, 48, 15, .32);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.dialog-note.created {
  border-color: rgba(72, 213, 151, .46);
  color: #b9f5d7;
  background: rgba(15, 62, 44, .38);
}

/* 建立後不可更改的欄位。⛔ 停用而不是藏起來：藏起來使用者只覺得「欄位怎麼不見了」，
   看得到＋鎖頭＋說明條才知道「這是刻意的，而且原因寫在上面」。 */
.field-locked { opacity: .58; }
.field-locked > input, .field-locked > select { cursor: not-allowed; }
/* ⛔ ::before 不是 ::after —— label 是 display:block 且 input 包在 label 裡面，
   ::after 會把鎖頭掉到輸入框「下面」而不是接在欄位名旁邊。 */
.field-locked::before {
  content: '🔒';
  margin-right: var(--space-1);
  font-size: var(--text-xs);
}

/* 建立成功後彈回來時，指定商品那一格閃一下 —— 那是整個彈窗存在的理由，
   ⛔ 不要讓使用者自己在表單裡找。動畫尊重 prefers-reduced-motion（見檔頭那條 media query）。 */
.field-attention {
  border-radius: var(--radius-md);
  animation: field-attention-pulse 1.6s ease-out 1;
}
@keyframes field-attention-pulse {
  0% { box-shadow: 0 0 0 0 rgba(62, 215, 208, .55); }
  100% { box-shadow: 0 0 0 12px rgba(62, 215, 208, 0); }
}


/* ===== 0.4.3 建立／編輯機器人對話框：說明收成 `?` 提示 + 收緊列距 =====
   站長 2026-08-19：「新增機器人 這邊不要空這麼大」＋「將說明 全部做成 標題旁邊的 ?
   游標移動過去才顯示 就好」。
   ⚠ 說明字放在 .field-hint 的 aria-label（i18n.js 的 ATTRS 會翻譯它）；
     這裡用 content: attr(aria-label) 把同一份字畫成泡泡 ⇒ ⛔ 只有一份真相源。
   ⛔ 不要改用 title 屬性：那會同時跳出瀏覽器原生 tooltip ＝ 兩個泡泡。 */
#botForm .form-grid { gap: 0 20px; }
#botForm .form-grid > label { margin: 0 0 16px; }
#botForm .form-grid > label > input,
#botForm .form-grid > label > select { margin-top: 6px; }
#botForm .form-grid-full, #accountForm .form-grid-full { grid-column: 1 / -1; }
/* 「指定商品」跨整行，但它的三個零件（篩選框／選單／同步鈕）橫著排成一列。
   ⭐ 起因（站長 2026-08-24）：「那個選單 應該是在表格裡面 而不是在表格下面 很奇怪」。
      在此之前這一格不只排在全表最後，內部還是【垂直三列】⇒ 在兩欄網格底下自成一大塊，
      看起來就是「掛在表格外面的東西」。
   ⛔ 試過改成佔半格（拿掉 form-grid-full）：那格量到 242px 高而隔壁「分組」只有 56px
      ⇒ 右邊留一大片空白，比原本更不整齊 ⇒ 已放棄，改成「表格中間的一整列」。
   ⚠ 選單那欄要 2fr：option 文字是全表最長的（「MNQU6 — Micro E-mini NASDAQ 100（此帳號已確認）」），
      給 1fr 會把來源標記截掉，而那個標記正是它唯一的安全提示。 */
#botForm .symbol-picker {
  margin-top: 6px;
  gap: 8px 12px;
  /* ⭐ 站長 2026-08-24 講了兩次，第二次是逐字的：
        「你是聽不懂喔 叫你把這兩個框 功能合併成一個框就好」
     ⇒ 篩選框與選單已合併成一個可搜尋的 combobox（index.html：input list + datalist）
     ⇒ 這一列只剩兩個零件：商品框 ＋ 同步鈕。
     ⛔ 這裡刻意【不用 grid】：這段先前累積了三輪互相矛盾的規則，而最後那三行 grid-area
        把選單釘死在第二列 —— 改它上面的任何宣告都不會生效，且每一版都像「CSS 沒載到」。
     ⇒ 一個伸縮 ＋ 一個固定，flex 是最直接的表達；flex-wrap 自帶「窄到放不下就折」
        ＝ 站長要的自適應，⛔ 不必再寫 media query 猜斷點。 */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
/* flex-basis 240px：比這窄的話商品名稱會被切到看不出是哪個月份的合約 ⇒ 寧可折行。
   ⛔ min-width: 0 不可省：flex item 預設 min-width:auto 會被內容撐開，
      長商品名（MNQU6 — Micro E-mini NASDAQ 100（此帳號已確認））會把整列推寬。
   ⭐ 而「被切掉的是什麼」這件事已經在 app.js 那邊治本了：來源標記 ✅ 移到最前面
      ⇒ 任何寬度下先被切掉的都是名稱，⛔ 不會是那個唯一的安全提示。 */
/* ⚠ 2026-08-24 下午：輸入框被包進 .symbol-select-wrap（面板要跟它同寬，見 index.html 的註解）
   ⇒ flex 欄位由 wrapper 接管，輸入框在 wrapper 裡撐滿。
   ⛔ 舊的 `> .symbol-select` 選擇器留著會失效而且看不出來（輸入框不再是直接子層）—— 直接換掉。 */
#botForm .symbol-picker > .symbol-select-wrap { flex: 1 1 240px; min-width: 0; position: relative; }
#botForm .symbol-picker > .symbol-select-wrap > .symbol-select { width: 100%; }
#botForm .symbol-picker > .symbol-picker-actions { flex: 0 0 auto; }
/* 按鈕文字不折行：折成兩行會把整列撐高，而它撐高的是「指定商品」那一整列。 */
#botForm .symbol-picker-actions button { white-space: nowrap; }
#botForm .dialog-actions { margin-top: 16px; }
#botForm .dialog-note { margin: 0 0 12px; }
.bot-wizard-progress { display: grid; grid-template-columns: max-content minmax(32px, 96px) max-content; align-items: center; gap: 12px; margin: 0 0 20px; padding: 0; color: var(--muted); list-style: none; }
.bot-wizard-progress > li { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.bot-wizard-progress > li > span { display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid rgba(151, 166, 224, .35); border-radius: 50%; font-weight: 800; }
.bot-wizard-progress > li.active > span { border-color: #45d9d0; color: #b9fff5; background: rgba(44, 205, 192, .14); }
.bot-wizard-progress > li.done > span { border-color: #45d9d0; color: #07121b; background: #45d9d0; }
.bot-wizard-progress > li > strong { color: #aeb9d8; font-size: 14px; white-space: nowrap; }
.bot-wizard-progress > li.active > strong, .bot-wizard-progress > li.done > strong { color: #e9efff; }
.bot-wizard-progress > i { height: 1px; background: rgba(151, 166, 224, .3); }
.bot-wizard-hidden { display: none !important; }
#botDialog[data-bot-mode="create"] .bot-wizard-page-2 { grid-column: 1 / -1; }

.field-hint {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin-left: 6px;
  border: 1px solid rgba(151, 166, 224, .45);
  border-radius: 50%;
  background: rgba(4, 7, 20, .55);
  color: #9fb0e0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  vertical-align: middle;
  position: relative;
}
.field-hint:hover, .field-hint:focus-visible { border-color: #4fa3ff; color: #cfe2ff; outline: none; }
/* 泡泡本體。⚠ 對話框內容會捲動，所以用 position:absolute 貼著問號本身，
   ⛔ 不用 fixed —— fixed 的泡泡捲動時會留在原地。 */
.field-hint::after {
  content: attr(aria-label);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  /* ⭐ 2026-08-24：固定的 -50%（純置中）在窄視窗會把泡泡推出畫面 ——
     實測 640px 下左溢 9px 與 26px，站長截圖就是這個。
     ⇒ 加一個由 JS 量出來的位移把它推回畫面內（tooltip 的標準做法）。
     ⛔ 預設 0px ⇒ JS 沒跑（或還沒 hover）時行為與改動前完全一樣，不會變更糟。 */
  transform: translateX(calc(-50% + var(--hint-shift, 0px)));
  z-index: 30;
  width: max-content;
  /* 窄畫面下泡泡本身也不該比畫面寬：24px 是左右各留 12px 安全邊。 */
  max-width: min(280px, calc(100vw - 24px));
  padding: 10px 12px;
  border: 1px solid rgba(79, 163, 255, .38);
  border-radius: 10px;
  background: #0d1b2e;
  box-shadow: 0 12px 32px #000a;
  color: #d6e2f7;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.55;
  letter-spacing: 0;
  text-align: left;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s;
  pointer-events: none;
}
.field-hint:hover::after, .field-hint:focus-visible::after { opacity: 1; visibility: visible; }
/* ⛔ 泡泡一律往**上**開。實測（headless 量測 + 截圖）：往下開會正好蓋住這個欄位
   自己的輸入框 —— 使用者滑過去看說明，結果看不到要填的地方。往上開只會蓋到對話框
   標題那一區（那裡沒有需要同時看的東西），且第一排欄位 y≈302 遠低於泡泡高度，
   不會被切掉。 */

.bot-webhook-field .copy-field { margin-top: 6px; }
.bot-webhook-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.bot-webhook-note { color: #8693bc; font-size: 14px; font-weight: 500; line-height: 1.5; }

/* 刪除警告視窗要逐行讀 —— brandConfirm 用 textContent 寫入，沒有這行換行符會被吃掉。 */
.brand-dialog #confirmDialogMessage { white-space: pre-line; }


/* ===== 必填欄位的紅色 ＊（站長 2026-08-19：「將必填寫項目左上角 * 紅色的
   選填則沒有 主流都這樣區分」）=====

   ⛔ 唯一真相源是 HTML 的 `required` 屬性 —— 也就是**送出時真的會被擋下**的那個條件。
      ⛔ 不在 label 文字裡手寫 *：那是第二份判準，拿掉一個 required 時沒有任何東西
      會提醒你星號還留著，而畫面會繼續要求一個其實選填的欄位。
   ⚠ `:has()` 是這裡的關鍵（Electron 43 ＝ Chromium 130+，本檔已用過三次）。
   ⚠ `/ ''` 是 content 的替代文字：`required` 本身已經傳達給輔助技術，
      螢幕閱讀器不需要再唸一次「星號」。
   ⛔ 用 ::before 不是 ::after —— label 是 display:block 且輸入框包在 label 裡面，
      ::after 會把星號掉到輸入框「下面」，而站長要的是「左上角」。 */
label:has(> input[required]),
label:has(> select[required]),
label:has(> textarea[required]) { position: relative; }

label:has(> input[required])::before,
label:has(> select[required])::before,
label:has(> textarea[required])::before {
  content: '＊' / '';
  margin-right: 2px;
  color: var(--red);
  font-weight: 700;
  line-height: 1;
}

/* 同一個 label 同時「建立後不可更改」＋「必填」時（編輯模式的交易帳號／預設口數／
   每點價值就是這一類），一個元素只有一個 ::before ⇒ 上面那條會把 .field-locked 的
   🔒 蓋掉。合併成一串，兩件事都要說得出來。
   ⚠ 🔒 是彩色 emoji 字形，不吃 `color` ⇒ 這串裡只有 ＊ 是紅的，正是要的效果。 */
.field-locked:has(> input[required])::before,
.field-locked:has(> select[required])::before,
.field-locked:has(> textarea[required])::before {
  content: '🔒 ＊' / '';
  font-size: var(--text-xs);
  margin-right: var(--space-1);
}

/* ===== 快訊商品 vs 機器人商品：三級差異警示 =====================================
   站長 2026-08-19：「快訊 NQ 機器人選 NQU6 要顯示有差別、黃色警示；GC 這種差很多的
   要出現紅色警告 —— **但還是能下單**」。⛔ 這組樣式只上色，擋單的邏輯一行都沒有。

   ⛔ 不可只靠顏色傳達（約 8% 男性有紅綠色覺辨識障礙，而黃/紅正好是那一組）：
      徽章一律自帶圖示（⚠／⛔）＋ 文字（有差別／不同商品），灰階列印也讀得出來。
      顏色是**加速辨識**的第三層，不是唯一那層。
   ⭐ match／none 不產生任何徽章 —— 天天亮的綠勾會訓練人不看這一欄，於是真正該紅
      的那一次被一起忽略。這是本功能唯一的失敗模式，比漏報更貴。
   ⚠ 放在檔尾是刻意的：本檔沒有主題切換機制（0 個 data-theme／data-skin），
      同名規則靠先後順序決勝（.delivery-status 就被覆寫過三次）⇒ 檔尾＝最高優先。 */
.symbol-cell { white-space: nowrap; }
.symbol-flag {
  display: inline-flex; align-items: center; gap: var(--space-1, 4px);
  margin-left: var(--space-2, 8px); padding: 2px 8px;
  border: 1px solid transparent; border-radius: 999px;
  font-size: var(--text-xs, 12px); font-weight: 800; line-height: 1.6;
  vertical-align: middle; cursor: help;
}
/* 黃：同一個商品，但寫法／到期月不同，或我們無法確認 —— 值得看一眼，不是錯誤。 */
.symbol-flag.warn {
  border-color: rgba(255, 198, 90, .38);
  color: var(--amber, #f2b84b);
  background: rgba(89, 60, 15, .34);
}
/* 紅的語意只有一個：**這是不同的商品**。⛔ 其他異常一律留在黃色，
   否則紅色天天出現就等於沒有紅色（symbol-mismatch.js 檔頭同一條原則）。 */
.symbol-flag.danger {
  border-color: rgba(255, 98, 121, .42);
  color: var(--red, #ff6279);
  background: rgba(87, 24, 43, .55);
}
@media (max-width: 760px) {
  .symbol-cell { white-space: normal; }
  .symbol-flag { margin-left: 0; margin-top: var(--space-1, 4px); }
}

/* ===== 分頁左上角標題（站長 2026-08-19：「點下去的按鈕文字 要跟左上角的標題一樣」）=====
   八個 panel 的第一個子元素統一成 .section-title。其中 #internal-browse 是 flex column
   （.workbench-stage 靠 flex 分高度，48px 的上外距會直接從舞台身上扣）、#settings 底下
   緊接著自己的 .settings-toolbar —— 這兩處用 .panel-head 把上外距收掉、下外距收緊。
   ⛔ 特異性必須是 (0,2,0)：.section-title 在本檔出現 40+ 次，後面四套佈景（:506 / :794 /
   :1147 / :1424）各自重設過 margin，(0,1,0) 的規則寫在這裡也贏不了它們。 */
.section-title.panel-head { margin-top: 0; margin-bottom: var(--space-3, 12px); }

/* Shared key input controls, used by the API access key. */
.key-field { position: relative; display: block; margin-top: 8px; }
.key-field input { margin-top: 0; padding-right: 52px; }
.key-field-clear {
  position: absolute; top: 50%; right: 8px; transform: translateY(-50%);
  width: 34px; min-width: 34px; height: 34px; min-height: 34px; margin: 0; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: #6f8da8; font-size: 16px; line-height: 1; cursor: pointer;
}
.key-field-clear:hover { color: var(--red, #ff6279); border-color: rgba(255, 98, 121, .35); background: rgba(255, 98, 121, .08); }
.key-field-clear:focus-visible { outline: 2px solid var(--cyan, #19ddff); outline-offset: 1px; }
.key-field-clear[hidden] { display: none; }

/* QW-DESIGN-SYSTEM:BEGIN v0.5.0 — 儀表艙。⛔ 這對哨兵之間是自動替換區，手改會被蓋掉。 */
/* ═══════════════════════════════════════════════════════════════════════════
   0.5.0 儀表艙（Flight Deck）設計系統 — 單一權威層
   來源：design canvas「QuantWing 儀表艙視覺方案」四張板（刻度／主控台／設定／色彩）
   ⛔ 這一段刻意放在檔尾：本檔有五套主題疊加（:root@1 / @401 command-deck /
      @734 orbital / @1517 deck / @1947 aurora），同 specificity 時**最後一條贏**。
      新的元件規則放這裡才會生效 —— 改前面幾套是白改（實例：.bot-head h3 全檔
      宣告 6 次，只有第 6 條 @3071 在生效，@2219 那條 30px 被靜默廢掉）。
   ⭐ 本層是**收斂**不是第六套主題：每加一條就刪掉被它取代的舊宣告。
      ⛔ 下一個人要改視覺請改這裡，不要再往後面疊。

   ⚠ 施工當下實測推翻了 design 的幾個現況數字，本層照**實測**做，不照 design 的數字：
      · 指標卡圓角 18px（design 說 22）／高 160px（說 184）／內距 24px（說 64）
      · 指標卡標籤字重 700 比數值的 620 還**重** —— 標籤在字重上贏了數值
        （⚠ 更正：我一度回報標籤是 18px，那是量錯的——`.metric span` 的第一個
          是圖示 span 不是標籤。標籤字級本來就是 14px，**design 這個數字是對的**，
          真正要動的只有字重與字距。）
      · 徽章早就是中文，五態實測 86/86/86/102/102 = 1.19 倍（design 說 2.6 倍，
        那是它的量測頁沒跑 app.js、餵自己編的英文字串量出來的）
      · 真正會爆版的是第六態 .reconciling（258px），design 沒發現
      · design 的 56px／44px 都會讓金額被**靜默裁切**（見下方指標卡與機器人卡兩段）
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── 型階：用途命名的七檔（design 01 刻度）───────────────────────────
     ⛔ 跟 :root@1 那組 --fs-sm…4xl（數值命名）不同用途：那組是尺寸階，
        這組是**刻度**——每一檔綁定一個用途，用途決定字級，不是反過來。
     ⭐ 核心比值：卡內數值 ÷ 標籤 = 32/14 ≈ 2.3 倍（改前 18/16 = 1.125 倍）。
        「字大」來自這個落差，⛔ 不是每個字加 2px。 */
  --fs-label: 14px;        /* 標籤（下限·站長 2026-08-22 定） */
  --fs-body: 18px;         /* 內文、說明、輸入值 */
  --fs-card-title: 22px;   /* 卡片標題 h3 */
  --fs-section: 28px;      /* 區段標題 h2 */
  --fs-stat: 32px;         /* 卡內數值 */
  --fs-page: 40px;         /* 頁標題 h1 */
  --fs-metric: 56px;       /* 指標卡數值 */

  /* ── 字重四檔（改前全檔 18 種：300…900）─────────────────────────── */
  --fw-body: 400;
  --fw-label: 600;
  --fw-value: 650;
  --fw-badge: 800;

  /* ── 色彩：1 品牌 ＋ 4 語意 ＋ 6 階中性（design 04）─────────────────
     ⭐ 全部映射到既有 token，⛔ 不新發明顏色：--accent 就是既有的 --violet
        (#9d7cff)，只是從「第二張卡的裝飾色」升格成唯一品牌色。
     ⛔ 顏色只有一個工作：告訴我這件事要不要緊。
        顏色一旦有裝飾用途，就再也不能用來報警。 */
  /* ⚠⚠ 定義 --accent 這個動作本身有一處**靜默副作用**：檔案裡已經有人在用
     `var(--accent, #4c8dff)`（AI 輔助的供應商選中框），它今天是靠 fallback 的**藍**活著。
     一旦 --accent 有了定義，那個 fallback 就不再生效 ⇒ 邊框變紫、底色卻還是寫死的藍。
     ⇒ 本層下面有一條把那格的底色一起接上 --accent，⛔ 兩條要一起在，缺一個就配色打架。 */
  --accent: var(--violet, #9d7cff);
  --ok: var(--green, #72f2c3);       /* 在跑・獲利 */
  --warn: var(--amber, #ffd37a);     /* 待確認・演練 */
  --danger: var(--red, #ff708e);     /* 錯誤・虧損・鎖定 */
  --info: var(--cyan, #78e5ff);      /* 連線中・唯讀 */

  --n0: var(--bg, #050611);          /* 底 */
  --n1: var(--surface, rgba(13, 17, 39, .93)); /* 卡 */
  --n2: rgba(24, 30, 62, .92);       /* 浮層（新增：收斂散在檔裡的近似深藍） */
  --n3: rgba(163, 174, 255, .2);     /* 分隔（= 既有 --border） */
  --n4: var(--muted, #8e96bb);       /* 次要字 */
  --n5: var(--text, #f3f4ff);        /* 主字 */

  /* ── 圓角四檔封頂（design 03）───────────────────────────────────
     ⚠ 只套用在 design 點名的元件上。全檔 241 條 border-radius 裡大宗是
        2px(33)／3px(37)／4px(27)，那些是分隔線、光點、進度條這類微裝飾，
        ⛔ 強行拉到 8px 會讓它們變形 —— 收斂的是**卡片級**的值（26/22/18/15/13/11）。 */
  --radius-pill: 999px;
}

/* ── 型階套用 ────────────────────────────────────────────────────── */

/* 頁標題。⛔ 這是左上角那顆「總覽」，不是區段標題。 */
.section-title h1 {
  font-size: var(--fs-page);
  font-weight: var(--fw-value);
  line-height: 1.1;
  letter-spacing: -.02em;
}

/* 區段標題（「交易機器人」）。
   ⭐ 改前實測 20px/610，比它管的 .bot-head h3 (24px) 還**小 4px** ＝ 階層反轉。
      這一條把它重新蓋回 h3 之上。 */
.section-title h2 {
  font-size: var(--fs-section);
  font-weight: var(--fw-value);
  line-height: 1.15;
  letter-spacing: -.015em;
}

.section-title p {
  font-size: var(--fs-body);
  font-weight: var(--fw-body);
  color: var(--n4);
}

/* 卡片標題。⚠ 這是**降**（24→22）不是升 —— 讓區段標題 28px 拿回層級。 */
.bot-head h3,
.bot-name {
  font-size: var(--fs-card-title);
  font-weight: var(--fw-value);
  letter-spacing: -.01em;
}

/* 卡片副標（TXFH6・元大模擬）。
   ⭐ 這一條是**對比修正**不是造型：改前 rgb(127,136,170) 坐在卡片實際底色
      rgb(29,38,74) 上，用截圖取樣量到 **4.20:1 < AA 4.5**。
   ⚠ design 的對比表把這列標成「5.89 過」，但它自己註明背景是拿**頁面底色**算的
      ——卡片比頁面亮 ⇒ 真實值只會更低。它預言了「5.89 這列可能落在 AA 邊緣，
      需要在真的 app 裡再量一次」，這次量了，確實不過。 */
.bot-head p,
.bot-meta {
  color: var(--n4);
}

.form-card h2,
.subsection-heading h3 {
  font-size: var(--fs-card-title);
  font-weight: var(--fw-value);
}

/* ── 指標卡（金融儀表板密度）────────────────────────────────────────
   2026-09-04：完整保留幣別、正負號、千分位與小數，不用 K／M 縮寫犧牲精度。
   四欄桌面依視窗寬度在 27–30px 間微調；切成 2×2 後有足夠欄寬，回到 30px。 */
.metric .metric-reading > strong,
.metric > strong {
  /* ⛔⛔ 這裡**不是** design 說的 56px，而且是被實測擋下來的，不是我保守：
     `.metric` 有 overflow:hidden、`.metric-reading` 是 flex nowrap
     ⇒ 放不下不是換行，是**靜默裁切**（沒有省略號、沒有 title、沒有任何徵兆）。
     真實金額格式是 app.js:1804 `money()` = `-$` + toFixed(2)，**無千分位**
     ⇒ 最長會出現 `-$1234567.89`（12 字元）。
     實測（真 Chromium，六種視窗寬度，electron.js:795 預設開 1520、允許縮到 1100）：
       56px → 1920/1600/1520/1440/1280/1100 **全部裁切**
       48px → 1440/1280/1100 裁切
       40px → 1280/1100 裁切
       36px → 只有 1100 裁切（＝**現況**）
     ⛔ 56px 在 1100px 下把 `-$123456.78` 與 `-$1234567.89` 都切成「-$12345」——
        兩個相差 10 倍的損益長得一模一樣，而且都是合法數字。這是交易軟體，不能這樣。
     ⇒ 取「任何寬度都不比現況更容易裁切」為硬條件：≥1440px 給 40px，其餘退回 36px。
     ⭐ 落差改由**標籤**扛：標籤 18px→14px ⇒ 比值從 36/18 = 2.0 拉到 40/14 = 2.86。
        「字大」的來源是落差，⛔ 不是把數值撐到會切掉自己。
     ⚠ 記債：**現況 36px 在 1100px 也會裁**（need 219 / have 189）—— 那是既有問題，
        本輪沒有讓它更糟，但也沒有解決它。真正的根治是讓它放不下時縮小或換行。 */
  font-size: clamp(27px, 1.85vw, 30px);
  font-weight: var(--fw-value);
  line-height: 1;
  letter-spacing: -.03em;
  /* 數字等寬 —— 每 2 秒就地改寫的數值不等寬會左右跳動 */
  font-variant-numeric: tabular-nums;
}

@media (max-width: 1439px) {
  .metric .metric-reading > strong,
  .metric > strong { font-size: 30px; }
  /* ⭐⭐ 這一條才是指標卡那邊真正的根治。
     四張卡擠在一排時，1440px 以下每格內容區只剩 234px（1100px 更只有 189px），
     而最長金額 `-$1,234,567.89` 在 36px 下需要 236px ⇒ **必切**。
     ⛔ 再往下調字級沒有用：1100px 下連 32px 都要 210px，還是超過 189px。
        ⇒ 這不是字級問題，是**一排塞四張卡**在窄視窗下本來就不成立。
     ⇒ 窄視窗改 2×2。卡片寬度直接翻倍（1280px 下 536px、1100px 下 446px）
        ⇒ 完整金額綽綽有餘，字級也不必再退。
     ⚠ 代價是指標區從一列變兩列、機器人清單被往下推 —— 這是刻意換的：
        **寧可多捲一點，也不要看到一個被切掉、但仍然合法的金額。** */
  .metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ⚠ text-transform: uppercase 對中文是**空操作** —— 繁中介面下「持倉」不會變成
   任何東西。design 的「標籤全大寫＋字距」在中文介面有一半不會發生。
   ⇒ 中文的標籤區隔靠：字級落差 ＋ 字重差 ＋ 顏色差 ＋ **字距**（中文有效）。
      uppercase 保留是為了英文介面（i18n 有 en），對中文無害。 */
.metric .metric-label > span {
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--n4);
}

/* 單位（個／口／點）降一階，⛔ 不跟著數值放大 */
.metric .metric-reading > small,
.metric .metric-reading > .metric-unit {
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  color: var(--n4);
}

/* ⭐ 四張卡共用同一個色調 ＝ design 04 的核心主張落地。
   改前 tone-cyan/violet/blue/green 讓「綠色」只代表「排第四張」。
   ⛔ 不刪 class、不刪 --tone 機制：--tone 是整張卡的視覺骨架（16 處 var(--tone)：
      邊框、背景漸層、頂部光條、beacon、數值色），清空會讓 color-mix() 整條失效。
   ⇒ 只讓四張卡落回同一個值。 */
.metric.telemetry-card,
.metric.telemetry-card.tone-cyan,
.metric.telemetry-card.tone-violet,
.metric.telemetry-card.tone-blue,
.metric.telemetry-card.tone-green {
  --tone: var(--accent);
  border-radius: var(--radius-lg, 16px);
}

/* ── 機器人卡：四格分兩層 ────────────────────────────────────────
   ⛔⛔ 用 `[data-stat="…"]` **不是** `:nth-child`：app.js:4016 的註解明說
      「改欄位順序不影響（updateBotCardNumbers），但刪掉 data-stat 就等於讓數字停更」
      ⇒ 這個產品的定位錨是 data-stat，位置是可變的。
      我第一版用 nth-child ⇒ 任何人調順序，樣式就會套到錯的欄位上，而且畫面不會報錯。

   ⭐ 分層依據被紅隊改過一次，這裡記錄理由：
      design 5.2 主張「未實現／持倉放大，最新價壓小」。⛔ 這個分法把因果倒過來了 ——
      **最新價格是唯一每 2 秒真的在跳的欄位**（app.js:328 write('[data-stat="price"]')），
      未實現損益是**由它算出來的衍生值**；而「持倉」是「多 3／空倉」這種幾分鐘才變一次
      的狀態值。用大字顯示不動的「空倉」、用灰色小字顯示一直在跳的價格，
      掃視時眼睛會被不動的那個吸走。
   ⇒ 改成：**會跳的兩個（未實現／最新價）在上層，設定與狀態（持倉／指定商品）在下層。**

   ⚠ 字級 20px 也是被實測擋下來的，不是我保守：`.bot-stats div` 有 overflow:hidden，
      2 欄 grid 每格內容區 1920px 下只有 **97px**。實測 `-$123456.78`：
        32px → 需 196px（1920 起全部視窗裁切）／24px → 需 148px／20px → 需 123px
        18px（**現況**）→ 需 111px ⇒ **現況本來就在裁**（1920/1600/1280）。
      20px 的裁切範圍與現況 18px **完全相同** ⇒ 不比現況更糟，而落差從 1.125 提到 1.43。
   ⚠ 記債：這一格放不下六位數金額是**既有問題**（overflow:hidden 靜默截斷）。
      真正的根治是讓「未實現」跨兩欄拿到 206px，那是版面改動，本輪沒做。 */
/* ⭐⭐ 根治「金額被靜默切掉」：讓**未實現**跨滿兩欄。
   改前是 2×2，每格內容區在 1920px 下只有 **97px** —— 那裡塞不下任何六位數金額，
   連現況 18px 都在切。⛔ 這不是字級問題，是**格子太窄**。
   跨欄後有 **206px**，完整的 `-$1,234,567.89` 放得下 ⇒ 不必犧牲精度也不必縮字。
   版面變成三列：
     [ 未實現（跨兩欄·大） ]
     [ 最新價 ] [ 持倉 ]
     [ 指定商品（跨兩欄·小） ]
   ⚠ 卡片會長高約一列，⛔ 這是刻意換來的 —— 站長要「字大」，而字要大就得有地方放。 */
.bot-stats > div:has([data-stat="pnl"]),
.bot-stats > div:has([data-stat="price"]) {
  grid-column: 1 / -1;
}

/* ⚠ 為什麼**最新價格**也要跨欄：第一版只讓未實現跨欄，實測（1920px 三欄卡片）
   剩下那兩格各只有 89px，而 `23418.00` 在 20px 下需要 96px ⇒ **最新價被切成
   「23418.…」**。它是每 2 秒在跳的即時價格，切掉它跟切掉損益一樣不能接受。
   ⇒ 版面定案（**兩個會跳的數字各佔一整列，兩個幾乎不動的併一列**）：
     [ 未實現（跨欄·28px） ]
     [ 最新價（跨欄·20px） ]
     [ 持倉 ]  [ 指定商品 ]
   ⭐ 持倉是「多 3／空倉」、指定商品是設定值 —— 它們短、又幾乎不變，併一列剛好。 */

.bot-stats [data-stat="pnl"] {
  font-size: 28px;
  font-weight: var(--fw-value);
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.bot-stats [data-stat="price"] {
  font-size: 20px;
  font-weight: var(--fw-value);
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.bot-stats [data-stat="side"],
.bot-stats [data-stat="symbol"] {
  font-size: 16px;
  font-weight: var(--fw-label);
  line-height: 1.2;
  color: var(--n4);
}

/* ⛔⛔ 截斷必須**看得見**。
   改前這些格子是 `overflow:hidden` 而已 ⇒ 放不下就直接切掉，沒有省略號、沒有任何徵兆
   ⇒ `-$1234567.89` 被切成「-$12345」，而那**仍然是一個合法金額**，使用者不會知道。
   ⭐ 主流作法（Carbon Design System）：截斷一律配省略號**＋ hover tooltip 顯示完整值**。
      title 由 app.js 的 updateBotCardNumbers 跟著每 2 秒的更新一起寫（⛔ 不能只寫 textContent，
      否則 tooltip 會停在第一次的值 —— 那比沒有 tooltip 更糟）。
   ⇒ 這一條讓「切掉」變成「看得出來被切了，而且移上去看得到完整的」。 */
.bot-stats strong,
.metric .metric-reading > strong {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bot-stats span {
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--n4);
}

.bot-stats > div {
  border-radius: var(--radius-md, 12px);
}

/* 卡片圓角統一（改前實測 26px；同一張卡上有 26/16/15/13/12/999 六種） */
.bot-card,
.card,
.form-card,
.module-card {
  border-radius: var(--radius-lg, 16px);
}

/* ⭐ 狀態靠左緣色條表達 ⇒ 卡片列表遠看就分得出誰在跑，不必逐張讀徽章。
   ⛔ **不能用偽元素**：這張卡的兩個都被佔走了 ——
      `::before` 是卡片頂部那條漸層光條（643/922/1436，跟指標卡同一個視覺語彙），
      `::after` 是右上角的模組編號（`data-module="TRADING UNIT / 01"`，1719 開啟）。
      我第一版用了 ::before ⇒ 把頂部光條**靜默換掉**了，截圖才看出來。
   ⇒ 改用 border-left。⚠ 我原本以為 border 會撐大版面 —— 這份檔第 61 行有全域
      `* { box-sizing: border-box }` ⇒ 外部尺寸不變，只吃掉 2px 內部空間（原本就有
      1px 透明邊框），肉眼看不出來。 */
.bot-card {
  border-left: 3px solid var(--n3);
}

.bot-card:has(.badge.running) { border-left-color: var(--ok); }
.bot-card:has(.badge.connecting) { border-left-color: var(--info); }
.bot-card:has(.badge.awaiting_verification) { border-left-color: var(--warn); }
.bot-card:has(.badge.reconciling) { border-left-color: var(--warn); }
.bot-card:has(.badge.error) { border-left-color: var(--danger); }

/* ── 狀態徽章 ────────────────────────────────────────────────────
   實測（用 app.js:botStatusLabel 的**真值**，不是自己編的英文）：
     運行中 86 ／ 已停止 86 ／ 連線中 86 ／ 等待驗證 102 ／ 連線錯誤 102 ＝ 1.19 倍
   ⇒ design 說的「2.6 倍、改成中文三字」**已經是現況**，不需要改文案。
   真正的兩個問題：
   ① connecting／awaiting_verification／error 三態的 border-color 是**透明**的
      ⇒ 同一組元件出現兩種長相（running／stopped 看得見邊框）。
   ② ⭐ 第六態 .reconciling 是「訂單結果待確認・不會自動重送」14 個字 ＝ **258px**，
      而 .bot-head 只用 padding-right 讓出 142px、.badge 又是 absolute right:0
      ⇒ **溢出 116px 直接蓋住機器人名稱**，偏偏那是最需要看清楚是哪台機器人的時刻。 */
.badge {
  min-width: 102px;
  justify-content: center;
  border-radius: var(--radius-pill);
  font-size: var(--fs-label);
  font-weight: var(--fw-badge);
}

/* ⚠⚠ 每一態都必須**自己帶 color**，而且要寫成 #rrggbb 字面 —— 這不是我囉嗦，是
   test/runtime-ux-recovery.test.js:238 的 `lastDeclaration()` 釘死的：它只讀
   **最後一條**同名規則（理由寫在它上面的註解：「.badge.stopped 有三處宣告，只有最後
   一條在畫面上，所以 grep 整個檔案的斷言會在沒人看得到的規則上開心通過」——
   跟本層存在的理由是同一件事）。
   ⇒ 我這一層一旦成為最後一條，就繼承了「說清楚顏色」的責任。只寫 border-color
     會讓那條測試判定「the winning rule sets no color」而紅（我第一版就是這樣被擋下的）。
   ⛔ 不能改用 var()：那條測試的 rgb() 只認 #rrggbb，var() 會讓它 throw。
   ⛔ 這五個值是**實測現況**（Chromium 計算樣式），不是重新調色 —— 顏色一個都沒改，
     只是把它們搬到 winning rule 上。
   ⭐ 那條測試守的是「已停止 ≠ 故障」：0.3.40 曾把 .stopped 塗成 #ff9daf，
     跟 .error 一模一樣（CIEDE2000 = 0.00）⇒ 顏色在那裡不帶任何資訊。 */
.badge.running { color: #83f7c3; border-color: color-mix(in srgb, var(--ok) 46%, transparent); }
.badge.stopped { color: #aeb8e8; border-color: color-mix(in srgb, var(--n4) 46%, transparent); }
.badge.connecting { color: #77d9ff; border-color: color-mix(in srgb, var(--info) 46%, transparent); }
.badge.awaiting_verification { color: #ffd77b; border-color: color-mix(in srgb, var(--warn) 46%, transparent); }
.badge.error { color: #ff9daf; border-color: color-mix(in srgb, var(--danger) 46%, transparent); }

/* ⭐⭐ 徽章**全部**改回參與排版，⛔ 不再絕對定位。
   改前：`.bot-head .badge` 是 `position:absolute; right:0`，靠 `.bot-head` 的
   `padding-right: 142px` 讓位 —— 那是一個**寫死的寬度**，只要徽章比它寬就直接蓋住標題。
   ⚠ 我第一版只把讓位從 142px 收到 118px（照中文徽章實測的 102px 量的），
     那在繁中介面剛好，但 **i18n 有 en locale** 而 `.badge` 帶 `text-transform: uppercase`：
       RUNNING / STOPPED 102px ✅
       CONNECTING 122.5px ⇒ 蓋掉標題 4.5px
       CONNECTION ERROR 172.6px ⇒ 蓋掉 54.6px
       AWAITING VERIFICATION 214.3px ⇒ **蓋掉 96.3px**
     ⛔ 被蓋掉的正好是「連線中／連線錯誤／等待驗證」——**你最需要知道是哪一台出事的三個時刻**。
   ⇒ 治本：`.bot-head` 本來就是 `display:flex; justify-content: space-between`，
     徽章當 flex item 自然靠右，而 `.bot-identity` 有 `min-width: 0` 可以收縮
     ⇒ 長徽章會把標題**壓窄**（標題本來就有 line-clamp 2 行），⛔ 而不是蓋住它。
     這樣任何語言、任何長度都不會再蓋到標題，也不需要維護那個寫死的數字。 */
.bot-head {
  /* ⚠ nowrap 是刻意的：先前用 wrap，結果**標題長的卡片徽章掉到下一行、短的留在右上**
     ⇒ 同一排卡片徽章高低不一（截圖看得很清楚）。徽章的位置應該由版面決定，
     不該由機器人名字有多長決定。
     ⇒ nowrap ＋ 標題可收縮（.bot-identity 本來就有 min-width: 0，且 .bot-name 有
       line-clamp 2 行）⇒ 徽章永遠在右上、標題最多被壓窄，**但不會被蓋住**。 */
  flex-wrap: nowrap;
  padding-right: 0;
  gap: 12px;
}

.bot-head .badge {
  position: static;
  flex: 0 0 auto;
  align-self: flex-start;
}

/* 卡面「全啟」開關（站長 2026-08-28：放進機器人卡，不要長句「關閉一鍵啟動功能」）。
   跟右上狀態徽章同一排；金色＝跟一鍵全啟那顆同一血統（既有 --amber），關掉就退成中性。
   ⚠ 它是按鈕，標題列拖曳已經排除 button，按它不會被當成拖卡片。 */
.bot-head-flags {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 8px;
  flex: 0 0 auto;
}
.bot-include-start-all {
  min-height: 44px;
  min-width: 56px;
  padding: 0 12px;
  border: 1px solid var(--n3);
  border-radius: var(--radius-pill);
  background: var(--n2);
  color: var(--n4);
  font-size: var(--fs-label);
  font-weight: var(--fw-badge);
  letter-spacing: .08em;
  cursor: pointer;
}
.bot-include-start-all.is-on {
  border-color: color-mix(in srgb, var(--amber, #f2b84b) 55%, transparent);
  color: #f2c75c;
  background: rgba(242, 184, 75, .12);
}
.bot-include-start-all:hover {
  filter: brightness(1.08);
}
.bot-head:has(.badge.reconciling) .bot-head-flags {
  flex: 1 1 100%;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* 只有第六態例外：它是一整句話（258–422px），nowrap 會把標題壓到幾乎沒有
   ⇒ 單獨讓這張卡換行，徽章自己佔滿一行。 */
.bot-head:has(.badge.reconciling) {
  flex-wrap: wrap;
}

/* 第六態 `reconciling` 是「訂單結果待確認・不會自動重送」13 個字，實測 258px
   （視窗越寬越長，量到 290–628px）⇒ 讓它自己佔滿一行，⛔ 不跟標題擠。
   ⛔ 不用 max-width + 省略號：那會把「不會自動重送」這句**安全資訊**截掉。
   ⚠ 這也是為什麼「五態等寬」這個目標在這個產品上本來就不成立 —— 它有第六態。 */
.bot-head .badge.reconciling {
  flex: 1 1 100%;
  min-width: 0;
  margin-top: 12px;
}

/* ── 按鈕 ───────────────────────────────────────────────────────
   ⛔ 焦點環（2px cyan ring ＋ 3px offset）design 自己說「現況本來就做對了」⇒ 不動。
   ⚠ 裸 <button> 實測 border-radius 竟是 0px（被後層規則重設），只有 .primary/
      .secondary/.danger 是 12px ⇒ 沒掛修飾類的按鈕是直角，跟旁邊對不齊。 */
button,
.button {
  border-radius: var(--radius-md, 12px);
  font-weight: var(--fw-value);
}

button:disabled,
.button:disabled,
button[disabled] {
  /* ⛔ 不用整顆 opacity 調降 —— 那會讓底下的卡片紋理透出來 */
  opacity: 1;
  color: var(--n4);
  background: var(--n2);
  border-color: var(--n3);
  box-shadow: none;
  cursor: not-allowed;
}

/* ── 表單 ───────────────────────────────────────────────────────
   改前實測：label 18px/w650、input 也 18px/w650 ⇒ **完全同級**，
   掃視表單時每一行都要重讀才知道哪個是欄位名。
   改後：標籤 14/600 灰、值 18/400 白 ⇒ 眼睛只會停在值上。 */
label {
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  letter-spacing: .08em;
  color: var(--n4);
}

input,
select,
textarea {
  font-size: var(--fs-body);
  font-weight: var(--fw-body);
  color: var(--n5);
  border-radius: var(--radius-md, 12px);
}

/* ── 網址／指令的唯讀顯示格 ──────────────────────────────────────
   ⛔⛔ design 說的「Webhook 條」**認錯選擇器了**：`.webhook` 這個 class 在
      index.html 與 app.js 裡**一個都沒有**（`querySelectorAll('.webhook').length === 0`），
      styles.css 卻為它留了 6 條宣告 —— 全是鬼。design 量到的 15px 值是對的，
      但那個值屬於 `.copy-field code`（它們寫在同一條三合一宣告裡）。
   ⚠ 這個坑我自己也踩了兩次：第一版把規則寫給 `.webhook`（＝空操作），
      而且量測夾具**自己造了一個 .webhook 元素** ⇒ 量到的是我編的東西。
   ⚠ 連帶事故：反熵刪除因為比對到 `.webhook` + border-radius，把那條**三合一**
      宣告的圓角刪掉了 ⇒ `.copy-field code` 與 `.connection-line` 一起失去圓角。
      下面這兩條把它補回來，⛔ 而且是補成 design 要的刻度而不是原本的 15px。
   ⇒ `.copy-field code` 實質是唯讀輸入框（API 網址／驗證方式／Webhook 網址共用）⇒ 8px。 */
.copy-field code {
  border-radius: var(--radius-sm, 8px);
}

/* 機器人卡上的「瀏覽器連線」橫條 —— 卡內狀態列 ⇒ 12px。 */
.connection-line {
  border-radius: var(--radius-md, 12px);
}

/* 收斂剩下兩個不在刻度上的卡片級圓角（17px / 13px）。 */
.receiver-status {
  border-radius: var(--radius-lg, 16px);
}

.notice {
  border-radius: var(--radius-md, 12px);
}

/* ── 圓角長尾收斂 ───────────────────────────────────────────────
   ⭐ 這一組不是掃 CSS 檔挑出來的，是**對真 DOM 普查**每個可見元素的 computed
      borderRadius 之後，逐一往上找容器確認身分才決定歸哪一檔的
      （掃檔案會掃到一堆從不渲染的鬼規則 —— 這份檔 241 條宣告裡有大量是死的）。
   ⛔ 刻意**不碰** 2px / 4px / 5px / 6px 那些：它們是分隔線、視窗控制鈕、
      小標籤這類微裝飾，design 的退場清單也沒點名，強行拉到 8px 只會讓它們變形。 */
.entitlement-grid > span { border-radius: var(--radius-md, 12px); }   /* 15px · 會員資訊小格 */
/* ⚠ selector 要寫 .metric-head > .metric-icon：贏家在 styles.css:1144 是
   (0,2,0)，裸 .metric-icon (0,1,0) 排在後面也贏不了（第一版就是這樣沒生效）。 */
.metric-head > .metric-icon { border-radius: var(--radius-md, 12px); }  /* 11px · 指標卡圖示 36×40 */
.alert-fields > div { border-radius: var(--radius-sm, 8px); }          /* 9px  · 欄位小格 */
.account-list-empty { border-radius: var(--radius-lg, 16px); }         /* 18px · 空狀態框 */
td.empty { border-radius: var(--radius-lg, 16px); }                    /* 18px · 表格空列 */
#toast { border-radius: var(--radius-md, 12px); }                      /* 18px · 浮層通知 ⇒ 對話框那一檔 */
pre.alert-shape { border-radius: var(--radius-md, 12px); }             /* 11px · 格式圖 */
.json-template { border-radius: var(--radius-lg, 16px); }              /* 20px · 範例區塊 */
.table-wrap { border-radius: var(--radius-lg, 16px); }                 /* 23px · design 明說表格外框 16 */

/* ── API 金鑰（design 03）────────────────────────────────────────
   ⚠ 2026-08-22 上一輪剛把狀態寫進 placeholder、清除鈕移進欄位內 ⇒ ⛔ 不推翻那個改動。
   ⛔ 遮罩只進 placeholder，**絕不進 value**（進了 value 按儲存會把圓點當新金鑰送出）。
   本層只補 design 要的兩件事：等寬字（遮罩點與尾碼對得齊、位數數得出來）＋ 危險區。 */
#apiKeyMasked,
.api-key-value,
.key-mask,
input[data-key-field] {
  /* 改前用介面字體 ⇒ 遮罩點與尾碼對不齊，也數不出位數。等寬字兩件事都解決。
     ⚠ #apiKeyMasked 是 readonly 顯示欄（app.js:6856 寫入 key.masked），
       ⛔ 不是使用者輸入的欄位 —— 這裡的遮罩在 value 是安全的，因為它送不出去。 */
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: .04em;
}

/* ⛔ 這裡原本有一整組 `.qw-danger-zone`（危險區外框＋外框按鈕）。
   站長 2026-08-22 要求「API Key 寫進欄位裡面，用按鈕來確認和刪除」
   ⇒ 撤銷鍵改用跟 AI 金鑰同一套 `.key-field` 的欄位內 ✕，危險區整組移除（HTML 也拿掉了）。
   ⚠ 誤按的阻力沒有變少：它來自 app.js:7080 的 brandConfirm（danger 二次確認），
     ⛔ 不是來自按鈕擺得遠。 */

/* ⚠ 這一條是上面 `--accent` 那段註解說的配套，⛔ 不可單獨刪：
   `.ai-assist-provider.is-selected` 原本寫 `var(--accent, #4c8dff)` ＋ 寫死的藍底，
   在 --accent 沒有定義的年代靠 fallback 兩邊都是藍、剛好一致。
   本層一定義 --accent，邊框就變紫而底色還是藍 ⇒ 把底色也接上同一個來源。
   ⛔ radio 本身與邊框都要留著：這格不可以只靠顏色傳達選中
      （理由沿用本檔原有註解「⭐ 選中狀態同時給【邊框顏色】與【底色】」那一段，
        ⛔ 不是我新起的規定）。 */
.ai-assist-provider.is-selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

/* ── 窄視窗 ─────────────────────────────────────────────────────
   ⛔ 這一段必須有：本層在檔尾，同 specificity 會蓋掉前面 @media 內的規則。
      不重新宣告的話，窄視窗的調整會被本層的桌面值蓋掉。 */
@media (max-width: 1050px) {
  .metric .metric-reading > strong,
  .metric > strong { font-size: 30px; }
}

@media (max-width: 760px) {
  /* 手機兩欄每格僅約 120px，完整金額必然被切；單欄保留精確數值與可讀點按區。 */
  .metric-grid { grid-template-columns: minmax(0, 1fr); }
  .bot-head { padding-right: 118px; }
  .bot-head:has(.badge.reconciling) { padding-right: 0; }
  .section-title h1 { font-size: var(--fs-section); }
  .section-title h2 { font-size: var(--fs-card-title); }
  .metric .metric-reading > strong,
  .metric > strong { font-size: 28px; }
  .bot-stats > div:nth-child(1) > strong,
  .bot-stats > div:nth-child(2) > strong { font-size: var(--fs-card-title); }
}
/* ── ⛔ 指標卡金額仍被切 —— 實機截圖打臉上一版的「六種寬度全過」───────────
   2026-08-22 重啟後背景截圖（1536px 視窗）：未實現顯示「$0....」、已實現顯示
   「+$1...」⇒ 上一版的 fit.mjs 說全過，真機在切。

   ⭐ 根因是我上一版**量錯了對象**：我只量金額字串本身有多寬，卻沒有把
      **同一行裡的兩個 <small>** 算進去。真實 DOM 是

        <div class="metric-reading">
          <strong>$0.00</strong><small>USD</small><small>本機算・Tradovate 未連線</small>
        </div>

      而 `.metric-reading` 是 `display:flex`（gap 8px）⇒ 那段 12 字的中文說明
      在 14px 下就吃掉約 168px，1536px 四張一排時每張內容區只有約 302px
      ⇒ 剩不到 90px 給金額，40px 的 `$0.00` 需要約 100px ⇒ **必切**。
      （截圖佐證：那段說明自己已經折成兩行，代表它確實在搶寬度。）

   ⛔ 而且我上一版加的 `text-overflow: ellipsis` 讓**錢**成為被犧牲的那一個 ——
      優先順序完全反了：這是交易軟體，該折行的是「資料來源說明」，不是金額。

   ⇒ 修法：來源說明**永遠**獨佔第二行（不是「放不下才換」）。
      永遠換行還順帶解掉一個沒人會注意的毛病：文字在「等待連線 / 本機算 /
      Tradovate 已連線」之間切換時長度不同，若採「放不下才換」，卡片高度會
      隨著連線狀態忽高忽低。

   ⚠ 這兩個 id 是 index.html:163/167 寫死的，⛔ 不用 :last-child —— 那會連
      「個」「口」這種兩字單位也推到第二行，白白多佔一行。 */
.metric-reading { flex-wrap: wrap; }

#metricUnrealizedSource,
#metricRealizedSource {
  flex: 1 0 100%;
  margin-top: 10px;
  line-height: 1.35;
  /* 它是輔助資訊，不該跟金額搶視覺重量 */
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  color: var(--n4);
}

/* 金額拿回整行後仍保留省略號當最後防線（配 title，app.js 每次更新同步寫）。
   tabular + lining numerals 是行情／券商終端常用排法：更新時不左右跳，所有位數同高。
   ⛔ flex item 預設 min-width:auto 會讓 overflow:hidden 失效 ⇒ 必須歸零。 */
.metric .metric-reading > strong {
  min-width: 0;
  max-width: 100%;
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: -.04em;
}

/* QW-DESIGN-SYSTEM:END */

/* ── 尚未指定商品（站長 2026-08-24：指定商品移到「機器人建立後」）────────────
   ⛔ 這是**正常的起始狀態**不是錯誤：建立完成後、還沒選商品之前每一台都會經過它。
   ⇒ 刻意**不**用 .bot-reconciling-warning 那組橘色警示語彙（那組代表「訂單結果待確認」
     ＝真的出事了）。這裡用藍色資訊色，並且**自帶出路**（右邊那顆「指定商品」）——
     一個只說「你少了東西」卻不告訴你去哪裡補的橫幅，等於把問題丟回給使用者。
   ⚠ 顏色是唯一區別時對色盲不成立 ⇒ 文案自己就講得完整（「還不能下單」＋按鈕文字），
     ⛔ 不要把「這是什麼狀態」的資訊只放在顏色上。 */
.bot-symbol-missing {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: 12px 0 16px;
  padding: 14px 16px;
  border: 1px solid rgba(53, 164, 255, .42);
  border-radius: 11px;
  background: rgba(12, 52, 92, .34);
  font-size: var(--fs-sm);
  line-height: 1.45;
}
.bot-symbol-missing > div {
  display: grid;
  gap: 4px;
  flex: 1 1 220px;
  min-width: 0;
}
.bot-symbol-missing strong { color: #cfe8ff; font-size: var(--fs-base); }
.bot-symbol-missing span { color: #9dc2e6; }
/* ⛔ 這顆不縮：它是這張橫幅存在的唯一理由。窄卡片時整顆換行到下一列（flex-wrap），
   ⛔ 不要讓它被壓成一個看不出是按鈕的細條。 */
.bot-symbol-missing button { flex: 0 0 auto; white-space: nowrap; }

/* ===== X 按鈕統一：游標過去就是實心紅底白字（站長 2026-08-24）=====
   「X 關閉的按鈕 全部統一 一律游標過去 背景色變紅 那種方式」——
   「那種方式」指的是標題列 .window-close 本來就有的行為（#d83c52 實心紅底白字）。

   統一之前各自為政：
   · .icon-button（對話框右上角的 ×，全 codebase 只有 3 處、內容全是「×」）—— hover 完全沒有紅
   · .key-field-clear（清除金鑰／撤銷 API Key 的 ✕）—— 只有 8% 透明度的淡紅，幾乎看不出來

   ⚠ 這一段【必須放在檔案最後】：.icon-button 在本檔有三處定義（L314／759／1014），
     寫在它們前面會被後面那兩處蓋掉。同一份 CSS 今天稍早才因為這件事白改三版
     （symbol-picker 的 grid-area）。
   ⛔ 不用 !important：靠位置贏就好 —— !important 會讓下一個要做深色／高對比主題的人無路可走。
   ⭐ 紅色沿用 #d83c52（.window-close 的值），⛔ 不另外挑一個接近的紅：
     兩個「幾乎一樣的紅」在同一個畫面上，看起來就是沒對齊。 */
.icon-button:not(.qf-dialog-navigation-back):hover,
.icon-button:not(.qf-dialog-navigation-back):focus-visible,
.key-field-clear:hover,
.key-field-clear:focus-visible {
  border-color: #d83c52;
  background: #d83c52;
  color: #fff;
}
/* 鍵盤操作要看得出焦點在哪 —— 紅底之外再加一圈，⛔ 不能只靠顏色（色覺障礙者分不出來）。 */
.icon-button:focus-visible,
.key-field-clear:focus-visible {
  outline: 2px solid var(--cyan, #19ddff);
  outline-offset: 1px;
}

/* ⭐ 指定商品的自訂下拉（站長 2026-08-24：「有夠醜 做成一體成形的吧」）。
   ⛔ 一體成形的關鍵是三件事，少一件就又變成「貼在輸入框下面的另一個東西」：
      ① 底色與輸入框【同一個值】（#07131f）  ② 去掉上邊框、只有下方圓角
      ③ 面板寬度 = 輸入框寬度（靠 position:absolute + left/right:0，⛔ 不寫死 px）
   ⚠ 它住在 <dialog> 裡，而 dialog 的 UA 樣式帶 overflow:auto ⇒ 面板會被對話框切
     （同一天的說明泡泡就是這個坑）⇒ 給它 max-height 自己捲，⛔ 不讓它長到被切。
   ⚠ .symbol-picker 是 flex，面板要定位就必須有個 position:relative 的參考框
     ⇒ 那個框是 .symbol-select-wrap（index.html 沒有多一層 div 的話，
        這裡讓 .symbol-picker 自己當參考框：面板 left 對齊到輸入框的 flex 欄）。 */
/* ⛔ 定位參考框是 .symbol-select-wrap 不是 .symbol-picker：後者是整列（含同步鈕），
   面板會橫跨到按鈕下面（實測 562px vs 輸入框 372px）⇒ 那不是一體成形。
   ⚠ wrapper 的 position:relative 寫在上面那條 flex 規則裡（同一處，⛔ 不分兩地）。 */
.symbol-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 40;
  max-height: 264px;
  overflow-y: auto;
  margin-top: -1px;                     /* 蓋掉輸入框的下邊框 ⇒ 接縫消失 */
  background: #07131f;                  /* ⛔ 與 .symbol-select 同一個值 */
  border: 1px solid rgba(25, 221, 255, .75);
  border-top: none;
  border-radius: 0 0 9px 9px;
  box-shadow: 0 18px 38px rgba(2, 8, 18, .55);
}
.symbol-menu[hidden] { display: none; }
/* 面板開著時，輸入框只留上方圓角 ⇒ 兩者是同一塊。 */
.symbol-select[aria-expanded="true"] {
  border-radius: 9px 9px 0 0;
  border-color: rgba(25, 221, 255, .75);
}
.symbol-option {
  display: grid;
  gap: 2px;
  padding: 10px 14px;
  cursor: pointer;
  border-bottom: 1px solid rgba(84, 160, 210, .12);
}
.symbol-option:last-child { border-bottom: none; }
.symbol-option:hover,
.symbol-option[data-active="1"] { background: rgba(25, 221, 255, .09); }
.symbol-option-code { font-weight: 700; color: var(--text); letter-spacing: .2px; }
/* ⭐ 說明只有一行、放得下就不截斷；真的太長才用省略號
   ⛔ 不用 white-space:nowrap 加寬面板：面板一寬就不再與輸入框同寬 ＝ 不是一體成形了。 */
.symbol-option-note { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.symbol-menu-empty { padding: 12px 14px; font-size: 13px; color: var(--muted); }


/* ── 快速下單列（站長 2026-08-24）─────────────────────────────────────────
   買綠賣紅是業界標準配色（Quantower / NinjaTrader / Tradovate 一致）。
   ⛔ 鎖住時【變灰不能按】而不是隱藏：使用者要看得到「它在那裡、只是鎖著」，
      隱藏會讓人以為功能不見了（站長要的原話就是「變灰不能按」）。 */
.bot-quick-trade {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto;
  gap: 8px;
  align-items: stretch;
  margin: 10px 0 0;
}
.bot-quick-trade .qt-side,
.wb-grid-trade .qt-side {
  border: 1px solid transparent;
  border-radius: 9px;
  font-weight: 700;
  font-size: var(--fs-base, 14px);
  letter-spacing: .04em;
  padding: 10px 4px;
  cursor: pointer;
  color: #04120a;
  transition: filter .12s ease, opacity .12s ease;
}
.bot-quick-trade .qt-buy, .wb-grid-trade .qt-buy { background: var(--green, #2ecc71); }
.bot-quick-trade .qt-sell, .wb-grid-trade .qt-sell { background: var(--danger, #e74c3c); color: #1a0505; }
.bot-quick-trade .qt-side:not(:disabled):hover, .wb-grid-trade .qt-side:not(:disabled):hover { filter: brightness(1.12); }
.bot-quick-trade .qt-side:not(:disabled):active, .wb-grid-trade .qt-side:not(:disabled):active { filter: brightness(.92); }
/* 鎖住／未連線 ⇒ 變灰。⛔ 不用 opacity 一招帶過：那會讓文字糊掉，
   而使用者要讀得出上面寫的是「買入」還是「賣出」。 */
.bot-quick-trade .qt-side:disabled,
.wb-grid-trade .qt-side:disabled {
  background: #39414d;
  color: #8b95a3;
  cursor: not-allowed;
}
/* ⛔ 這一組【不綁】.bot-quick-trade：同一個元件也長在工作台的「機器人操作・市價」
   那一列（#workbenchQtyBox）。綁在卡片底下的話，工作台那份會完全沒有樣式。 */
.qt-qty {
  display: grid;
  /* 兩側等寬才不會歪。⚠ 中間用 minmax 而不是固定寬：口數可以到 10000（5 位數）。 */
  grid-template-columns: 32px minmax(48px, 1fr) 32px;
  align-items: stretch;
  border: 1px solid var(--border, #2a3341);
  border-radius: 9px;
  overflow: hidden;
}
/* ⛔ min-height: 0 是承重的，不是多餘（2026-09-12 站長：「口數與 +- 的位置不夠中間，
   太偏下面了」）。本檔頂層有兩條**無條件**的全域規則：
     :3179  button, .button { min-height: 52px; ... }
     :3180  input, select   { min-height: 56px; }
   而這個盒子的子項高度**本來就該由盒子決定**（.qt-qty 是 grid + align-items: stretch）。
   工作台舞台側欄把盒子設成 height: 46px，於是 52/56px 的最小高度勝過 height: 100%
   ⇒ 子項變成 52/56px、往下溢出，被 .qt-qty 的 overflow: hidden 切掉下緣
   ⇒ 圖示與數字在「看得見的那 46px」裡**整體下沉 6px**。
   ⚠ 旁邊的 .qt-side 與 .qt-lock 都各自寫了 min-height 擋住那兩條全域規則，
     **只有這裡漏寫** —— 所以只有口數這一格歪掉。
   ⚠ 症狀是「切掉」不是「變高」⇒ 量 height 會看到 46px 很正常，
     要量子項的 getBoundingClientRect() 才看得出它其實是 56px。 */
.qt-qty button {
  display: grid;
  place-items: center;
  /* ⛔ padding: 0 是關鍵：<button> 的瀏覽器預設 padding 在 32px 寬的格子裡會把
     字元推離中心，看起來就是站長說的「+- 位置歪了」。 */
  padding: 0;
  min-height: 0;
  background: transparent;
  border: 0;
  color: inherit;
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.qt-qty .qt-step-icon {
  display: block;
  width: 18px;
  height: 18px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  pointer-events: none;
}
.qt-qty button:hover { background: rgba(255, 255, 255, .07); }
.qt-qty button:active { background: rgba(255, 255, 255, .12); }
.qt-qty input {
  box-sizing: border-box;
  margin: 0;
  padding: 0;                      /* 同上：input 也有預設 padding */
  min-height: 0;                   /* 同上：擋掉頂層 `input, select { min-height: 56px }` */
  border: 0;
  background: transparent;
  color: inherit;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--fs-base, 14px);
  line-height: 1;
  min-width: 0;
}
/* 原生上下箭頭在深色底下很醜、也太小不好點 ⇒ 隱藏，用旁邊那兩顆。 */
.qt-qty input::-webkit-outer-spin-button,
.qt-qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qt-qty input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.qt-qty.is-disabled { opacity: .45; pointer-events: none; }
.qt-lock {
  display: grid;
  place-items: center;
  padding: 0;
  width: 38px;
  border: 1px solid var(--border, #2a3341);
  border-radius: 9px;
  background: transparent;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.qt-lock:hover { background: rgba(255, 255, 255, .07); }
/* 解鎖狀態要一眼看得出來 —— 這是「現在按下去就會真的下單」的唯一視覺提示。 */
.bot-quick-trade[data-locked="0"] .qt-lock,
.wb-trade-row .qt-lock[aria-pressed="false"] {
  border-color: var(--green, #2ecc71);
  box-shadow: 0 0 0 1px var(--green, #2ecc71) inset;
}


/* 工作台「機器人操作・市價」那一列 —— 買入 ─ 口數 ─ 賣出 ─ 鎖。
   ⛔ 買賣鍵不准縮小（index.html 的註解：「大顆好按就是它留在這裡的理由」）
   ⇒ 用 auto 給口數與鎖，剩下的空間全留給那兩顆。 */
.wb-trade-row { display: flex; align-items: stretch; gap: 8px; }
.wb-trade-row .qt-qty { flex: 0 0 auto; }
.wb-trade-row .qt-lock { flex: 0 0 auto; align-self: stretch; }
.wb-trade-row .qt-lock:disabled { opacity: .4; cursor: not-allowed; }


/* 口數提示。⚠ 兩態要看得出差別：調整中（還在動）vs 已定案。 */
.wb-qty-hint {
  display: block;
  margin-top: 4px;
  font-size: var(--fs-sm, 12px);
  text-align: right;
  color: #8b95a3;
  transition: color .15s ease;
}
.wb-qty-hint[data-state="settling"] { color: var(--amber, #f0b429); }
/* 「送出去了，但交易頁還沒回報」——⛔ 不能跟 settled 同色：這兩者的差別正是站長
   在意的那件事（上面那格到底變了沒）。琥珀＋閃爍表示【還在追】。 */
.wb-qty-hint[data-state="syncing"] {
  color: var(--amber, #f0b429);
  animation: wb-qty-syncing 1s ease-in-out infinite;
}
@keyframes wb-qty-syncing { 50% { opacity: .55; } }
.wb-qty-hint[data-state="settled"] { color: var(--green, #2ecc71); }
/* 只有【交易頁那一格真的變了】才給綠色 —— 後端把值讀回來比對過才算。 */
.wb-qty-hint[data-state="synced"] { color: var(--green, #2ecc71); font-weight: 600; }
.wb-qty-hint[data-state="failed"] { color: var(--red, #e74c3c); }
@media (prefers-reduced-motion: reduce) {
  .wb-qty-hint[data-state="syncing"] { animation: none; }
}

/* ── 機器人自訴：常駐錯誤區（站長 2026-08-25 傍晚）──────────────────────────
   逐字：「無法自行解決的 用**系統提示＋常駐錯誤顯示** 來讓用戶除錯」
   ＋「先前的錯誤也都要顯示 只是多了 提示 呼叫救援AI 中...」

   ⭐ 顏色**只編碼一件事：誰該出手**。⛔ 不編碼嚴重度 ——
      使用者要的答案是「我現在要不要動手」，不是「這有多糟」。
      · needs-you（human）＝ 琥珀：跟既有的唯讀橫幅、待確認警示同一支血統
      · 機器人處理中（self）＝ 藍：跟連線中的圓點同一支，語意是「在跑，別急」
      · 救援 AI（ai）＝ 紫：⭐ 刻意**不是紅** —— 有人在處理不等於出事了
   ⚠ **`--violet` 只有第三個主題層原本就有**（`#9d7cff`），前兩層是本輪補的（2026-08-25）。
      ⭐ 這段註解自己踩過兩次同一個坑，留著當警告：
        第一版寫「沿用既有的 --amber / --blue / --violet」—— 沒查，錯。
        第二版查了但 `head -6` **截斷**，於是寫成「--violet 當時並不存在」—— 也錯，
        第三層一直都有；我那次補的第三個是**重複定義**、而且排在原有的前面 ⇒ 後者贏 ⇒ 我加的是死碼。
      ⇒ 判準：印集合前先印 `len()`，⛔ 別用截斷過的輸出寫全稱句。
   ⛔ 另外兩個確實是既有的（--amber / --blue）；⛔ 不為這一塊再開別的色票。 */
.bot-diagnostics {
  margin: var(--space-2) 0 0;
  padding: 12px 16px;
  border: 1px solid var(--amber, #f2b84b);
  border-left-width: 3px;
  border-radius: 10px;
  background: rgba(242, 184, 75, .1);
  font-size: var(--text-sm, 14px);
  line-height: 1.55;
}
.bot-diagnostics.tier-self { border-color: var(--blue, #35a4ff); background: rgba(53, 164, 255, .1); }
.bot-diagnostics.tier-ai { border-color: var(--violet, #a98bff); background: rgba(169, 139, 255, .12); }
.bot-diagnostics > strong { display: block; margin-bottom: 6px; color: var(--text, #e8f1fb); }
.bot-diagnostic-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.bot-diagnostic-item { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
/* 「誰該出手」是這一整塊唯一要人一眼看到的東西 ⇒ 它排最前面且是唯一有底色的。 */
.bot-diagnostic-tier {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .1);
  font-weight: 700;
  white-space: nowrap;
}
.tier-human > .bot-diagnostic-tier,
.bot-diagnostic-item.tier-human .bot-diagnostic-tier { color: var(--amber, #f2b84b); }
.tier-self > .bot-diagnostic-tier,
.bot-diagnostic-item.tier-self .bot-diagnostic-tier { color: var(--blue, #35a4ff); }
.tier-ai > .bot-diagnostic-tier,
.bot-diagnostic-item.tier-ai .bot-diagnostic-tier { color: var(--violet, #a98bff); }
.bot-diagnostic-text { flex: 1 1 auto; min-width: 0; color: var(--text, #e8f1fb); }
/* 後端補的上下文（場上有幾個面板、各是什麼商品）—— 給要查的人看，⛔ 不跟主文案搶注意力。 */
.bot-diagnostic-detail { flex: 1 1 100%; color: var(--muted, #8fa8c4); font-size: 13px; }
.bot-diagnostic-age { flex: 0 0 auto; color: var(--muted, #8fa8c4); font-variant-numeric: tabular-nums; }
.bot-diagnostic-more { color: var(--muted, #8fa8c4); }

/* ── 卡片上的診斷槽：**永遠佔位**（站長 2026-08-25）────────────────────────
   逐字：「將它顯示在標題下方 且**固定要有一個空白區域** 這樣才不會變成插入
   讓整個列表位移」

   ⭐ 病灶不是「多了一塊東西」，是**它會來會走**：券商快照每 2 秒一輪，問題出現／
      消失都會重畫卡片 ⇒ 以前那塊「有才插」的警示一出現，它下面的未實現／最新價格／
      持倉／買入賣出**整排往下掉**，同一列的鄰居卡片卻不動。
      ⇒ 兩張卡片的同一個欄位不再對齊，**而使用者的手正停在「賣出」上面**。
   ⛔ 用 height 不用 min-height：min-height 只擋得住「空 ⇄ 一行」，
      擋不住「一行 ⇄ 兩行」，而後者一樣會位移（所以下面 compact 改成不換行）。
   ⚠ 高度用 calc 由字級推出來，⛔ 不寫死 42px —— 這個產品在 100%／125%／150%
      三種縮放下都被驗過，寫死的值只有在其中一種下是對的。
     22px ＝ 上下 padding 16 ＋ tier 膠囊的上下 padding 4 ＋ 上下 border 2。 */
.bot-diagnostics-slot {
  --diagnostic-line: 13px;
  margin: var(--space-2) 0 0;
  height: calc(var(--diagnostic-line) * 1.55 + 22px);
}
/* margin 由槽負責 ⇒ 裡面那塊歸零，否則會頂出槽外又變成位移。 */
.bot-diagnostics-slot > .bot-diagnostics { margin: 0; height: 100%; }

/* 卡片上的緊湊版：⛔ 只有一行 —— 卡片上已經有連線狀態、持倉、損益在搶注意力。
   ⚠ 但「另有 N 個問題」一定要說，⛔ 不可以只顯示一條讓人以為只有一個問題。 */
.bot-diagnostics.compact {
  display: flex;
  align-items: center;
  gap: 8px;
  /* ⛔ nowrap：換行 ＝ 槽被撐破 ＝ 站長這次要根治的位移又回來了。
     ⇒ 擠不下的是文案本身，交給下面的省略號，⛔ 不是換行。 */
  flex-wrap: nowrap;
  padding: 8px 12px;
  font-size: var(--diagnostic-line, 13px);
  overflow: hidden;
}
/* 被擠掉的字仍然查得到：整塊有 title（app.js 給的），hover 看得到全文。 */
.bot-diagnostics.compact .bot-diagnostic-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bot-diagnostics.compact .bot-diagnostic-more { flex: 0 0 auto; white-space: nowrap; }

/* ⚠ 呼叫救援 AI 時的呼吸感 —— 它是「正在發生」的唯一線索（其餘全是靜態文字）。
   ⛔ 只動 opacity：這一塊會跟卡片一起被整批重繪，動 transform 會在重繪時跳一下。 */
.bot-diagnostic-item.ai-calling .bot-diagnostic-tier { animation: diagnosticPulse 1.6s ease-in-out infinite; }
@keyframes diagnosticPulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) {
  .bot-diagnostic-item.ai-calling .bot-diagnostic-tier { animation: none; }
}

/* ── 卡片拖曳排序（站長 2026-08-25 兩輪需求）──────────────────────────────
   第一輪：「自由左右拖曳 從左至右是順序」＋「不要因為加東西變太亂」
   第二輪：「還會畫出一條線 還會自動推擠別張卡片 且是整張卡片被帶走
             其它卡片動態排位置 猶如 iPhone APP 主畫面 拖曳 APP 那樣」

   ⭐ 動的全部是 `transform` 與 `opacity` —— 這兩個屬性由合成器處理，⛔ 不觸發
      重排（reflow）。改 `left/top` 或 `order` 會在每一格重算整個 grid 的版面，
      12 張卡就開始掉幀，而拖曳是全 app 對流暢度最敏感的動作。
   ⚠ 位移量由 JS 算（見 app.js 的 applyShift）—— CSS 這裡只負責**怎麼動**，
     ⛔ 不負責**動到哪**。 */
.bot-head { cursor: grab; }
.bot-grid { position: relative; }         /* 插入線是它的絕對定位子元素 */
.bot-grid.is-drag-sorting { cursor: grabbing; user-select: none; }
/* 拖曳期間關掉 hover 位移 —— 它跟推擠共用 transform，兩者會互相覆蓋，
   症狀是游標經過的卡片會忽然彈一下。 */
.bot-grid.is-drag-sorting .bot-card:hover { transform: none; }

/* ③ 整張卡片被帶走：卡片**本體**跟著游標，⛔ 不是瀏覽器產的半透明快照。
   輕微放大＋傾斜＋加深陰影 ＝「它離開桌面了」，這是 iOS 主畫面拖 App 的語彙。
   ⛔ 不要調 opacity：那正是原生拖放最被詬病的地方（它強制壓到 .8 且不可控），
      而站長要的是「整張卡片被帶走」——被帶走的東西應該是實心的。 */
.bot-card.is-dragging {
  cursor: grabbing;
  z-index: 30;
  box-shadow: 0 26px 60px rgba(0, 0, 0, .55);
  transition: box-shadow 160ms ease;
  will-change: transform;
}
/* ② 推擠 ＋ ④ 動態排位：其他卡片滑到讓位後的那一格。
   ⚠ 只寫 transform 的 transition，⛔ 不寫 `all` —— 卡片上還有連線狀態、獲利顏色
     在變，把它們一起補間會讓數字跟顏色糊成一團。 */
.bot-card.is-shifting {
  transition: transform 230ms cubic-bezier(.2, 0, 0, 1);
  will-change: transform;
}

/* ① 落點那條線。畫在**空出來的那一格**的左緣（JS 定位）。
   ⚠ 用獨立元素而不是卡片的 ::after —— 前一版用 ::after 時撞到
     `.bot-card.module-card::after` 被設成 display:none，整條線靜默消失。
     獨立元素不跟任何既有裝飾共用選擇器，那類衝突從結構上就不會發生。
   ⛔ 顏色沿用既有的 --cyan，不發明第 N 個強調色（站長：不要變亂）。 */
.bot-drop-line {
  position: absolute;
  width: 3px;
  border-radius: 2px;
  background: var(--cyan, #19ddff);
  box-shadow: 0 0 12px rgba(25, 221, 255, .85);
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease, left 180ms cubic-bezier(.2, 0, 0, 1), top 180ms cubic-bezier(.2, 0, 0, 1);
  z-index: 20;
}

@media (prefers-reduced-motion: reduce) {
  /* ⚠ 只關動畫，⛔ 不關功能：拖曳本身照常，卡片仍會到正確的位置，
     只是不補間。這是 reduced-motion 的正確語意（少動，不是少功能）。 */
  .bot-card.is-shifting,
  .bot-drop-line { transition: none; }
  .bot-card.is-dragging { box-shadow: 0 12px 28px rgba(0, 0, 0, .5); }
}

/* ── 刪除分組：游標靠近才變紅（站長 2026-08-25：「游標靠近要變紅色按鈕」）──────
   ⭐ **平時不紅**：它就在分組下拉旁邊，長駐紅色會讓整條工具列看起來像在警告什麼。
      hover 才轉紅 ＝ 使用者把游標移過去的那一刻才知道「這顆是會刪東西的」。
   ⛔ 不改成 class="danger"（那會平時就紅）；⛔ 也不自己調色 —— 直接引用既有 .danger
      那組值（styles.css:98 起 ／ 各主題層 685 / 960 / 1630 / 2067 都有覆蓋），
      不然主題一換這顆就會跟旁邊的危險鍵不同色。 */
#botGroupDelete { transition: background-color .15s ease, border-color .15s ease, color .15s ease; }
#botGroupDelete:hover:not(:disabled) {
  background: linear-gradient(145deg, rgba(87, 24, 43, .8), rgba(46, 17, 30, .9));
  border-color: rgba(255, 85, 120, .55);
  color: #ff9bb0;
}
/* ⚠ 鍵盤使用者也要看得到同一個訊號 —— 只綁 :hover 等於把它藏起來給不用滑鼠的人。 */
#botGroupDelete:focus-visible {
  background: linear-gradient(145deg, rgba(87, 24, 43, .8), rgba(46, 17, 30, .9));
  border-color: rgba(255, 85, 120, .55);
  color: #ff9bb0;
}

/* ── 唯讀浮水印（站長 2026-08-25：「唯讀模式時 要有浮水印在右上角 唯讀」）─────────
   ⭐ 為什麼右上角可以、而「頂端置中」不行：styles.css:3624 那段註解否決的是**置中**
      浮層（實測會蓋掉 Tradovate 的淨值／保證金那一列）。右上角是圖表的留白帶，
      而且這是**半透明浮水印**不是實心橫幅 —— 底下的東西看得穿。
   ⛔ pointer-events:none 是承重的：唯讀模式底下的畫面**仍然要能被機器人操作**，
      而且解除唯讀後使用者第一個動作極可能就是點右上角那一區。
   ⚠ 它與 .wb-stage-readonly 橫幅**兩個都要在**，職責不同：
      浮水印回答「我現在為什麼點不動」（一眼、永遠在視野裡），
      橫幅回答「這是什麼狀態、機器人會不會受影響」（有完整說明文字）。 */
.wb-viewer-readonly {
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 5;
  cursor: pointer;
  padding: 4px 12px;
  border: 1px solid rgba(242, 184, 75, .55);
  border-radius: 6px;
  background: rgba(58, 42, 12, .58);
  color: rgba(255, 214, 138, .92);
  font: 700 13px/1.2 ui-monospace, Consolas, monospace;
  letter-spacing: 2px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
}
.wb-stage-live.is-read-only::before { content: none !important; }
.wb-viewer-readonly[hidden] { display: none; }
.wb-viewer-readonly:hover:not(:disabled) { background: rgba(116, 79, 17, .9); border-color: var(--amber); }
.wb-viewer-readonly:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.wb-viewer-readonly:active:not(:disabled) { transform: translateY(1px); background: rgba(151, 103, 22, .95); }
.wb-viewer-readonly:disabled { cursor: default; }
/* 英文介面：i18n 走的是文字節點與屬性，⛔ 摸不到 CSS 的 content
   ⇒ 用 :lang() 換掉，⛔ 不要把浮水印改成需要 JS 寫入的元素（那會多一條要同步的路）。 */
:lang(en) .wb-stage-live.is-read-only::before { content: 'READ-ONLY'; letter-spacing: 1px; }

/* ══════════════════════════════════════════════════════════════════════════
   AI 求救的隱私揭露 —— 站長 2026-08-25 裁決：「明確寫出來會傳給第三方API 即可」
   ══════════════════════════════════════════════════════════════════════════
   ⛔ 這段要看得見才算揭露。用 .field-help.ai-assist-disclosure 兩個 class 疊出
      特異性（0,2,0），⛔ 不靠「寫在後面就會贏」—— .field-help 在本檔有兩處定義，
      靠順序等於把樣式綁在「誰在下面」這個會被反熵整理弄壞的性質上。
   ⭐ 顏色走既有 --warn token（不新發明顏色），帶 fallback 以防它在某層沒定義。 */
.field-help.ai-assist-disclosure {
  margin-top: 10px;
  padding: 12px 14px;
  border-left: 3px solid var(--warn, #ffd37a);
  border-radius: 0 8px 8px 0;
  background: color-mix(in srgb, var(--warn, #ffd37a) 8%, transparent);
  color: inherit;
  font-size: 14px;
  line-height: 1.65;
}
.field-help.ai-assist-disclosure strong { color: var(--warn, #ffd37a); font-weight: 650; }

/* ══════════════════════════════════════════════════════════════════════════
   複製按鈕統一成圖示 ＋ 金鑰欄位排版（站長 2026-08-26）
   ══════════════════════════════════════════════════════════════════════════
   站長逐字：「API Key 兩顆按鈕黏一起／大改 複製按鈕全部改 複製的圖案 即可 單一
   真相源／API Key 只是在 複製按鈕前 有顆眼睛點了看完整 預設眼睛關的 跟主流一樣／
   複製按鈕不要在 文字框裡面 眼睛才要在文字框裡面」。

   ## ⛔ 真兇：三顆鈕疊在同一個座標上，不是「靠太近」
   `.key-field-clear` 是 `position:absolute; right:8px`。2026-08-26 稍早往同一個
   `.key-field` 裡塞了 👁 ／ ⧉ ／ ✕ 三顆 —— 三顆都絕對定位在 right:8px
   ⇒ **完全重疊**，畫面上看起來是一坨、而且只有最上面那顆（✕ 撤銷）點得到。
   ⚠ 這種壞法不會有任何錯誤訊息：DOM 三顆都在、都有 aria-label、測試也抓得到，
     只有真的用滑鼠點下去才會發現按到的是撤銷。
   ⇒ 修法是給它們一個 flex 容器（`.key-field-actions`）排隊，⛔ 不是各自調 right 值
     （那等於把「有幾顆鈕」寫死在座標裡，下次再加一顆又要重算一輪）。

   ## 版面（站長指定）
       [ 文字框 ……………… 👁 ✕ ]   [複製圖示]
       └── .key-field（框內）──┘ gap └ 框外，與框並排

   ⛔ 撤銷 ✕ 留在框內：站長 2026-08-22 明說「寫進欄位裡面，用按鈕來確認和刪除」，
      2026-08-26 這輪只點名了「複製」要出去、「眼睛」要進來 ⇒ 不動它。 */

/* 框內的操作鍵排成一列。⛔ 只有這個容器負責定位，裡面的鈕一律 static —— 
   否則 `.key-field-clear` 那條 absolute 會讓它們又疊回同一點。 */
.key-field-actions {
  position: absolute; top: 50%; right: 8px; transform: translateY(-50%);
  display: flex; align-items: center; gap: 12px;
}
.key-field-actions .key-field-clear {
  position: static; top: auto; right: auto; transform: none;
}
/* ⛔ gap 不是 6px（站長 2026-08-26 實測後再提）。
   真瀏覽器量到的 6px 是【眼睛右緣 488.19 到撤銷左緣 494.19】——
   兩顆 34px 的鈕中間只隔 6px，而右邊那顆是【撤銷】（不可逆）。
   ⭐ 12px 是本列已經在用的間距：.key-row 的 gap 就是 12px，實測框外複製鈕
     離框也是 12.00px ⇒ 框內、框外同一個節奏，⛔ 不另挑一個差不多的數字。
   ⚠ ⛔ 不能拉到 60px（那是框【外】眼睛到複製的距離）：這兩顆在輸入框【內】，
     拉得越開，遗給金鑰文字的寬度越少，遮罩值會提早被截掉。 */

/* 圖示鈕的 SVG 尺寸。⛔ 別靠上面那條 font-size:16px —— 它只對【✕ 這個文字字元】
   有效；換成 <svg> 之後 font-size 一點作用都沒有，而 SVG 沒寬高時會用 viewBox 的
   24×24 擐滿整顆 34px 的框—— 不會報錯，只會看起來「圖大得很奇怪」。
   ⭐ 18px 是跟旁邊框外複製鈕（19px）對齊的【視覺重量】，⛔ 不是按框寬比例算
     （按比例算出來是 14.6px，兩顆貼在一起時眼睛會明顯比複製小一截）。
   ⚠ pointer-events:none —— 讓點擊一律落在 <button> 上，⛔ 不是落在 <svg>：
     任何用 event.target 判按到哪顆的地方都會因此静默失效。 */
.key-field-clear svg { width: 18px; height: 18px; display: block; pointer-events: none; }

/* 輸入框右側要空出「按鈕總寬 + 兩側留白」的位置，⛔ 否則遮罩文字會被鈕蓋住。
   用 :has() 依實際有幾顆鈕決定，⛔ 不寫死一個數字（加減鈕時不必回來改）。
   ⚠ 98 = 兩顆 34px + 中間 12px + 右側 right:8px + 10px 寬限；
     gap 從 6 改成 12 這一行必須跟著加 6，⛔ 否則遮罩值會被眼睛蓋掉。 */
.key-field:has(.key-field-actions) input { padding-right: 98px; }
.key-field:has(.key-field-actions > :only-child) input { padding-right: 52px; }

/* 金鑰列：文字框 ＋ 框外的複製鈕。gap 就是站長要的「不要黏一起」。 */
.key-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px; align-items: center; margin-top: 8px;
}
.key-row .key-field { margin-top: 0; }

/* ── 複製按鈕：全 app 唯一的一套外觀 ──────────────────────────────────────
   圖案本身（SVG）只有一份，定義在 app.js 的 COPY_ICON_SVG；這裡只管框與狀態。
   ⛔ 不要在這裡再放一份 mask-image 的 SVG —— 那就是第二個真相源。 */
.copy-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  width: 44px; min-width: 44px; height: 44px; margin: 0; padding: 0;
  border: 1px solid var(--border, #23415e); border-radius: 9px;
  background: rgba(7, 19, 31, .72);
  color: #8fc7ec; cursor: pointer;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.copy-icon-btn svg { width: 19px; height: 19px; display: block; pointer-events: none; }
.copy-icon-btn:hover { color: #cfefff; border-color: #2f7fb5; background: rgba(20, 52, 78, .85); }
.copy-icon-btn:focus-visible { outline: 2px solid var(--cyan, #19ddff); outline-offset: 1px; }
.copy-icon-btn:disabled { opacity: .45; cursor: not-allowed; }
/* 已複製：沿用既有的 button.copied 綠（那條帶 !important，⛔ 不要再挑一個接近的綠）。 */
.copy-icon-btn.copied { border-color: #2f9d6a; background: rgba(24, 66, 48, .8); }

/* .copy-field 的第二欄本來是一顆文字鈕（寬度隨字長跑）。改成圖示鈕之後，
   讓它靠上對齊 code 區塊的第一行，⛔ 不要拉伸成跟多行 <code> 一樣高。 */
.copy-field .copy-icon-btn { align-self: start; }

/* 對話框動作列（「複製完整 API Key」那顆）：跟旁邊的主要按鈕等高，
   ⛔ 不要因為變成圖示就縮成一顆小方塊、在一排大鈕旁邊看起來像壞掉。 */
.dialog-actions .copy-icon-btn { height: 48px; min-width: 48px; width: 48px; }

/* ── 機器人卡收斂（2026-08-26）──────────────────────────────────────────
   上半部先前被五套主題疊成：頭 92px、連線列 68px、帳號窗三行、四格統計還把
   未實現／最新價各拉成整列 ⇒ 一張卡還沒到按鈕就比視窗高。
   主流交易面板（FreqUI / PrimeAutomation / 3Commas）是「一行身分＋一列 KPI
   ＋主操作」，次要動作進 overflow ⋯。本層只壓高度，不刪欄位。 */
.bot-card {
  padding: 14px 16px 12px;
}
.bot-head {
  min-height: 0;
  margin: 0;
  padding: 0;
  border-bottom: 0;
  background: none;
}
.bot-head h3,
.bot-name {
  font-size: 18px;
  margin: 0 0 2px;
}
.bot-name-trigger {
  display: -webkit-box;
  width: 100%;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  text-align: left;
  word-break: break-word;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  cursor: text;
}
.bot-name-trigger:hover { color: #ffffff; text-decoration: underline; text-decoration-color: rgba(143, 199, 236, .62); text-underline-offset: 3px; }
.bot-name-trigger:focus-visible { outline: 2px solid var(--cyan, #19ddff); outline-offset: 2px; }
.bot-identity .bot-name.is-editing {
  display: block;
  overflow: visible;
}
.bot-name-input {
  display: block;
  width: min(100%, 360px);
  min-height: 32px;
  height: 32px;
  margin: -4px 0 0;
  padding: 3px 8px;
  border: 1px solid var(--cyan, #19ddff);
  border-radius: 6px;
  background: rgba(3, 12, 25, .92);
  color: #fff;
  font: inherit;
  line-height: 1.2;
  box-shadow: 0 0 0 3px rgba(25, 221, 255, .12);
}
.bot-identity .card-code {
  margin-bottom: 2px;
  font-size: 12px;
  letter-spacing: .6px;
}
.bot-identity .bot-meta {
  font-size: 13px;
  line-height: 1.3;
}
.connection-line {
  min-height: 0;
  margin: 8px 0 0;
  padding: 8px 10px;
  gap: 10px;
}
.connection-line strong { font-size: 13px; margin-top: 0; }
.bot-account-window {
  margin: 8px 0 0;
  padding: 8px 10px;
  gap: 2px;
}
.bot-account-window-name { font-size: 14px; }
.startup-visual-status {
  margin: 8px 0 0;
  padding: 8px 10px;
  gap: 8px;
}
.startup-visual-status small { display: none; }
.bot-stats {
  margin: 10px 0 8px;
  gap: 8px;
}
.bot-stats > div:has([data-stat="pnl"]),
.bot-stats > div:has([data-stat="price"]) {
  grid-column: auto;
}
.bot-stats div {
  min-height: 0;
  padding: 8px 10px;
}
.bot-stats [data-stat="pnl"] { font-size: 20px; }
.bot-stats [data-stat="price"] { font-size: 16px; }
.bot-stats [data-stat="side"],
.bot-stats [data-stat="symbol"] { font-size: 14px; }
.bot-actions {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 8px;
  padding-top: 0;
  align-items: center;
}
.bot-actions button {
  min-height: 36px;
  font-size: 14px;
  padding: 0 12px;
  flex: 1 1 auto;
}
.bot-more {
  flex: 0 0 36px;
  min-width: 36px;
  margin-left: auto;
}
.bot-cloud { margin-top: 8px; font-size: 12px; }

/* 截圖預覽：暗底 lightbox + 滾輪縮放 + 拖曳平移（ImageGlass / Google Photos） */
.shot-viewer {
  position: fixed;
  inset: 0;
  z-index: 12000;
  display: flex;
  flex-direction: column;
  background: rgba(4, 6, 16, .92);
}
.shot-viewer[hidden] { display: none; }
.shot-viewer-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  padding: 8px 12px 8px 16px;
  background: rgba(8, 10, 24, .96);
  border-bottom: 1px solid rgba(163, 174, 255, .16);
}
.shot-viewer-bar > strong {
  min-width: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 600;
  color: #eef1ff;
}
.shot-viewer-tools {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}
.shot-viewer-tools button {
  min-height: 32px;
  min-width: 32px;
  padding: 0 10px;
  font-size: 14px;
}
#shotViewerScale {
  min-width: 52px;
  text-align: center;
  font: 600 13px/1 ui-monospace, Consolas, monospace;
  color: #c5cce8;
}
.shot-viewer-close { flex: 0 0 auto; margin: 0 8px 0 0; } /* 外觀由「〈返回」母版提供 */
.shot-viewer-stage {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
}
.shot-viewer-stage.is-panning { cursor: grabbing; }
.shot-viewer-stage img {
  display: block;
  max-width: none;
  user-select: none;
  pointer-events: none;
}

/* ── 0.3.61 舊工作台版型（0.3.63 已由檔尾單一規則取代）──────────────────
   寬窗格（單格、上下 1:1）使用左側控制艙；窄窗格（左右 1:1、2×2）把同一份
   控制元件 reflow 到上方。沒有第二套 HTML，也不靠 viewport 猜窗格寬度。 */
@media not all {
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) {
  container-type: inline-size;
  display: grid;
  align-items: stretch;
}

:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"][data-split-axis="vertical"] .wb-focus-pane) {
  grid-template-columns: clamp(256px, 23%, 320px) minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "rail notices" "rail canvas";
}

:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  grid-template-areas: "rail" "notices" "canvas" "problem";
}

:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > .wb-stage-notices { grid-area: notices; min-width: 0; }
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > :is(.wb-stage-viewer-layer, .wb-stage-record-layer) {
  grid-area: canvas;
  align-self: stretch;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
}

.wb-stage-rail {
  grid-area: rail;
  z-index: 42;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: auto;
  border: 0;
  border-right: 1px solid var(--border);
  background: linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 52%, var(--surface)), var(--surface));
}

.wb-stage-rail > .wb-stage-head.wb-stage-head {
  display: grid;
  flex: 0 0 auto;
  grid-template-columns: 28px minmax(0, 1fr);
  align-items: start;
  gap: 8px;
  min-width: 0;
  min-height: 0;
  padding: 10px;
  overflow: visible;
  border: 0;
  background: transparent;
}
.wb-stage-head > .wb-pane-drag-handle { align-self: start; width: 28px; height: 44px; }
.wb-stage-head > .wb-pane-picker {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 7px;
  width: 100%;
  min-width: 0;
  height: auto;
  border: 0;
  background: transparent;
}
.wb-stage-head .wb-pane-group {
  width: 100%;
  min-width: 0;
  height: 38px;
  padding-inline: 10px 28px;
  border: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: 13px;
}
.wb-pane-identity-row { display: grid; grid-template-columns: 48px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 0; }
.wb-pane-identity-row > .bot-avatar-button {
  display: grid;
  place-items: center;
  width: 46px;
  min-width: 46px;
  max-width: 46px;
  height: 46px;
  min-height: 46px;
  max-height: 46px;
  margin: 0;
  border-width: 2px;
}
.wb-pane-identity-row > .bot-avatar-button :is(img, .bot-avatar-fallback) { width: 100%; height: 100%; }
.wb-stage-head .wb-pane-bot-picker { position: relative; width: 100%; min-width: 0; }
.wb-stage-head .wb-pane-bot-picker > summary {
  display: flex;
  align-items: center;
  min-height: 46px;
  padding: 0 30px 0 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface-2);
}
.wb-stage-head .wb-pane-current { gap: 8px; }
.wb-stage-head .wb-pane-current strong { color: var(--text); font-size: 15px; font-weight: 750; }
.wb-stage-head .wb-pane-bot-picker > .workbench-tabs {
  inset: calc(100% + 6px) auto auto 0;
  display: grid;
  width: min(320px, calc(100vw - 32px));
  max-height: min(52vh, 420px);
  overflow: auto;
  padding: 5px;
}
.workbench-panel[data-layout="grid"] .wb-pane-picker { min-width: 0; max-width: none; }
.workbench-panel[data-layout="grid"] .wb-pane-bot-picker > .workbench-tabs { left: 0; }

.wb-stage-head > .wb-stage-tools {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) repeat(3, minmax(36px, 44px));
  gap: 6px;
  width: 100%;
  min-width: 0;
  margin: 0;
}
.wb-stage-head .wb-pane-tabs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; }
.wb-stage-head .wb-pane-tabs button,
.wb-stage-head > .wb-stage-tools > button { width: 100%; min-width: 0; height: 40px; min-height: 40px; }
.wb-stage-head .wb-pane-tabs svg { width: 23px; height: 23px; }

:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"][data-split-axis="vertical"] .wb-focus-pane) .wb-stage-tools {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"][data-split-axis="vertical"] .wb-focus-pane) .wb-stage-tools .wb-pane-tabs { grid-column: 1 / -1; }

.wb-stage-rail > .wb-trade-summary {
  position: static;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  margin: 0;
  padding: 10px;
  gap: 8px;
  overflow: visible;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .wb-grid-trade {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(100px, 1.2fr) minmax(0, 1fr);
  grid-template-areas: "buy qty sell" "lock lock lock";
  gap: 6px;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .qt-buy { grid-area: buy; }
.wb-stage-rail > .wb-trade-summary .qt-sell { grid-area: sell; }
.wb-stage-rail > .wb-trade-summary .qt-qty {
  grid-area: qty;
  display: grid;
  grid-template-columns: 32px minmax(32px, 1fr) 32px;
  align-items: stretch;
  width: 100%;
  min-width: 0;
  height: 48px;
  min-height: 48px;
  overflow: hidden;
}
.wb-stage-rail > .wb-trade-summary .qt-qty button { display: grid; place-items: center; width: 100%; min-width: 0; height: 100%; padding: 0; font-size: 18px; line-height: 1; }
.wb-stage-rail > .wb-trade-summary .qt-qty input { align-self: stretch; width: 100%; min-width: 0; height: 100%; padding: 0; font-size: 16px; line-height: 48px; }
.wb-stage-rail > .wb-trade-summary .wb-grid-trade .qt-side { min-width: 0; min-height: 48px; padding: 0 6px; font-size: 15px; }
.wb-stage-rail > .wb-trade-summary .qt-lock {
  grid-area: lock;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  min-width: 0;
  height: 28px;
  min-height: 28px;
  padding: 0 8px;
  border-radius: 7px;
  color: var(--muted);
  font-size: 12px;
}
.wb-grid-trade .qt-lock[aria-pressed="false"] { border-color: var(--green); color: var(--green); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--green) 62%, transparent); }
.qt-lock-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.wb-stage-rail > .wb-trade-summary .wb-stage-metrics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 5px;
  width: 100%;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--surface-2) 88%, var(--surface));
  text-align: left;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric small { color: var(--muted); font-size: 14px; line-height: 1.2; white-space: nowrap; }
.wb-stage-rail > .wb-trade-summary .wb-stage-metric strong {
  max-width: 100%;
  overflow: hidden;
  font-size: clamp(13px, 12cqi, 18px);
  line-height: 1.2;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 左右 1:1 與 2×2：控制艙改在畫面上方。寬窗格時身份／工具與交易摘要並排；
   窄窗格再自然堆疊，永遠優先保住券商畫面的完整寬度。 */
:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > .wb-stage-rail {
  display: grid;
  grid-template-columns: minmax(220px, .9fr) minmax(300px, 1.1fr);
  align-items: start;
  overflow: visible;
  border-right: 0;
  border-bottom: 1px solid var(--border);
}
:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > .wb-stage-rail > .wb-trade-summary {
  align-self: stretch;
  border-top: 0;
  border-left: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}
:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) .wb-stage-metrics {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) .wb-stage-metric {
  grid-template-columns: minmax(0, 1fr);
  gap: 3px;
  text-align: center;
}
:is(.workbench-stage[data-layout="split"][data-split-axis="horizontal"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) .wb-stage-metric strong { text-align: center; }

@container (max-width: 640px) {
  .wb-stage-rail { grid-template-columns: minmax(0, 1fr) !important; }
  .wb-stage-rail > .wb-trade-summary { border-left: 0 !important; border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent) !important; }
  .wb-stage-head > .wb-stage-tools { grid-template-columns: minmax(0, 1fr) repeat(3, minmax(34px, 40px)); }
  .wb-stage-rail > .wb-trade-summary { padding: 8px; gap: 6px; }
  .wb-stage-rail > .wb-trade-summary .wb-grid-trade { grid-template-columns: minmax(0, 1fr) minmax(88px, 1.15fr) minmax(0, 1fr); }
  .wb-stage-rail > .wb-trade-summary .wb-stage-metric { padding: 7px 6px; }
  .wb-stage-rail > .wb-trade-summary .wb-stage-metric small { font-size: 13px; }
}

@media (max-width: 520px) {
  :is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(280px, 1fr);
    grid-template-areas: "rail" "notices" "canvas";
  }
  .wb-stage-rail { overflow: visible; border-right: 0; border-bottom: 1px solid var(--border); }
  .workbench-stage[data-layout="split"][data-split-axis="vertical"] .wb-focus-pane {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(280px, 1fr);
    grid-template-areas: "rail" "notices" "canvas";
  }
}

/* 0.3.74：畫面生命週期修復。
   工具列留出固定空間，身份選單只拿需要的寬度，避免最右側眼睛／全螢幕被蓋住。 */
.wb-stage-rail > .wb-stage-head.wb-stage-head {
  grid-template-columns: 22px minmax(140px, 210px) minmax(0, 1fr);
}
.wb-stage-head > .wb-pane-picker { max-width: 210px; }
.wb-stage-head .wb-pane-combined-picker > summary { padding-right: 24px; }
.wb-stage-head .wb-pane-combined-picker > .workbench-tabs { width: min(270px, calc(100vw - 24px)); }
.wb-stage-head .wb-stage-window-tools { flex: 0 0 auto; }

/* 已有最後成功影格時，啟動圖層絕不能再蓋上來。重連只用右下角小卡回報。 */
.wb-stage-live.is-loading.has-frame .brand-loading-state { display: none; }
.wb-stream-retry-countdown {
  min-height: 1.2em;
  color: var(--amber);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* 全螢幕是完整窗格放大：保留內容頁籤、機器人選擇、交易控制與提示。 */
:is(.wb-focus-pane, .wb-grid-tile).is-fullscreen,
.workbench-stage.is-single-fullscreen {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  grid-template-areas: "rail" "notices" "canvas" "problem";
}
:is(.wb-focus-pane, .wb-grid-tile).is-fullscreen > .wb-stage-rail,
.workbench-stage.is-single-fullscreen > .wb-stage-rail {
  grid-area: rail;
  display: grid;
  grid-template-rows: 48px minmax(58px, auto);
  height: auto;
  overflow: visible;
  border: 0;
  border-bottom: 1px solid var(--border);
}
:is(.wb-focus-pane, .wb-grid-tile).is-fullscreen .wb-stage-viewer-layer,
.workbench-stage.is-single-fullscreen .wb-stage-viewer-layer {
  grid-area: canvas;
  width: 100%;
  height: 100%;
  max-height: none;
  aspect-ratio: auto;
  padding: 0;
}

@container (max-width: 480px) {
  .wb-stage-rail > .wb-stage-head.wb-stage-head {
    grid-template-columns: 20px minmax(0, 1fr);
    grid-template-rows: 36px 36px;
  }
  .wb-stage-head > .wb-pane-picker { max-width: none; }
  :is(.wb-focus-pane, .wb-grid-tile).is-fullscreen .wb-stage-head {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: 40px;
  }
}
}

/* ── 0.3.69 多窗格交易工作台單一版型真相 ────────────────────────────────
   CBUA 裁決：不可逆下單控制維持 pane-scoped，但在所有多窗格一律收進上方兩列。
   不再依窗格寬度把整組控制器搬到左側：搬位會讓操作目標跳動，也會永久犧牲
   券商畫面的寬。2×2 與左右 1:1 的舞台由可視高度決定，內容不得把頁面撐高。 */
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) {
  container-type: inline-size;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  grid-template-areas: "rail" "notices" "canvas" "problem";
  align-items: stretch;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > .wb-stage-notices {
  grid-area: notices;
  min-width: 0;
  /* ⛔ 2026-09-17：舊值是 max-height:64px + overflow:hidden。動機沒錯（不讓告知
     橫幅吃掉券商畫面），但 64px 連一顆按鈕都放不下 —— 實測警示卡需要 162.6px，
     被裁掉 99px，而裁掉的那段正好是使用者**唯一的出口**：那顆確認鍵。
     按鈕中心點做 hit-test 打到的是 wb-stage-img（券商畫面），不是按鈕。
     ⭐ 真正把高度壓下來的是下面 .bot-reconciling-warning 改成單條橫幅那組規則，
        ⛔ 不是這裡的上限 —— 這裡只負責「萬一超出就讓人捲得到」而不是裁掉。
     ⛔ overflow 用雙值 `hidden auto`，⛔ 不可寫成 overflow-y: auto：
        那樣 overflow-x 會依規範從 visible 被**計算成 auto**，窄窗格會多一條水平捲軸。
     ⛔ max-height 不可改百分比：notices 所在的 grid 軌道是 auto，百分比高度會循環
        解析而**靜默退化**成 auto —— 不報錯、computed 值還看起來對，只有人眼看得出不對。 */
  max-height: 128px;
  overflow: hidden auto;
  overscroll-behavior: contain;
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > :is(.wb-stage-viewer-layer, .wb-stage-record-layer) {
  grid-area: canvas;
  align-self: stretch;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile) > .wb-stage-problem-layer {
  grid-area: problem;
  z-index: 46;
  align-self: end;
  justify-self: stretch;
  min-width: 0;
  padding: 8px;
  pointer-events: none;
  background: transparent;
}
.wb-stage-problem-layer[hidden] { display: none !important; }
.wb-stage-problem-layer .wb-stage-problem-strip {
  width: 100%;
  margin: 0;
  padding: 10px 14px;
  border: 1px solid color-mix(in srgb, #f4c653 74%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, #171108 88%, transparent);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .34);
  backdrop-filter: blur(16px) saturate(135%);
}
.wb-stage-problem-layer:not([hidden]) { display: grid; gap: 6px; }
.qf-price-warning {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 2px 8px;
  min-width: 0;
  margin: 8px 0 2px;
  padding: 7px 9px;
  border: 1px solid rgba(244, 198, 83, .65);
  border-radius: 8px;
  background: #211b12;
  color: #f9deb0;
  font-size: 12px;
  line-height: 1.4;
}
.qf-price-warning[hidden] { display: none !important; }
.qf-price-warning strong { flex: 0 0 auto; color: #ffd56a; }
.qf-price-warning span { flex: 1 1 170px; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .qf-price-warning { width: 100%; box-sizing: border-box; }
  .wb-stage-problem-layer .wb-stage-problem-strip { padding: 7px 9px; gap: 3px 7px; font-size: 12px; }
  .wb-stage-problem-layer .wb-stage-problem-strip > span { flex-basis: 100%; }
}
/* 問題列已有獨立自動高度區；畫面復原提示只在剩餘 canvas 內定位。 */
:is(.wb-grid-tile, .wb-focus-pane):has(> .wb-stage-problem-layer:not([hidden]))
  .wb-stage-live.has-frame.is-reconnecting .wb-stage-state {
  bottom: 12px;
}

/* 桌面兩種切版共用 2×2 的工作台外框；手機仍走可捲動的長頁。 */
@media (min-width: 721px) {
body[data-active-panel="internal-browse"][data-workbench-layout="grid"],
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="vertical"],
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="horizontal"] {
  overflow: hidden;
}
body[data-active-panel="internal-browse"][data-workbench-layout="grid"] #appShell,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="vertical"] #appShell,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="horizontal"] #appShell {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}
body[data-active-panel="internal-browse"][data-workbench-layout="grid"] main,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="vertical"] main,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="horizontal"] main {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  width: 100%;
  height: auto;
  min-height: 0;
  max-width: none;
  padding: 4px;
  overflow: hidden;
}
#internal-browse.panel.active[data-layout="grid"],
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="vertical"] #internal-browse.panel.active,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="horizontal"] #internal-browse.panel.active {
  box-sizing: border-box;
  flex: 1 1 0;
  height: auto;
  min-height: 0;
  gap: 0;
  overflow: hidden;
}
#internal-browse.panel.active[data-layout="grid"] > .workbench-stage,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="vertical"] #internal-browse.panel.active > .workbench-stage,
body[data-active-panel="internal-browse"][data-workbench-stage-layout="split"][data-workbench-split-axis="horizontal"] #internal-browse.panel.active > .workbench-stage {
  flex: 1 1 0;
}
.workbench-stage[data-layout="grid"] {
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  gap: 8px;
  overflow: hidden;
  aspect-ratio: auto;
  align-self: stretch;
  grid-template-columns: minmax(0, var(--wb-grid-x, 50%)) minmax(0, 1fr);
  grid-template-rows: minmax(0, var(--wb-grid-y, 50%)) minmax(0, 1fr);
}
.workbench-stage[data-layout="split"] {
  width: 100%;
  /* 左右 1:1 是兩個完整工作欄，不是只占上半屏的半套 2×2。下方空間由各欄自己的
     交易／操作紀錄接手，整個舞台貼滿可視高度，頁面本身不生成捲軸。 */
  height: 100%;
  min-height: 0;
  margin: 0;
  overflow: hidden;
  align-self: stretch;
}
.workbench-stage[data-layout="grid"] > :is(.wb-grid-tile, .wb-grid-empty),
.workbench-stage[data-layout="split"] > .wb-focus-pane {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
}

/* Desktop web shares the original viewport-fit split/grid contract above.
   The phone-only vertical scrolling contract stays in quantum-flight.css. */

.wb-stage-rail {
  grid-area: rail;
  z-index: 42;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 48px 58px;
  width: 100%;
  min-width: 0;
  min-height: 0;
  overflow: visible;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(90deg, color-mix(in srgb, var(--surface-2) 58%, var(--surface)), var(--surface));
}
.wb-stage-rail > .wb-stage-head.wb-stage-head {
  display: grid;
  grid-template-columns: 22px minmax(174px, 1fr) minmax(174px, .92fr);
  align-items: center;
  gap: 5px;
  width: 100%;
  min-width: 0;
  min-height: 0;
  height: 48px;
  padding: 5px 6px;
  overflow: visible;
  border: 0;
  background: transparent;
}
.wb-stage-head > .wb-pane-drag-handle {
  align-self: center;
  width: 22px;
  height: 36px;
}
.wb-stage-head > .wb-pane-picker {
  display: grid;
  grid-template-columns: minmax(76px, .62fr) minmax(94px, 1fr);
  align-items: center;
  gap: 5px;
  width: 100%;
  min-width: 0;
  height: 38px;
  border: 0;
  background: transparent;
}
.wb-stage-head .wb-pane-group {
  width: 100%;
  min-width: 0;
  height: 36px;
  min-height: 36px;
  max-height: 36px;
  padding: 0 24px 0 8px;
  border: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: 12px;
}
.wb-pane-identity-row {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  align-items: center;
  gap: 5px;
  min-width: 0;
}
.wb-pane-identity-row > .bot-avatar-button {
  display: grid;
  place-items: center;
  width: 36px;
  min-width: 36px;
  max-width: 36px;
  height: 36px;
  min-height: 36px;
  max-height: 36px;
  margin: 0;
  border-width: 2px;
}
.wb-pane-identity-row > .bot-avatar-button :is(img, .bot-avatar-fallback) { width: 100%; height: 100%; }
.wb-stage-head .wb-pane-bot-picker { position: relative; width: 100%; min-width: 0; }
.wb-stage-head .wb-pane-bot-picker > summary {
  display: flex;
  align-items: center;
  min-width: 0;
  min-height: 36px;
  padding: 0 24px 0 8px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
}
.wb-stage-head .wb-pane-current { min-width: 0; gap: 5px; }
.wb-stage-head .wb-pane-current strong {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: 13px;
  font-weight: 750;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wb-stage-head .wb-pane-bot-picker > .workbench-tabs {
  inset: auto;
  display: grid;
  position: fixed;
  z-index: 20030;
  width: min(300px, calc(100vw - 24px));
  max-height: min(52vh, 420px);
  overflow: auto;
  padding: 5px;
}
.workbench-panel[data-layout="grid"] .wb-pane-picker { min-width: 0; max-width: none; }
.workbench-panel[data-layout="grid"] .wb-pane-bot-picker > .workbench-tabs { left: 0; }

.wb-stage-head > .wb-stage-tools {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  margin: 0;
}
.wb-stage-head .wb-stage-window-tools {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}
.wb-stage-head .wb-pane-tabs {
  display: inline-grid;
  grid-template-columns: repeat(3, 32px);
  width: auto;
  min-width: 0;
}
.wb-stage-head .wb-pane-tabs button,
.wb-stage-head .wb-stage-window-tools > button {
  width: 32px;
  min-width: 32px;
  height: 36px;
  min-height: 36px;
  padding: 0;
}
.wb-stage-head .wb-pane-tabs svg { width: 21px; height: 21px; }
.wb-stage-head .wb-pane-tabs button[aria-pressed="true"] {
  color: var(--cyan);
  background: color-mix(in srgb, var(--cyan) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cyan) 26%, transparent);
}

.wb-stage-rail > .wb-trade-summary {
  --qw-workbench-summary-control-height: 47px;
  position: static;
  display: grid;
  grid-template-columns: minmax(212px, .82fr) minmax(252px, 1.18fr);
  align-items: stretch;
  gap: 6px;
  width: 100%;
  min-width: 0;
  height: 58px;
  margin: 0;
  padding: 5px 6px;
  overflow: hidden;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .wb-grid-trade {
  display: grid;
  grid-template-columns: minmax(42px, .8fr) minmax(82px, 1.2fr) minmax(42px, .8fr) 30px;
  grid-template-areas: "buy qty sell lock";
  gap: 4px;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .qt-buy { grid-area: buy; }
.wb-stage-rail > .wb-trade-summary .qt-sell { grid-area: sell; }
.wb-stage-rail > .wb-trade-summary .qt-qty {
  grid-area: qty;
  display: grid;
  /* ⛔ 加減鍵要能縮：舊值寫死 28px，加上中間的 30px 最小值 ⇒ 內容最小 86px，
     而上面 .wb-grid-trade 給它的那一軌最小只有 82px ⇒ 裝不下。
     實測（2026-09-11·四格版面 tile 寬 590px）：軌寬 82.1px、內容 86px，
     「+」按鈕右緣 x=164.8 而盒子右緣 159.9 ⇒ overflow:hidden 切掉 4.9px，
     按鈕貼死右框、跟「賣出」之間的縫消失 —— 站長「口數 格子版面不好看 沒有置中格子」。
     ⭐ ⛔ 不是把軌改寬（改 min-content 實測過）：那會把整列的最小需求從 208 推到 214px，
       tile 寬 500px 時整列改成溢出 —— 把病從一個寬度搬到另一個。
       讓內容能縮才安全：縮永遠不會抬高任何最小值。
     ⚠ 中間的 30px 不動（口數可到 10000 五位數），只讓兩側讓位。 */
  grid-template-columns: minmax(22px, 28px) minmax(30px, 1fr) minmax(22px, 28px);
  align-items: stretch;
  width: 100%;
  min-width: 0;
  height: var(--qw-workbench-summary-control-height);
  min-height: var(--qw-workbench-summary-control-height);
  overflow: hidden;
}
.wb-stage-rail > .wb-trade-summary .qt-qty button,
.wb-stage-rail > .wb-trade-summary .qt-qty input {
  width: 100%;
  min-width: 0;
  height: 100%;
  padding: 0;
  line-height: 1;
}
.wb-stage-rail > .wb-trade-summary .qt-qty button { display: grid; place-items: center; font-size: 17px; }
.wb-stage-rail > .wb-trade-summary .qt-qty input { align-self: stretch; padding-block: 0; font-size: 15px; }
.wb-stage-rail > .wb-trade-summary .wb-grid-trade .qt-side {
  min-width: 0;
  height: var(--qw-workbench-summary-control-height);
  min-height: var(--qw-workbench-summary-control-height);
  padding: 0 4px;
  font-size: 14px;
}
.wb-stage-rail > .wb-trade-summary .qt-lock {
  grid-area: lock;
  display: grid;
  place-items: center;
  width: 30px;
  min-width: 30px;
  height: var(--qw-workbench-summary-control-height);
  min-height: var(--qw-workbench-summary-control-height);
  padding: 0;
  overflow: hidden;
  border-radius: 8px;
  color: var(--muted);
  font-size: 15px;
}
.wb-grid-trade .qt-lock[aria-pressed="false"] {
  border-color: var(--green);
  color: var(--green);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--green) 62%, transparent);
}
.wb-stage-rail .qt-lock-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metrics {
  display: grid;
  align-items: stretch;
  height: var(--qw-workbench-summary-control-height);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 4px;
  width: 100%;
  min-width: 0;
  padding: 0;
  background: transparent;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric {
  box-sizing: border-box;
  height: var(--qw-workbench-summary-control-height);
  min-height: var(--qw-workbench-summary-control-height);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  align-items: center;
  gap: 1px;
  min-width: 0;
  padding: 4px 5px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  border-radius: 7px;
  background: color-mix(in srgb, var(--surface-2) 88%, var(--surface));
  text-align: center;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric small {
  overflow: hidden;
  color: var(--muted);
  font-size: clamp(12px, 14cqi, 14px);
  line-height: 1.1;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wb-stage-rail > .wb-trade-summary .wb-stage-metric strong {
  max-width: 100%;
  overflow: hidden;
  font-size: clamp(14px, 16cqi, 17px);
  line-height: 1.12;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 手機寬度不能把身份、六顆工具、下單與三格損益硬塞在同一條；那會讓它們彼此覆蓋。
   控制艙固定拆成四條：身份、工具、下單、損益。DOM 與事件仍是同一份，只改 grid placement，
   因此不是另一套手機功能，也不會重建串流。 */
@container (max-width: 480px) {
  .wb-stage-rail {
    grid-template-rows: auto auto;
  }
  .wb-stage-rail > .wb-stage-head.wb-stage-head {
    grid-template-columns: 20px minmax(0, 1fr);
    grid-template-rows: 36px 36px;
    gap: 4px;
    height: auto;
    min-height: 82px;
    padding: 4px;
  }
  .wb-stage-head > .wb-pane-drag-handle { grid-column: 1; grid-row: 1; }
  .wb-stage-head > .wb-pane-picker { grid-column: 2; grid-row: 1; grid-template-columns: 70px minmax(78px, 1fr); gap: 3px; }
  .wb-pane-identity-row { grid-template-columns: 32px minmax(0, 1fr); gap: 3px; }
  .wb-pane-identity-row > .bot-avatar-button { width: 32px; min-width: 32px; max-width: 32px; height: 32px; min-height: 32px; max-height: 32px; }
  .wb-stage-head > .wb-stage-tools { grid-column: 1 / -1; grid-row: 2; gap: 3px; }
  .wb-stage-head .wb-stage-window-tools { gap: 3px; }
  .wb-stage-head .wb-pane-tabs { grid-template-columns: repeat(3, 30px); }
  .wb-stage-head .wb-pane-tabs button,
  .wb-stage-head .wb-stage-window-tools > button { width: 30px; min-width: 30px; }
  .wb-stage-rail > .wb-trade-summary {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: repeat(2, var(--qw-workbench-summary-control-height));
    gap: 4px;
    height: auto;
    min-height: 106px;
    padding: 4px;
  }
  .wb-stage-rail > .wb-trade-summary .wb-grid-trade { grid-template-columns: minmax(42px, .75fr) minmax(84px, 1.2fr) minmax(42px, .75fr) 30px; gap: 3px; }
  .wb-stage-rail > .wb-trade-summary .qt-lock { width: 30px; min-width: 30px; }
  .wb-stage-rail > .wb-trade-summary .wb-stage-metric { padding-inline: 3px; }
  .wb-stage-rail > .wb-trade-summary .wb-stage-metric strong { font-size: clamp(14px, 16cqi, 16px); }
}

/* Narrow desktop panes retain the original controls in two compact rows.
   This follows their container mother rules, so later generic sizing cannot
   silently enlarge the web rail. Phone sizing remains unchanged. */
@media (min-width: 721px) {
  @container (max-width: 480px) {
    html[data-host="web"] .wb-stage-rail > .wb-stage-head.wb-stage-head {
      grid-template-rows: 32px 32px;
      min-height: 76px;
    }
    html[data-host="web"] .wb-stage-head > .wb-pane-picker,
    html[data-host="web"] .wb-stage-head .wb-pane-group { height: 32px; min-height: 32px; }
    html[data-host="web"] .wb-stage-head .wb-pane-tabs { grid-template-columns: repeat(3, 32px); }
    html[data-host="web"] .wb-stage-head .wb-pane-tabs button,
    html[data-host="web"] .wb-stage-head .wb-stage-window-tools > button { width: 32px; min-width: 32px; height: 32px; min-height: 32px; }
    html[data-host="web"] .wb-stage-rail > .wb-trade-summary {
      grid-template-rows: repeat(2, var(--qw-workbench-summary-control-height));
      min-height: 106px;
    }
    html[data-host="web"] .wb-stage-rail > .wb-trade-summary :is(.qt-qty, .qt-side, .qt-lock) { height: var(--qw-workbench-summary-control-height); min-height: var(--qw-workbench-summary-control-height); }
    html[data-host="web"] .wb-stage-rail > .wb-trade-summary .wb-stage-metric { padding-block: 2px; }
    html[data-host="web"] .wb-stage-rail > .wb-trade-summary .wb-stage-metric small { font-size: 12px; }
    html[data-host="web"] .wb-stage-rail > .wb-trade-summary .wb-stage-metric strong { font-size: 14px; }
    html[data-host="web"] .bot-reconciling-warning {
      grid-template-columns: minmax(0, 1fr) auto;
      grid-template-areas: "title confirm" "detail confirm";
      margin: 4px 6px;
      padding: 5px 8px;
      row-gap: 2px;
      column-gap: 6px;
      font-size: 12px;
      line-height: 1.25;
    }
    html[data-host="web"] .bot-reconciling-warning > button { grid-column: 2; grid-row: 1 / span 2; min-height: 34px; padding-inline: 8px; font-size: 12px; }
  }
}

/* 左右 1:1 的每欄只保留一套身份與下單列；畫面和紀錄共用這套單一真相源。
   viewer 固定在上、紀錄固定在下，因此切頁籤只是換下層內容，不會拔掉上層串流。 */
.workbench-stage[data-layout="split"][data-split-axis="horizontal"] > .wb-focus-pane.is-horizontal-composite,
:is(.wb-focus-pane, .wb-grid-tile).is-viewer-record-composite,
.workbench-stage.is-viewer-record-composite {
  /* 複合窗格的可用高度由同一個 grid 分配。viewer 與紀錄一起伸縮，不能再讓
     16:9 影格先拿完高度、再把無法使用的差額丟成黑色空區。2:1 保留完整交易畫面，
     同時確保下方交易紀錄是可操作區；Chrome viewport 會再依 canvas 實際尺寸調整。 */
  grid-template-rows: auto auto minmax(0, 2fr) auto minmax(148px, 1fr);
  grid-template-areas: "rail" "notices" "canvas" "problem" "record";
}
.workbench-stage > :is(.wb-focus-pane, .wb-grid-tile).is-viewer-record-composite > .wb-stage-viewer-layer,
#workbenchStage.workbench-stage.is-viewer-record-composite > .wb-stage-viewer-layer {
  grid-area: canvas;
  justify-self: stretch;
  width: 100%;
  height: 100%;
  max-height: none;
  aspect-ratio: auto;
  overflow: hidden;
  padding: 0;
}
.workbench-stage > :is(.wb-focus-pane, .wb-grid-tile).is-viewer-record-composite > .wb-stage-viewer-layer > :is(.wb-stage-live, .wb-stage-state),
#workbenchStage.workbench-stage.is-viewer-record-composite > .wb-stage-viewer-layer > :is(.wb-stage-live, .wb-stage-state) {
  width: 100%;
  height: 100%;
  min-height: 0;
}
.workbench-stage > :is(.wb-focus-pane, .wb-grid-tile).is-viewer-record-composite > .wb-stage-record-layer,
#workbenchStage.workbench-stage.is-viewer-record-composite > .wb-stage-record-layer {
  grid-area: record;
  min-height: 148px;
  border-top: 1px solid color-mix(in srgb, var(--cyan) 24%, var(--border));
  background: color-mix(in srgb, var(--surface) 96%, var(--surface-2));
}

/* ── 0.3.64 共用產品導覽＋薄桌面殼 ──────────────────────────────────────
   五顆產品按鈕只有這一份 DOM：寬螢幕是頂部玻璃 dock，手機移到底部；桌面殼僅
   追加右上角原生視窗控制。基本導覽不依賴 WebGPU，低階裝置與 reduced-motion
   仍可立即操作；WebGPU/TSL 只適合日後加非承重的光影。 */
.app-header .tabs {
  height: 62px;
  align-items: center;
  gap: 6px;
  padding: 5px;
  overflow: visible;
  border: 1px solid rgba(151, 176, 232, .18);
  border-radius: 18px;
  background: linear-gradient(135deg, rgba(31, 42, 78, .7), rgba(12, 17, 38, .62));
  box-shadow: inset 0 1px rgba(255, 255, 255, .08), 0 14px 34px rgba(0, 0, 0, .25);
  backdrop-filter: blur(20px) saturate(140%);
}
.app-header .tab {
  display: grid;
  grid-template-rows: 24px auto;
  place-items: center;
  gap: 2px;
  min-width: 68px;
  height: 50px;
  min-height: 50px;
  padding: 4px 10px;
  border: 1px solid transparent;
  border-radius: 13px;
  color: #aeb9d2;
  background: transparent;
  font-size: 12px;
  font-weight: 750;
  line-height: 1;
  transition: transform 160ms cubic-bezier(.2,.8,.2,1), color 140ms ease,
    background 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.app-header .tab svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.app-header .tab:first-child svg path:first-child { fill: currentColor; stroke: none; }
.app-header .tab:hover {
  color: #f4f8ff;
  border-color: rgba(139, 204, 255, .2);
  background: rgba(119, 156, 230, .12);
  transform: translateY(-2px);
}
.app-header .tab.active {
  color: #ecfbff;
  border-color: rgba(92, 218, 255, .42);
  background: linear-gradient(145deg, rgba(54, 169, 219, .28), rgba(93, 91, 210, .24));
  box-shadow: inset 0 1px rgba(255,255,255,.16), 0 8px 22px rgba(26, 126, 184, .22);
}
.app-header .tab:active { transform: translateY(0) scale(.96); }
.app-header .tab:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* 網頁不渲染假的縮小／關閉鍵；Tauri 只帶這個薄控制島，產品導覽仍由上面的共用 DOM 負責。 */
html:not([data-host="tauri"]) :is(.window-controls, .auth-window-controls) { display: none !important; }
html[data-host="tauri"] .app-header .window-controls {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 12000;
  gap: 0;
  height: var(--qw-titlebar-h, 44px);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  backdrop-filter: none;
}
html[data-host="tauri"] :is(.app-header .window-controls, .auth-window-controls) button {
  box-sizing: border-box;
  width: 46px;
  height: var(--qw-titlebar-h, 44px);
  min-height: var(--qw-titlebar-h, 44px);
  border: 1px solid transparent;
  border-radius: 0;
  color: #c7cfdd;
  background: transparent;
}
html[data-host="tauri"] :is(.app-header .window-controls, .auth-window-controls) button:hover {
  border-color: rgba(211, 222, 241, .2);
  color: #fff;
  background: rgba(125, 139, 164, .3);
}
html[data-host="tauri"] :is(.app-header .window-controls, .auth-window-controls) .window-close:hover {
  border-color: #e81123;
  color: #fff;
  background: #e81123;
}

/* Tauri 的 app-header 是原生視窗拖曳區。若全螢幕窗格蓋到 y=0，工具列雖
   看得到，WebView2 的原生命中仍會把該次按下交給標題列，分頁 click 不會抵達。
   全螢幕只佔標題列以下，保留可按的視窗控制與完整窗格工具列。 */
html[data-host="tauri"] body.workbench-fullscreen-active :is(
  .workbench-stage.is-single-fullscreen,
  .wb-focus-pane.is-fullscreen,
  .wb-grid-tile.is-fullscreen
) {
  inset: var(--qw-header-h, 88px) 0 0;
  width: 100dvw;
  height: calc(100dvh - var(--qw-header-h, 88px));
}

/* 2x2 must preserve every broker control just like single/split/fullscreen.
   The backend now renders each stream at the pane's measured aspect ratio, so
   contain fills the pane without either cover-cropping or side bars. */
.workbench-stage[data-layout="grid"] .wb-grid-tile:not(.is-fullscreen) .wb-stage-img {
  object-fit: contain;
}

@media (max-width: 760px) {
  .app-header {
    display: flex;
    min-height: 56px;
    padding: 5px 10px;
  }
  .app-header .brand { min-width: 0; }
  .app-header .brand-logo { width: 40px; height: 46px; flex-basis: 40px; }
  .app-header .brand-text { display: none; }
  .app-header .header-status { margin-left: auto; }
  /* ⛔ 這裡**只剩** adaptive-navigation.css 沒有的那幾條。手機底部那條 dock 的幾何
        （position / left / right / bottom / grid-template-columns / height / padding /
        overflow / border-radius，以及 .tab 的 height / min-height / padding、還有
        `main` 的 padding-bottom）原本在這裡也寫了一份，與 adaptive-navigation.css
        :212-:295 那份逐條重複，靠 `body:not(.auth-locked) .app-header .tabs`(1,3,0)
        贏過這裡的 `.app-header .tabs`(0,2,0) 分勝負 —— 兩份都對的時候看不出來，
        其中一份改了才會發現另一份還在。2026-09-14 刪掉重複的那些。
     ⚠ 下面留著的四條是**真的承重**，adaptive 那份完全沒有，刪掉會壞（實測 computed）：
        · z-index: 11000  —— 拿掉會掉到 1，dock 被內容蓋住
        · display: grid   —— 拿掉變 flex，adaptive 的 grid-template-columns 直接失效
        · width: auto     —— 拿掉 dock 從 351px 撐成 375px，貼齊不到左右的 12px
        · .tab{min-width:0} —— 拿掉每顆變 68px 下限，五顆擠爆
        · .tab span{…}    —— adaptive 一條都沒有，拿掉長標籤不再省略號截斷會換行破版
     ⭐ 判準不是「這條看起來重不重要」，是**拿掉之後 computed style 會不會變**。
        保留這五條時，375px 與 1440px 下的 computed 與刪除前逐項相同（差異 0 項）。 */
  .app-header .tabs {
    z-index: 11000;
    display: grid;
    width: auto;
  }
  .app-header .tab { min-width: 0; }
  .app-header .tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

@media (prefers-reduced-motion: reduce) {
  .app-header .tab { transition: none; }
  .app-header .tab:hover, .app-header .tab:active { transform: none; }
}

/* 0.3.72：分組與機器人合併為一顆身份選單。已選機器人的既有頭貼就在 summary 裡，
   不再另放一顆可編輯頭貼；節能與視窗工具仍由右側工具列獨立承載。 */
.wb-stage-head > .wb-pane-picker {
  display: block;
  width: 100%;
  min-width: 0;
  height: 42px;
}
.wb-stage-head .wb-pane-combined-picker { width: 100%; min-width: 0; }
.wb-stage-head .wb-pane-combined-picker > summary {
  min-height: 42px;
  padding: 2px 28px 2px 9px;
  border-color: color-mix(in srgb, var(--cyan) 28%, var(--border));
}
.wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-row {
  width: 100%;
  grid-template-columns: 9px 34px minmax(0, 1fr);
  gap: 8px;
}
.wb-stage-head .wb-pane-combined-picker > summary .bot-avatar-display {
  width: 34px;
  min-width: 34px;
  max-width: 34px;
  height: 34px;
  min-height: 34px;
  max-height: 34px;
}
.wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-name {
  display: block;
  overflow: hidden;
  color: var(--text);
  font-size: 14px;
  font-weight: 750;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wb-pane-picker-group + .wb-pane-picker-group {
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
}
.wb-pane-picker-group-label {
  padding: 2px 9px 5px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 650;
  line-height: 1.2;
}
.wb-pane-picker-group .wb-bot-option {
  width: 100%;
  min-height: 50px;
  padding: 5px 8px;
  text-align: left;
}
.wb-pane-picker-group .wb-bot-option .wb-bot-picker-row {
  grid-template-columns: 9px 36px minmax(0, 1fr);
  gap: 8px;
}
.wb-pane-picker-group .wb-bot-option .bot-avatar-display {
  width: 36px;
  min-width: 36px;
  max-width: 36px;
  height: 36px;
  min-height: 36px;
  max-height: 36px;
  aspect-ratio: 1;
  flex-shrink: 0;
  object-fit: contain;
}

/* 中窄窗格仍維持單列，但讓身份欄先吃剩餘空間，工具才用實際需要的寬度。
   七顆圖示在這段寬度縮成 26px；再窄於 481px 才由下一條規則換到第二列。 */
@container (min-width: 481px) and (max-width: 680px) {
  .wb-stage-rail > .wb-stage-head.wb-stage-head {
    grid-template-columns: 20px minmax(112px, 1fr) auto;
    gap: 3px;
    padding-inline: 4px;
  }
  .wb-stage-head > .wb-pane-drag-handle { width: 20px; }
  .wb-stage-head > .wb-pane-picker { height: 36px; }
  .wb-stage-head .wb-pane-combined-picker > summary {
    min-height: 36px;
    padding: 1px 20px 1px 6px;
  }
  .wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-row {
    grid-template-columns: 8px 28px minmax(0, 1fr);
    gap: 5px;
  }
  .wb-stage-head .wb-pane-combined-picker > summary .bot-avatar-display {
    width: 28px;
    min-width: 28px;
    max-width: 28px;
    height: 28px;
    min-height: 28px;
    max-height: 28px;
  }
  .wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-name { font-size: 12px; }
  .wb-stage-head > .wb-stage-tools,
  .wb-stage-head .wb-stage-window-tools { gap: 2px; }
  .wb-stage-head .wb-pane-tabs { grid-template-columns: repeat(3, 26px); }
  .wb-stage-head .wb-pane-tabs button,
  .wb-stage-head .wb-stage-window-tools > button {
    width: 26px;
    min-width: 26px;
    height: 34px;
    min-height: 34px;
  }
  .wb-stage-head .wb-pane-tabs svg,
  .wb-stage-head .wb-stage-window-tools svg { width: 18px; height: 18px; }
}

@container (max-width: 480px) {
  .wb-stage-head > .wb-pane-picker {
    grid-column: 2;
    grid-row: 1;
    height: 36px;
  }
  .wb-stage-head .wb-pane-combined-picker > summary { min-height: 36px; }
  .wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-row {
    grid-template-columns: 8px 30px minmax(0, 1fr);
    gap: 6px;
  }
  .wb-stage-head .wb-pane-combined-picker > summary .bot-avatar-display {
    width: 30px;
    min-width: 30px;
    max-width: 30px;
    height: 30px;
    min-height: 30px;
    max-height: 30px;
  }
}
/* The browser shell stays usable when its execution desktop is offline. */
/* #webWorkspaceStatus 已於 2026-09-14 移除（單一真相源：右上角那顆聚合狀態藥丸）。
   ⛔ 別再把它加回來：它掛在 <main> 裡，而 <main> 的內距工作台與其餘頁各一套
      ⇒ 同一行字的位置會隨分頁跳（E1：桌面 x=252 vs 274、手機 x=10 vs 18）。 */
.system-status.offline, .system-status.offline #systemStatusIcon { color: #a2aab5; }

.workspace-local-unavailable { display: none; }
.workspace-offline .workspace-local-unavailable { display: block; padding: 24px; color: #b8c4d3; border: 1px solid #334453; border-radius: 16px; }
.workspace-offline .workspace-local-data { display: none !important; }
.workspace-inline-pairing { margin-block: 20px; padding: 18px; border: 1px solid #334453; border-radius: 16px; }
.workspace-inline-pairing h2 { font-size: 18px; }
.workspace-offline .section-title .actions[inert],
.workspace-connecting .section-title .actions[inert],
.workspace-connecting .workspace-local-data[inert] :is(button, input, select, textarea, [role="button"]) { opacity: .45; }

/* ── 連線第三態：正在連線（2026-09-14） ────────────────────────────────────
   ⛔ 在這之前只有兩色：已連線 #73dec0 綠（:8257）與離線 #a2aab5 灰（:8259）——
      而「正在連線」被歸到跟**真的斷線**同一個灰。這兩種狀態該有的反應是相反的
      （前者只要等，後者要去查網路），同色等於這一格沒有提供任何資訊。
   ⭐ 顏色用既有的 var(--amber) ⛔ 不自創色碼：:32/:485/:842 三套佈景各自定義過它，
      而且「連線中＝琥珀」在這份檔裡已有先例 —— :3516 `.wb-dot.connecting`。
      寫死 #xxxxxx 會在另外兩套佈景下變成唯一不跟著換色的那一格。
   ⭐ 脈動不是裝飾，是**第二個辨識維度**：:3060 那條註解立下的約定是「形狀符號隨狀態
      改變 —— 色盲與單色列印下仍分得出來」。CSS 改不了 `●` 這個字元，所以這一態改用
      「會動 vs 不會動」來承擔同一件事：琥珀與灰在單色下幾乎同階，但一個在呼吸、
      一個是死的，不靠顏色也分得出來。
   ⚠ 這一態刻意**不**跨到 `.system-status` 那一軸（它有自己的 warn/pending/error，
      見 :3061-:3064）。兩個正交的軸共用一組詞，介面就會開始說謊。
   ⚠ 接線注意（app.js）：`workspace-offline` 是掛在 `document.documentElement` 上的
      （app.js:2761 `document.documentElement.classList.toggle('workspace-offline', offline)`），
      這一態請掛在同一個節點上，⛔ 不要掛到 body。 */
/* ⭐ 脈動不是裝飾，是**第二個辨識維度**：手機 ≤900px 把狀態文字藏起來時，琥珀與灰在單色下
   幾乎同階，但一個在呼吸、一個是死的，不靠顏色也分得出來。
   2026-09-14 橫幅移除後，這一維改掛在右上角那顆藥丸的圓點上 —— ⛔ 不是刪掉。 */
.workspace-connecting .system-status .system-status-icon {
  color: var(--amber, #f2b84b);
  animation: workspace-connecting-breathe 1.6s ease-in-out infinite;
}

@keyframes workspace-connecting-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: .48; }
}

/* 關掉動畫時顏色仍在 —— 三態靠色相與亮度仍分得出來，只是少了呼吸那一維。 */
@media (prefers-reduced-motion: reduce) {
  .workspace-connecting .system-status .system-status-icon { animation: none; }
}

/* SVG defs must not create an anonymous inline line box before the viewport shell. */
.ui-icon-defs { position: absolute; width: 0; height: 0; overflow: hidden; pointer-events: none; }

/* ── 交易帳號同步：失敗狀態的紅字（2026-09-12） ──────────────────────────
   ⛔ 這一塊取代的是「每次背景同步失敗就彈一則 toast」。站長原話：
      「不用跳系統提示，在同步那邊寫紅字大家都知道了」。
   ⚠ 它必須在**同步面板裡**而不是浮在畫面上 —— toast 一閃就沒了，而他是隔天
      才來看這一格（2026-09-11 夜失敗 33 次，他早上只看到一個反灰的開關）。
   ⚠ 不用 `.alert-*` 那套：那是設定頁「警示」分頁的區塊級版型（32px 外距、
      24px 標題），塞進這張卡片會比卡片本身還大。 */
.vault-sync-error {
  margin: 12px 0 4px;
  padding: 12px 14px;
  border: 1px solid rgba(255, 112, 142, .42);
  border-left: 3px solid var(--danger, #ff708e);
  border-radius: 10px;
  background: rgba(120, 26, 48, .22);
}
.vault-sync-error-title {
  margin: 0;
  color: var(--danger, #ff708e);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.5;
}
.vault-sync-error-body {
  margin: 6px 0 0;
  color: var(--text, #e7ecf3);
  font-size: 13px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}
/* 「交易不受影響」這句是承重的：看到紅字的第一個念頭是「我的單會不會出事」。 */
.vault-sync-error-hint {
  margin: 6px 0 0;
  color: var(--muted, #8b95a3);
  font-size: 12px;
  line-height: 1.5;
}
.vault-sync-error .actions { margin-top: 10px; }
.vault-sync-error .actions button { min-height: 38px; font-size: 13px; }

/* ── 帳號對話框的版面（2026-09-12） ─────────────────────────────────────
   ⛔ 這不是「美化」，是清掉三個**留在原地的舊身分**：#accountEditor 以前是設定頁
      account-manager-grid 的左欄，改成 <dialog> 之後那些欄位樣式沒跟著改：
        ① .credential-panel 的 border-right 變成一條切在對話框右緣的線
        ② .credential-panel 的 padding(32/48px) ＋ `dialog form` 的 padding(32/48px)
           疊成兩層 ⇒ 內容被擠到中間一條
        ③ .credential-panel 的半透明底色疊在對話框自己的底色上 ⇒ 顏色比別的對話框深一階
   ⚠ 一律用 #accountDialog 起頭限定範圍：.credential-panel 這個類別在別處還有人用。 */
#accountDialog .credential-panel {
  border-right: 0;
  background: none;
}
/* 水平留白只留一層（由 .credential-panel 提供，各主題 32/48px 各自為政）。 */
#accountDialog .credential-form {
  padding: 20px 0 0;
}
#accountDialog .qf-detail-header {
  margin-bottom: 4px;
}
/* 從機器人精靈進來時的那一行說明。⛔ 不是裝飾：使用者是在**建機器人**的半路被帶到
   這裡的，不告訴他「存完會自動帶回去」，他會以為自己剛剛跑掉了。 */
#accountDialog .account-form-hint.from-bot-wizard {
  padding: 10px 12px;
  border-left: 3px solid var(--cyan, #19ddff);
  border-radius: 8px;
  background: rgba(25, 221, 255, .08);
}

/* ── 設定頁窄螢幕：把垂直節奏收緊（2026-09-14） ─────────────────────────────
   ⛔ 先講清楚它**不是**溢出問題：375px 下實測橫向溢出 0，沒有任何一條 CSS 爆版。
      真正的毛病是「空資料就 6173px ＝ 7.6 個螢幕」的線性長捲。
   ⭐ 機制在 quantum-flight.css:971-1050 那個 760px 區塊 —— 它幫 #dashboard、#cloud、
      #botForm、dialog 都逐條收了間距，**唯獨 #settings 只寫了三條**（member-head /
      member-identity / member-facts）。所以設定頁不是「自適應壞了」，是那一批收緊
      **從來沒做到設定頁**。這裡補上同一批。
   ⚠ 選擇器為什麼這麼長：quantum-flight.css 在本檔**之後**載入，它的
      `.panel:not(#internal-browse) .form-card` 特異性是 **(1,2,0)** 不是 (0,3,0) ——
      `:not()` 內的 `#internal-browse` 算一個 id。跟 `#settings .settings-item.form-card`
      正好**平手**，平手時後載入的贏 ⇒ 必須再多一層 `.settings-grid` 墊到 (1,3,0)。
      同理 `#settings .switch-row`(1,1,0) 要用 `.settings-item` 墊到 (1,2,0) 才蓋得過。
   ⚠ 這代表設定頁的 RWD 真相源其實已經一分為二（本檔＋quantum-flight.css）。
      這裡沒有搬過去，是因為那份檔案這一輪由別人負責；⛔ 下次動它時請合併成一處。
   ⛔ 這裡全部是「收緊間距」，**沒有任何一條在截斷內容**：⛔ 不用 max-height + overflow
      hidden 去假收合（那會把文字切掉而使用者不知道）。真正要把 6173px 壓到一兩個螢幕，
      必須讓長卡片可收合，而那需要 DOM 改成 <details>/<summary> —— 不是 CSS 做得到的。 */
@media (max-width: 760px) {
  /* 卡片內距：23px → 16px。八張卡各省上下 14px。 */
  #settings .settings-grid .settings-item.form-card { padding: 16px; }
  #settings .settings-grid,
  #settings .settings-preferences-stack { gap: 14px; }

  /* 開關列：原 padding 17px 0 + min-height 76px。內容本身（粗體標題＋說明兩行）就
     遠高於 44px 觸控下限，收到 11px 仍有 94px 以上。
     ⛔ `margin: 0` 不能省：.switch-row 自己就是 <label>，會被下面那條 label 規則命中，
        把 quantum-flight.css:743 的 margin:0 蓋掉 ⇒ 九列各憑空多出上下外距。 */
  #settings .settings-item .switch-row { min-height: 56px; margin: 0; padding: 11px 0; gap: 14px; }
  #settings .settings-item .switch-row small { margin-top: 3px; line-height: 1.45; }

  /* 獨立欄位：24px → 14px（相鄰的會外距折疊，實際每組省的是 10px 不是 20px）。 */
  #settings .settings-item label { margin: 14px 0; }

  /* 交易帳號卡頭：原本在 375px 下仍吃左右各 48px 內距，可用寬只剩約 197px ——
     「＋ 新增帳號」那顆按鈕被擠成三行、整個卡頭撐到 293px 高。
     ⚠ :1934 的 `padding-bottom: 68px` 是留給 .simulation-chip 的絕對定位用的，
        而那個元素在 public/ 全目錄（.js 與 .html）已經一個都找不到 ⇒ 是留給不存在
        元素的空位。這裡一併收掉。 */
  #settings .account-manager .account-manager-head { padding: 2px 0 14px; }

  /* 關於卡四格規格：:2425 把它壓成單欄 ⇒ 四格各 84px 疊成 372px。兩欄放得下
     （每欄約 140px，欄位名最長四個字），高度直接砍半。 */
  #settings .about-card .product-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 16px; }
  #settings .about-card .about-note { margin-top: 14px; }

  /* AI 求救卡的說明段：這張卡 1485px 裡有將近一半是純說明文字。這裡只收外距，
     ⛔ 不動字級 —— 那是拿可讀性換高度，而且換不到多少（實測 16px→15px 只差 24px）。 */
  #settings .ai-assist-explainer { margin-top: 14px; padding-top: 12px; }
  #settings .ai-assist-explainer-body h4 { margin: 14px 0 5px; }
  #settings .ai-assist-explainer-body p,
  #settings .ai-assist-explainer-body ul { margin-bottom: 6px; }
  #settings .ai-assist-explainer-body li { margin-bottom: 4px; }
}

/* ── 展示模式角標 ────────────────────────────────────────────────────
   「明顯但不干擾」：右下角、不蓋任何數字欄位，但在截圖裡一眼看得到。
   ⛔ 不放頂部置中：那位置實測會蓋住 Tradovate 的淨值／保證金那一列
   （同 wb-stage-readonly 的註解）。pointer-events:none 是承重的——下單鍵就在
   附近，這枚標記絕不能吃掉點擊。 */
.presentation-badge {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px;
  border: 1px solid rgba(96, 165, 250, .45);
  border-radius: 999px;
  background: rgba(13, 26, 43, .92);
  color: #cbd5f5;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .02em;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .38);
  pointer-events: none;
}
.presentation-badge[hidden] { display: none; }
/* 展示模式：券商畫面的帳戶列遮罩。
   ⛔ 只蓋最上面那一條橫帶（EQUITY／OPEN P/L／DAY MARGIN／INITIAL MARGIN），
   ⛔ 不碰 K 線、報價階梯、成交量、商品代碼與時間
   —— 遮掉那些，這張截圖就不再證明任何事。
   座標由 app.js 的 syncPresentationMask() 依影像實際繪製區算出來寫進 style，
   ⛔ 這裡不寫死任何位置（<img> 是 object-fit: contain，比例漂移時會有黑邊）。
   z-index 2：疊在影像之上，但在 .wb-stage-state（3）與唯讀內框（4）之下——
   斷線時那兩層要蓋得過它。 */
.wb-stage-privacy {
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  box-sizing: border-box;
  background: #0b1524;
  border-bottom: 1px solid rgba(96, 165, 250, .38);
  color: #93a4c8;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  overflow: hidden;
  pointer-events: none;
}
.wb-stage-privacy[hidden] { display: none !important; }
.wb-stage-privacy-dots { color: #cbd5f5; letter-spacing: .2em; }
.presentation-badge-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #60a5fa;
  box-shadow: 0 0 0 3px rgba(96, 165, 250, .22);
}
/* 介面卡裡只有這一列開關，底線會變成懸在半空的一條線。 */
#settings .interface-card .switch-row { border-bottom: 0; }

/* ── 編輯交易紀錄（站長 2026-09-17）──────────────────────────────────────────
   站長：「就照交易紀錄的視窗去設計 就很直觀了」⇒ 這裡刻意**不**另造一套表格樣式，
   沿用 .workbench-table 的邊框／間距／字級，只補三件交易紀錄表沒有的東西：
     ① 儲存格裡的輸入框  ② 唯讀（機器人）列的視覺  ③ 那一列被退回時的紅字。
   ⛔ 不複製 .workbench-table 的顏色與圓角到這裡 —— 複製的那一份不會跟著主題改，
      下一次換色就會只有這一頁沒跟上，而且沒有任何東西會報錯。 */

.history-edit-panel .history-edit-notice {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--warn, #ffd37a);
  border-radius: var(--radius-md);
  background: rgba(255, 211, 122, .08);
  color: var(--text);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.history-edit-notice strong { color: var(--warn, #ffd37a); }

.history-edit-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.history-edit-toolbar button { min-height: 40px; padding: 0 var(--space-4); font-size: var(--text-sm); }
.history-edit-bot { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }
.history-edit-bot select { min-height: 40px; padding: 0 var(--space-3); font-size: var(--text-sm); }
/* ⚠ 這一段推開左右兩邊，⛔ 不用 margin-left:auto 掛在某一顆按鈕上：那樣一旦按鈕
   換順序就會整排錯位，而錯位不報錯。 */
.history-edit-spacer { flex: 1 1 auto; }
.history-edit-count, .history-edit-loaded { color: var(--muted, #8fa9c4); font-size: var(--text-sm); }

/* 捲動容器：站長要「原本所有的交易紀錄都看得到 並且可捲動」。
   ⛔ 高度用 vh 不用固定 px —— 固定值在筆電上會把表格壓到只剩三列。 */
.history-edit-log { max-height: calc(100vh - 320px); overflow: auto; }
.history-edit-table { width: 100%; }
.history-management-toolbar { display: flex; flex-wrap: wrap; align-items: end; gap: 10px; margin: 12px 0; }
.history-management-toolbar label { display: grid; gap: 4px; min-width: 160px; max-width: 100%; }
.history-management-toolbar select { max-width: 100%; }
.history-management-hint { flex-basis: 100%; color: var(--muted); font-size: 12px; }
.history-edit-table .history-management-select { width: 42px; min-width: 42px; text-align: center; }
.history-management-select input { width: 18px; height: 18px; cursor: pointer; }
.history-management-select input:disabled { cursor: default; }
@media (max-width: 640px) {
  .history-management-toolbar label { flex: 1 1 100%; min-width: 0; }
  .history-management-toolbar button { flex: 1 1 auto; white-space: normal; }
  .history-management-hint { line-height: 1.5; }
}
/* 表頭要黏住：捲到第 300 列時看不到欄名，等於每一欄都得用猜的。 */
.history-edit-table thead th { position: sticky; top: 0; z-index: 1; background: var(--surface-2); }

/* 儲存格裡的輸入框。⛔ 高度比表格列矮一階（32px）：跟列一樣高的話整張表會被撐成
   兩倍長，而站長要的是「像試算表」不是「像表單」。 */
.history-edit-input {
  width: 100%;
  min-width: 0;
  min-height: 32px;
  padding: 0 var(--space-2);
  box-sizing: border-box;
  font-size: var(--text-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
}
.history-edit-input:focus { outline: 2px solid var(--accent, #9d7cff); outline-offset: -1px; }
/* 被後端（或前端驗證）退回的那一欄。⛔ 只有紅框不夠 —— 色盲看不出來，所以那一列
   底下另有一條寫著理由的紅字（.history-edit-error-row）。 */
.history-edit-input.is-invalid { border-color: var(--danger, #ff708e); background: rgba(255, 112, 142, .10); }
.history-edit-draft > td { background: rgba(157, 124, 255, .06); }
.history-edit-error-row td {
  padding: var(--space-1) var(--space-3);
  color: var(--danger, #ff708e);
  font-size: var(--text-sm);
  background: rgba(255, 112, 142, .08);
}

/* 機器人送出的列：淡化 ＋ 鎖頭。⛔ 不是把按鈕藏起來就算數 —— 藏起來的話使用者
   只會覺得「怎麼有些列沒有按鈕」，看不出那是一條規則。 */
.history-edit-row.is-locked > td { opacity: .72; }
.history-edit-lock { display: inline-block; padding: 0 var(--space-1); cursor: help; }
.history-edit-row.is-editing > td { background: rgba(157, 124, 255, .10); }
.history-edit-muted { color: var(--muted, #8fa9c4); font-size: var(--text-sm); }
.history-edit-bot-cell { font-size: var(--text-sm); }

.history-edit-actions { white-space: nowrap; }
.history-edit-mini {
  min-height: 28px;
  padding: 0 var(--space-2);
  margin-right: 2px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
}
.history-edit-mini.danger { color: var(--danger, #ff708e); border-color: rgba(255, 112, 142, .45); }
.history-edit-mini:hover { border-color: var(--accent, #9d7cff); }

/* ⭐ 站長：「損益本身要成為一個按鈕 按下去就在算一次」⇒ 表頭本身就是按鈕。
   ⛔ 它要看起來像表頭不是像工具列按鈕（不然那一欄的欄名就消失了）⇒ 繼承字色與字重，
      只靠虛線底線與游標告訴人「這個可以按」。 */
.history-edit-pnl-head {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  cursor: pointer;
  border-bottom: 1px dashed currentColor;
}
.history-edit-pnl-head:hover { color: var(--accent, #9d7cff); }
/* ⛔ 「計算中」一定要跟「算完了是 0」長得不一樣：兩者都是「那一格沒有數字」，
   不給訊號的話使用者分不出該等還是該去查。 */
.history-edit-pnl-head.is-busy, .history-edit-recalc.is-busy { opacity: .7; cursor: progress; }
.history-edit-pnl-head.is-busy { border-bottom-style: solid; }

@media (max-width: 900px) {
  .history-edit-toolbar { flex-direction: column; align-items: stretch; }
  .history-edit-spacer { display: none; }
  .history-edit-log { max-height: calc(100vh - 380px); }
}

/* 工作台窗格裡那張交易紀錄小表上方的一排。⭐ 這是站長【實際看得到】的那一張表
   （.record-bar 與 #workbenchLogRows 在 data-scope="bot" 下被 CSS 藏著），
   所以「編輯交易紀錄」的入口非掛在這裡不可。
   ⛔ 靠右不置中：這張表很窄，按鈕擺中間會把使用者的視線從資料上拉走。 */
/* ⭐ 站長 2026-09-17 裁決：入口直接放在交易紀錄表的**表頭**上，跟損益重算鈕並排，
   ⛔ 不藏進「⋯」選單也⛔ 不另開一排 —— 他給的判準是「直觀」。
   （前一版的 .wb-pane-record-actions 已隨之刪除：沒有消費端的樣式就是死樣式。） */
.wb-pane-record-edit-col { text-align: center; white-space: nowrap; }
.wb-pane-record-table thead .wb-pane-record-edit-col { padding: 4px 6px; }

/* 人補寫的列要一眼看得出來（站長：「總要知道這單不是正常下的」）。
   ⛔ 判準在 JS 的 historyRowUserEntered（editable / recordSource），
      ⛔ 不是 trigger 那句顯示文字 —— 那句話會被翻譯、也正要被改名。
   ⛔ 左邊那條槓不可省：只靠底色的話，在淺色主題下幾乎看不出來，
      而且色盲使用者拿不到任何訊號。 */
.is-user-entered > td:first-child { box-shadow: inset 3px 0 0 var(--accent, #9d7cff); }
.is-user-entered > td { background: rgba(157, 124, 255, .07); }
.record-manual-tag {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--accent, #9d7cff);
  border-radius: 999px;
  color: var(--accent, #9d7cff);
  font-size: 12px;
  line-height: 1.5;
  white-space: nowrap;
}

/* 工作台只有窗格內的機器人選單與三種互斥內容。全集紀錄是獨立模式，
   不再接在兩格／四格舞台後面形成第二個工作台。 */
.workbench-panel[data-scope="bot"] .workbench-picker-stack,
.workbench-panel[data-scope="bot"] .workbench-robot-trade,
.workbench-panel[data-scope="bot"] #workbenchMoreBtn,
.workbench-panel[data-scope="bot"] > .record-bar,
.workbench-panel[data-scope="bot"] > .record-pager,
.workbench-panel[data-scope="bot"] > .workbench-log { display: none; }
.workbench-panel[data-scope="all"] .workbench-bar-actions { display: flex; }
.workbench-panel[data-scope="all"] .wb-layout-switch,
.workbench-panel[data-scope="all"] .workbench-robot-trade,
.workbench-panel[data-scope="all"] #workbenchMoreBtn { display: none; }
.workbench-panel[data-scope="bot"] .workbench-bar { justify-content: flex-end; position: relative; top: auto; flex: 0 0 auto; }
.workbench-panel[data-scope="bot"] .workbench-bar-actions { flex: 0 0 auto; }
body[data-active-panel="internal-browse"] main { width: 100%; box-sizing: border-box; margin: 0; }
.workbench-panel[data-scope="bot"] { width: 100%; }
#internal-browse.workbench-panel[data-scope="all"] #workbenchStage { display: none; }

.wb-pane-record { display: flex; flex-direction: column; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
.wb-pane-record-controls { display: flex; align-items: end; flex: 0 0 auto; min-height: 48px; box-sizing: border-box; flex-wrap: wrap; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--border); overflow-x: hidden; }
.wb-pane-record-controls select { flex: 0 0 100px; width: 100px; min-width: 100px; max-width: 100px; font-size: 12px; padding-inline: 8px 22px; white-space: nowrap; }
.wb-pane-record-controls input[data-wb="record-search"] { flex: 0 1 126px; width: 126px; min-width: 80px; max-width: 126px; font-size: 12px; }
.wb-pane-record-controls input[type="date"] { flex: 0 0 38px; width: 38px; min-width: 38px; max-width: 38px; padding: 0 6px; color-scheme: dark; font-size: 12px; }
.wb-pane-record-controls input[type="date"]::-webkit-datetime-edit { display: none; }
.wb-pane-record-controls input[type="date"]::-webkit-calendar-picker-indicator { display: block; width: 18px; height: 18px; margin: 0; cursor: pointer; }
.wb-pane-record-controls :is(button, a) { flex: 0 0 auto; white-space: nowrap; font-size: 12px; padding-inline: 10px; }
.wb-pane-record-controls :is(select, input, button, a) { min-height: 34px; }
/* Compact shared pager; retain full range text and original event targets. */
.wb-pane-record-pager { display: flex; align-items: center; justify-content: space-between; flex: 0 0 auto; flex-wrap: nowrap; height: auto; min-height: 36px; padding: 3px 4px; gap: 4px; font-size: var(--text-sm); overflow-x: auto; overflow-y: hidden; }
.wb-pane-record-pager :is(.record-pager-range, .record-pager-nav, .record-pager-size) { flex: 0 0 auto; white-space: nowrap; grid-area: auto; margin: 0; }
.wb-pane-record-pager .record-pager-nav { display: flex; align-items: center; gap: 2px; order: 1; }
.wb-pane-record-pager .record-pager-size { display: flex; align-items: center; gap: 2px; order: 2; font-size: inherit; }
.wb-pane-record-pager .record-pager-page { padding-inline: 2px; font-size: inherit; }
.wb-pane-record-pager :is(button, select) { height: 26px; min-height: 26px; margin: 0; padding-inline: 4px; font-size: inherit; }
.wb-pane-record-pager button { width: 26px; min-width: 26px; padding-inline: 0; }
.wb-pane-record-pager select { min-width: 50px; max-width: 60px; }
@media (pointer: coarse) { .wb-pane-record-pager :is(button, select) { height: 44px; min-height: 44px; } .wb-pane-record-pager button { width: 44px; min-width: 44px; } }
.wb-pane-record-scroll { min-height: 128px; min-width: 0; flex: 1 0 128px; overflow: auto; overscroll-behavior: none; scrollbar-gutter: stable; }
/* Both record surfaces stop at their content edge, including touch overscroll. */
.table-wrap:has(> :is(.history-table, .operation-table)) { overscroll-behavior: none; }
.wb-pane-record-table { min-width: 0; width: 100%; }
/* Cycle details span all original columns; raw fills remain horizontally scrollable. */
.history-position-cycle-detail > td[colspan] { max-width: none; overflow: visible; }
.history-position-cycle-detail details { width: 100%; }
.wb-pane-record-table.history-table { min-width: 0; }
/* 紀錄表頭常駐時要完全遮住捲過去的資料列。全域 th 主題使用半透明底色，
   若這裡不覆蓋，上一筆時間與文字會透到欄名後面。兩種紀錄只用同一個實色。 */
:is(.history-table, .operation-table) thead th,
.wb-pane-record-table thead { background: #182040; }
/* Sticky headers must paint above the avatar's positioned image and glow.
   Without an explicit table-header layer, scrolling rows cover header labels. */
:is(.history-table, .operation-table) thead th { z-index: 4; }
.wb-pane-record-table thead { position: sticky; top: 0; z-index: 3; }

/* 網站的縱向捲軸會讓 100dvw 比可見內容區多出捲軸寬，
   手機全螢幕最後一顆解鎖按鈕因此被裁掉。固定窗格以佈局視埠寬度為準。 */
html[data-host="web"] :is(
  .workbench-stage.is-single-fullscreen,
  .wb-focus-pane.is-fullscreen,
  .wb-grid-tile.is-fullscreen
) { width: 100%; }

/* 手機普通窗格使用穩定本機比例；遠端影格只以 contain 呈現，不回寫畫布高度。 */
@media (max-width: 700px) {
  html[data-host="web"] :is(.workbench-stage[data-layout="single"], .wb-grid-tile, .wb-focus-pane):not(.is-fullscreen):not(.is-single-fullscreen):has(.wb-stage-live) {
    height: auto; min-height: 0; max-height: none;
  }
  html[data-host="web"] :is(.workbench-stage[data-layout="single"], .wb-grid-tile, .wb-focus-pane):not(.is-fullscreen):not(.is-single-fullscreen) > .wb-stage-canvas:has(.wb-stage-live) {
    flex: 0 0 auto; height: auto; min-height: 0; aspect-ratio: 16 / 9;
  }
}
/* Safari 不保證支援 orientation.lock。直握手機時把整個可操作窗格旋成橫向；
   座標反轉由 screencastPoint 同步處理，不能只轉圖片造成點擊錯位。 */
@media (max-width: 700px) and (orientation: portrait) {
  html[data-host="web"] body.workbench-fullscreen-active { overflow: hidden; }
  html[data-host="web"] body.workbench-fullscreen-active :is(
    .workbench-stage.is-single-fullscreen,
    .wb-focus-pane.is-fullscreen,
    .wb-grid-tile.is-fullscreen
  ) {
    position: fixed; inset: 0 auto auto 0;
    width: 100dvh; height: 100dvw;
    max-width: none; max-height: none;
    transform-origin: top left;
    transform: translateX(100dvw) rotate(90deg);
  }
}

/* 每格都有自己的分組與機器人選擇；長名稱由選單處理，不把控制欄撐成整排。 */
.wb-stage-head > .wb-pane-picker {
  display: grid;
  grid-template-columns: minmax(128px, 140px) minmax(0, 230px);
  align-items: center;
  gap: 6px;
  width: min(100%, 376px);
}
.wb-stage-head .wb-pane-group { width: 100%; max-width: none; font-size: 12px; }
.workbench-panel[data-layout="grid"] .wb-stage-head .wb-pane-group { width: 100%; }
@container (max-width: 480px) {
  .wb-stage-head > .wb-pane-picker {
    grid-template-columns: minmax(110px, 138px) minmax(0, 1fr);
    width: 100%;
    height: 36px;
  }
}
.wb-pane-record-table.operation-table { table-layout: fixed; }
.wb-pane-record-table.operation-table th,
.wb-pane-record-table.operation-table td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bot-reconciling-warning > button:nth-of-type(1) { grid-area: inspect; }
.bot-reconciling-warning > button:nth-of-type(2) { grid-area: confirm; }
.wb-stage-notices [hidden] { display: none !important; }
.wb-stage-notices:has(+ .wb-stage-viewer-layer[hidden]):not(:has([data-wb="ack-reconcile"])) { display: none !important; }
.wb-stream-notice { position: absolute; inset: 4px 8px auto; z-index: 4; max-height: calc(100% - 8px); overflow: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; padding: 5px 8px; border: 1px solid rgba(255, 98, 121, .55); border-radius: 8px; color: #ffe8eb; background: rgba(75, 22, 32, .8); font-size: 12px; }
.wb-stream-notice > span { min-width: 0; }
.wb-stream-notice[hidden] { display: none !important; }
.wb-stream-notice [hidden] { display: none !important; }
.wb-stream-notice[data-stream-presentation="preparing"] { border-color: var(--border); color: var(--muted); background: var(--surface, #171c25); }
.wb-stream-notice > button { min-height: 30px; padding: 2px 8px; margin-left: auto; white-space: nowrap; }

/* 版面切換貼著工作台標題；每台機器人的完整紀錄由窗格內三態切換。 */
#internal-browse .workbench-page-heading { justify-content: flex-start; gap: 12px; }
#internal-browse .workbench-page-heading .workbench-route-title { flex: 0 0 auto; }
#internal-browse .workbench-bar { display: none; }

/* 保留鎖定狀態的明顯弱化，但買賣方向仍各有辨識色。 */
.wb-stage-rail .wb-grid-trade .qt-buy:not(:disabled) {
  color: #041d16;
  border-color: #9bf8d2;
  background: linear-gradient(145deg, #8df0c4, #42cfa4);
  box-shadow: inset 0 1px rgba(255,255,255,.35), 0 3px 12px rgba(31,207,151,.18);
}
.wb-stage-rail .wb-grid-trade .qt-sell:not(:disabled) {
  color: #2a0811;
  border-color: #ff9eae;
  background: linear-gradient(145deg, #ff9dab, #fa6c82);
  box-shadow: inset 0 1px rgba(255,255,255,.3), 0 3px 12px rgba(255,91,122,.16);
}
.wb-stage-rail .wb-grid-trade .qt-buy:disabled {
  color: #96c7b5;
  border-color: rgba(76,190,148,.26);
  background: linear-gradient(145deg, #263e3b, #1c3030);
}
.wb-stage-rail .wb-grid-trade .qt-sell:disabled {
  color: #d7a6ae;
  border-color: rgba(240,105,129,.26);
  background: linear-gradient(145deg, #402c39, #302530);
}
@media (max-width: 700px) { .wb-pane-record-pager { justify-content: flex-start; } }

/* Phone stage geometry stays viewport-based; record rows follow their pane. */
@media (max-width: 700px) {
  .workbench-stage[data-layout="grid"] {
    display: flex;
    flex-direction: column;
    height: auto;
    min-height: 0;
    overflow: visible;
  }
  .workbench-stage[data-layout="grid"] > .wb-grid-tile:not(.is-fullscreen):has(.wb-pane-record),
  .workbench-stage[data-layout="split"] > .wb-focus-pane:not(.is-fullscreen):has(.wb-pane-record) {
    flex: 0 0 auto;
    height: min(74dvh, 650px);
    max-height: min(74dvh, 650px);
    min-height: 440px;
  }
  :is(.wb-grid-tile, .wb-focus-pane):not(.is-fullscreen):has(.wb-pane-record) > .wb-stage-rail {
    grid-template-rows: auto;
  }
}
.wb-pane-record { container-type: inline-size; min-width: 0; min-height: 0; }
.wb-pane-record-controls { border-top: 0; border-bottom: 1px solid var(--border); }
.wb-pane-record-scroll { flex: 1 1 168px; min-height: 134px; }
/* Keep whole panes readable on short desktop viewports. The existing panel
   scrolls the grid; each pane retains its pager and original resize geometry. */
@media (min-width: 721px) {
  #internal-browse.panel.active[data-layout="grid"]:has(.wb-pane-record) { overflow-y: auto; }
  .workbench-stage[data-layout="grid"]:has(.wb-pane-record) { min-height: 808px; flex-shrink: 0; }
}
@media (min-width: 721px) and (max-width: 1000px) {
  .workbench-stage[data-layout="grid"]:has(.wb-pane-record) { min-height: 984px; }
}
/* The same rows expand in a narrow desktop tile and on a phone. */
@container (max-width: 680px) {
  .wb-pane-record-controls {
    display: flex;
    gap: 6px;
    padding: 7px;
    flex: 0 0 auto;
    flex-wrap: wrap;
    overflow-x: hidden;
    min-height: 50px;
  }
  .wb-pane-record-controls :is(select, input, button, a) {
    min-height: 36px;
    margin: 0;
  }
  .wb-pane-record-controls select[data-wb="record-side"] { flex: 0 0 100px; min-width: 100px; }
  .wb-pane-record-scroll { overflow-x: auto; padding: 4px 6px 10px; }
}

/* Shared popup surface: geometry comes from the anchor controller, while the
   same CSS bounds every menu/search list and keeps long labels inside it. */
:is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .wb-submenu, .symbol-menu) {
  box-sizing: border-box;
  min-inline-size: 0;
  max-inline-size: calc(100vw - 16px);
  max-inline-size: calc(100dvw - 16px);
  max-block-size: min(var(--qw-popup-available-height, 60dvh), calc(100dvh - 16px));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: #567b96 transparent;
}
:is(.collection-suggestions, .symbol-menu) { max-block-size: min(var(--qw-popup-available-height, 240px), calc(100dvh - 16px)); }
.wb-menu { inline-size: 240px; }
.wb-submenu { inline-size: 240px; }
/* A desktop submenu may extend sideways. Narrow/short layouts use the same
   submenu in flow instead of clipping it inside the parent scroll surface. */
@media (min-width: 761px) {
  .wb-menu:has(.wb-submenu:not([hidden])):not(.wb-menu-inline-submenu) { overflow: visible; }
}
.wb-menu-inline-submenu .wb-submenu {
  position: static;
  inline-size: 100%;
  margin: 4px 0;
  max-block-size: min(240px, 40dvh);
  box-shadow: none;
}
@media (max-width: 760px) {
  .wb-menu .wb-submenu {
    position: static;
    inline-size: 100%;
    margin: 4px 0;
    max-block-size: min(240px, 40dvh);
    box-shadow: none;
  }
}
:is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .symbol-menu) :is(button, .symbol-option) {
  box-sizing: border-box;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
  white-space: normal;
  transform: none;
}
.wb-pane-group-options .wb-bot-option { overflow-wrap: anywhere; }
.symbol-option-code { min-inline-size: 0; overflow-wrap: anywhere; }

/* Hover is a mouse affordance, never a sticky selected state on touch. Focus,
   keyboard selection and pressed state have the same visible theme surface. */
@media (hover: hover) and (pointer: fine) {
  :is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .symbol-menu) :is(button, .symbol-option):hover:not(:disabled) {
    background: #284960;
    color: #edf8ff;
    box-shadow: inset 0 0 0 1px #537b96;
  }
}
:is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .symbol-menu) :is(button, .symbol-option):is(:focus-visible, :active, [aria-selected="true"], [data-active="1"]):not(:disabled) {
  background: #284960;
  color: #edf8ff;
  box-shadow: inset 0 0 0 1px #6cacc9;
}
:is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .symbol-menu) :is(button, .symbol-option):focus-visible {
  outline: 2px solid var(--cyan, #91d9f6);
  outline-offset: -2px;
}
@media (hover: none), (pointer: coarse) {
  :is(.collection-suggestions, .workbench-tabs, .wb-empty-picker-menu, .wb-menu, .symbol-menu) :is(button, .symbol-option):hover:not(:active):not(:focus-visible):not([aria-selected="true"]):not([data-active="1"]):not(.active) {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    filter: none;
  }
}

/* Status/update icons share a real 16px column, including collapsed rail mode. */
.header-status :is(.system-status, .header-update-badge) { transform: none; }
.header-status .header-update-badge::before,
.header-status .system-status-icon {
  display: inline-flex;
  flex: 0 0 16px;
  inline-size: 16px;
  align-items: center;
  justify-content: center;
  margin: 0;
  line-height: 1;
  text-align: center;
}
/* A close glyph is an anchored control, not a floating call-to-action. The
   generic button hover transform must never replace its vertical centering. */
.key-field > .key-field-clear:is(:hover, :focus-visible, :active) { transform: translateY(-50%); }
.key-field-actions .key-field-clear:is(:hover, :focus-visible, :active),
.icon-button:is(:hover, :focus-visible, :active) { transform: none; }
:is(.panel:not(#internal-browse), dialog) :is(.key-field-clear, .icon-button):not(.qf-dialog-navigation-back):is(:hover, :focus-visible) {
  border-color: #d83c52;
  background: #d83c52;
  color: #fff;
}

/* Persistent controls use a translucent material; content remains readable.
   Apple Liquid Glass and LINE action-button guidelines informed the treatment. */
#dashboard .dashboard-bot-heading { justify-content: flex-start; gap: 18px; align-items: center; flex-wrap: wrap; }
#dashboard .running-bot-count { color: #d7f2ff; font-size: 21px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.3; }
#dashboard .qf-fleet-card.bot-card .bot-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 8px; padding-top: 0; }
#dashboard .qf-fleet-card .bot-status-tools { display: flex; align-items: center; gap: 6px; }
#dashboard .qf-fleet-card.bot-card:has(.bot-status-tools) { transform: none; }
#dashboard .qf-fleet-card.bot-card .bot-status-tools > button { box-sizing: border-box; width: 40px; min-width: 40px; max-width: 40px; height: 40px; min-height: 40px; max-height: 40px; padding: 0; align-self: center; transform: none; }
#dashboard .qf-fleet-card.bot-card .qf-fleet-status,
#dashboard .qf-fleet-card .bot-rescue-records { position: static; align-self: center; flex: 0 0 36px; width: 36px; height: 36px; min-width: 36px; min-height: 36px; padding: 0; border-radius: 10px; }
.rescue-repair-icon { display: block; width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.rescue-repair-action, #dashboard .qf-fleet-card .bot-rescue-records { display: grid; place-items: center; }
.rescue-repair-action { width: 40px; min-width: 40px; height: 40px; min-height: 40px; padding: 0; }
#systemStatusBtn { position: relative; }
#systemStatusBtn.system-status { border-color: rgba(143, 169, 196, .3); gap: 14px; }
#systemStatusBtn .system-status-icon { position: relative; flex: 0 0 24px; inline-size: 24px; block-size: 24px; color: #cfe0f2; overflow: visible; animation: none; }
#systemStatusBtn .notification-theme-icon { width: 20px; height: 20px; flex: 0 0 20px; }
#systemStatusBtn .system-health-mark { display: none; }
#systemStatusBtn:is(.error, .offline, .pending) .system-health-mark { display: block; fill: var(--red); stroke: var(--surface); stroke-width: .8px; }
#systemStatusBtn.pending .system-health-mark { fill: var(--amber); }
#systemStatusBtn .notification-badge { position: absolute; top: -5px; left: 10px; right: auto; box-sizing: border-box; display: grid; place-items: center; min-width: 16px; height: 16px; margin: 0; padding: 0 4px; border: 0; border-radius: 999px; font-size: 10px; font-weight: 700; line-height: 16px; font-variant-numeric: tabular-nums; pointer-events: none; }
#systemStatusBtn .notification-badge[hidden] { display: none; }
#aiAssistUseRecommended[hidden] { display: none; }
#aiAssistUseRecommended { justify-self: start; min-height: 38px; }
#systemStatusPanel .notification-bell { display: flex; min-height: 42px; justify-content: flex-start; gap: 8px; width: 100%; }
.notification-theme-icon { width: 20px; height: 20px; flex: 0 0 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* Confirmation keeps its original action and stays beside the notice. */
.bot-reconciling-warning:has(> button[data-wb="ack-reconcile"]) {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "title confirm" "detail confirm";
}
.bot-reconciling-warning > button[data-wb="ack-reconcile"] {
  grid-area: confirm;
  justify-self: end;
  min-height: 34px;
}

/* Manual inspection and original acknowledgement must never occupy one grid cell. */
.wb-stage-notices:has(> .bot-reconciling-warning > button[data-wb="inspect-connect"]):has(> .bot-reconciling-warning > button[data-wb="ack-reconcile"]) { max-height: none; }

.wb-stage-notices .bot-reconciling-warning:not(.order-review-inline):has(> button[data-wb="inspect-connect"]):has(> button[data-wb="ack-reconcile"]) {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "title confirm" "detail inspect";
  row-gap: 5px;
}
.wb-stage-notices .bot-reconciling-warning:not(.order-review-inline):has(> button[data-wb="inspect-connect"]):has(> button[data-wb="ack-reconcile"]) > span {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: anywhere;
}
.wb-stage-notices .bot-reconciling-warning:not(.order-review-inline):has(> button[data-wb="inspect-connect"]):has(> button[data-wb="ack-reconcile"]) > button {
  justify-self: end;
  max-width: 100%;
  white-space: nowrap;
  overflow-wrap: normal;
}
.wb-stage-notices .bot-reconciling-warning:not(.order-review-inline):has(> button[data-wb="inspect-connect"]):has(> button[data-wb="ack-reconcile"]) > button[data-wb="ack-reconcile"] { grid-area: confirm; }
.wb-stage-notices .bot-reconciling-warning:not(.order-review-inline):has(> button[data-wb="inspect-connect"]):has(> button[data-wb="ack-reconcile"]) > button[data-wb="inspect-connect"] { grid-area: inspect; }

/* One-line unknown-order summary; action authority stays in the original handlers. */
.bot-reconciling-warning.order-review-inline:has(> button[data-wb="ack-reconcile"]) {
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "title confirm inspect";
  column-gap: 6px;
  row-gap: 0;
}
.bot-reconciling-warning.order-review-inline:has(> button[data-wb="ack-reconcile"]):not(:has(> button[data-wb="inspect-connect"])) { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title confirm"; }
.wb-stage-notices .bot-reconciling-warning.order-review-inline > strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; }
.bot-reconciling-warning.order-review-inline > button[data-wb="inspect-connect"] { grid-area: inspect; }
.bot-reconciling-warning.order-review-inline > button { min-height: 32px; padding-inline: 8px; font-size: 12px; justify-self: end; }
@media (max-width: 700px), (pointer: coarse) {
  .bot-reconciling-warning.order-review-inline > button { min-height: 44px; }
}
#notificationDialogTitle { display: flex; align-items: center; gap: 8px; }
.rescue-bot-records { margin-top: 20px; border-top: 1px solid var(--border); padding-top: 12px; }
.rescue-dialog .rescue-chat-header { position: sticky; top: 0; z-index: 3; padding: 8px 0; background: var(--panel, #10192a); }
.rescue-dialog .rescue-chat-header h2 { font-size: clamp(20px, 3vw, 28px); overflow-wrap: anywhere; }
.rescue-dialog .rescue-chat-close { flex: 0 0 36px; }
#aiRescueConversationDialog[open] { display: flex; flex-direction: column; box-sizing: border-box; height: min(760px, calc(100dvh - 32px)); max-height: calc(100dvh - 32px); overflow: hidden; padding: 16px 20px; }
#aiRescueConversationDialog .rescue-chat-header { flex: 0 0 auto; position: static; padding: 0 0 8px; }
#aiRescueConversationDialog .rescue-chat-header h2 { font-size: 20px; }
#aiRescueConversationDialog .rescue-chat-toolbar { flex: 0 0 auto; margin: 4px 0; }
#aiRescueConversationDialog .rescue-chat-toolbar :is(select, button) { min-height: 36px; height: 36px; padding-block: 2px; }
#aiRescueConversationDialog > .field-help { flex: 0 0 auto; margin: 4px 0; font-size: 12px; }
#aiRescueConversationDialog > .field-help:empty { display: none; }
#aiRescueConversationDialog .rescue-chat-layout { flex: 1 1 0; min-height: 80px; overflow: hidden; gap: 12px; }
#aiRescueConversationDialog .rescue-chat-history { min-height: 0; overflow: auto; }
#aiRescueConversationDialog .rescue-chat-messages { box-sizing: border-box; min-height: 0; height: 100%; max-height: none; padding: 10px; border: 1px solid var(--border); border-radius: 12px; background: rgba(5, 12, 25, .24); }
#aiRescueConversationDialog .rescue-chat-message { width: fit-content; max-width: 92%; margin: 4px 0; border: 1px solid var(--border); }
#aiRescueConversationDialog .rescue-chat-message[data-role="user"] { align-self: flex-end; border-color: color-mix(in srgb, var(--cyan) 38%, var(--border)); background: color-mix(in srgb, var(--cyan) 12%, transparent); }
#aiRescueConversationDialog .rescue-chat-form { position: relative; flex: 0 0 auto; margin: 10px 0 0; }
#aiRescueConversationDialog .rescue-chat-form textarea { min-height: 72px; height: 72px; max-height: 120px; }
.rescue-composer-actions { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rescue-mention-add { flex: 0 0 36px; width: 36px; height: 36px; min-height: 36px; padding: 0; font-size: 24px; color: var(--text); border: 1px solid var(--border); background: var(--surface-2, #193449); }
.rescue-mention-chip { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 5px 10px; border: 1px solid color-mix(in srgb, var(--cyan) 35%, var(--border)); border-radius: 16px; color: var(--cyan); font-size: 12px; }
.rescue-composer-actions .rescue-chat-send { margin-left: auto; border: 1px solid color-mix(in srgb, var(--cyan) 45%, var(--border)); color: var(--text); background: color-mix(in srgb, var(--cyan) 20%, var(--surface-2, #193449)); }
.rescue-mention-picker { position: absolute; z-index: 5; bottom: calc(100% + 6px); inset-inline: 0; padding: 6px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel, #10192a); box-shadow: 0 12px 32px rgba(0, 0, 0, .4); }
.rescue-mention-picker[hidden], .rescue-mention-picker input[hidden] { display: none; }
.rescue-mention-picker input { box-sizing: border-box; width: 100%; min-height: 36px; margin-bottom: 6px; }
.rescue-mention-options { max-height: min(220px, 32dvh); overflow: auto; }
.rescue-mention-option { display: flex; flex-direction: column; align-items: start; gap: 3px; box-sizing: border-box; width: 100%; min-height: 44px; padding: 6px 10px; text-align: start; border: 0; background: transparent; transform: none; }
.rescue-mention-option small { color: var(--muted); font-size: 11px; overflow-wrap: anywhere; }
.rescue-mention-option:is(:hover, :focus-visible, [aria-selected="true"]) { background: color-mix(in srgb, var(--cyan) 16%, var(--surface)); transform: none; }
#aiRescueConversationDialog .rescue-bot-records { flex: 0 0 auto; margin-top: 8px; padding-top: 8px; }
#aiRescueConversationDialog .rescue-bot-record-list { max-height: min(160px, 22dvh); }
@media (max-width: 600px) {
  #aiRescueConversationDialog[open] { padding: 12px; width: calc(100vw - 20px); height: calc(100dvh - 20px); max-height: calc(100dvh - 20px); }
  #aiRescueConversationDialog .rescue-chat-toolbar select { flex-basis: 120px; }
  #aiRescueConversationDialog .rescue-chat-layout { grid-template-rows: auto minmax(0, 1fr); gap: 4px; }
  #aiRescueConversationDialog .rescue-chat-history { max-height: 100px; }
  .rescue-mention-add, .rescue-composer-actions .rescue-chat-send { height: 40px; min-height: 40px; }
}
.rescue-bot-records > summary { cursor: pointer; font-weight: 700; }
.rescue-bot-record-list { display: grid; gap: 10px; margin-top: 10px; max-height: 240px; overflow: auto; }
.rescue-bot-record { padding: 12px; border: 1px solid var(--border); border-radius: 12px; background: rgba(24, 44, 66, .35); }
.rescue-bot-record time { font-size: 12px; color: var(--muted); }
.rescue-bot-record p { margin: 6px 0 10px; overflow-wrap: anywhere; }
#internal-browse .wb-stage-tools > button,
#internal-browse .wb-layout-switch,
#dashboard .qf-fleet-card.bot-card .bot-rescue-records {
  background: linear-gradient(145deg, rgba(230, 248, 255, .14), rgba(21, 56, 78, .10) 48%, rgba(153, 206, 228, .08));
  border: 1px solid rgba(198, 235, 249, .28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .32), inset 0 -1px 0 rgba(128, 189, 211, .14), 0 4px 14px rgba(0, 8, 20, .18);
  backdrop-filter: blur(12px) saturate(155%);
  -webkit-backdrop-filter: blur(12px) saturate(155%);
}
#internal-browse .wb-stage-tools > button:is(:hover, :focus-visible),
#dashboard .qf-fleet-card.bot-card .bot-rescue-records:is(:hover, :focus-visible) { background-color: rgba(174, 224, 242, .14); border-color: rgba(220, 248, 255, .58); }
#internal-browse .wb-stage-tools > button[aria-pressed="true"] { background-color: rgba(45, 154, 190, .24); border-color: #91d9f6; color: #dffaff; }
@supports not (backdrop-filter: blur(12px)) {
  #internal-browse .wb-stage-tools > button, #internal-browse .wb-layout-switch, #dashboard .qf-fleet-card.bot-card .bot-rescue-records { background-color: #193449; }
}
@media (prefers-reduced-transparency: reduce) {
  #internal-browse .wb-stage-tools > button, #internal-browse .wb-layout-switch, #dashboard .qf-fleet-card.bot-card .bot-rescue-records { background: #193449; backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Compact web/mobile notices retain the original content and actions. */
.compact-notice-toggle { display: none; }
.compact-notice > .compact-notice-toggle { display: inline-grid; place-items: center; width: 36px; min-width: 36px; height: 36px; padding: 0; border-radius: 50%; color: inherit; background: transparent; }
.compact-notice:not(.compact-notice-open) > :not(.compact-notice-toggle) { display: none !important; }
#streamHealthBanner.compact-notice:not(.compact-notice-open), #haltBanner.compact-notice:not(.compact-notice-open), #toast.compact-notice:not(.compact-notice-open), .bot-reconciling-warning.compact-notice:not(.compact-notice-open) { display: inline-flex; width: 36px; min-width: 36px; max-width: 36px; padding: 0; min-height: 36px; gap: 0; }
.compact-notice.compact-notice-open { max-width: calc(100vw - 32px); }
#toast.compact-notice.show { pointer-events: auto; }
#toast.compact-notice:not(.show) { pointer-events: none; }
.compact-notice-open > .compact-notice-toggle { grid-column: 1 / -1; }

.compact-notice[hidden] { display: none !important; }

.account-capital-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:8px 0}.account-capital-grid>div{display:flex;flex-direction:column;min-width:0}.account-capital-grid span{font-size:12px;opacity:.75}.account-capital-grid strong{overflow-wrap:anywhere}.current-account-button{flex-shrink:0}

#accountCapitalDialog{max-width:min(680px,calc(100vw - 24px));max-height:calc(100dvh - 24px);overflow:auto}#accountCapitalDialog form{display:grid;gap:10px}#accountCapitalFields[hidden]{display:none}

/* R9 mobile fleet layout v1: retain one CSS mother and original actions.
   Reflow is observable through existing dashboard client logs; CSS grants no trading authority. */
@media (max-width: 760px) {
  #dashboard .bot-group-bar { --qw-mobile-fleet-layout: reflow-v1; flex-wrap: wrap; gap: 10px; min-width: 0; }
  #dashboard .bot-group-picker { flex: 1 1 100%; flex-wrap: wrap; min-width: 0; max-width: 100%; white-space: normal; }
  #dashboard .bot-group-picker select { flex: 1 1 160px; min-width: 0; max-width: 100%; min-height: 44px; }
  #dashboard .bot-group-count { flex: 1 1 100%; min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
  #dashboard .bot-group-bar > button { min-width: 44px; min-height: 44px; white-space: nowrap; }
  #dashboard .qf-fleet-card.bot-card .bot-head { grid-template-columns: minmax(0, 1fr); padding: 0; gap: 10px; }
  #dashboard .qf-fleet-card.bot-card .bot-status-tools { justify-self: end; }
  #dashboard .qf-fleet-card.bot-card .bot-status-tools > button { width: 44px; min-width: 44px; max-width: 44px; height: 44px; min-height: 44px; max-height: 44px; }
  #dashboard .qf-fleet-card.bot-card .bot-card-identity { gap: 10px; }
  #dashboard .qf-fleet-card.bot-card .bot-name-trigger { display: block; min-height: 44px; word-break: normal; overflow-wrap: anywhere; }
  #dashboard .qf-fleet-card.bot-card .bot-meta { word-break: normal; overflow-wrap: normal; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 44px; gap: 8px; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade .qt-buy { grid-column: 1; grid-row: 1; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade .qt-sell { grid-column: 2; grid-row: 1; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade .qt-lock { grid-column: 3; grid-row: 1; width: 44px; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade .qt-qty { grid-column: 1 / -1; grid-row: 2; grid-template-columns: 44px minmax(44px, 1fr) 44px; }
  #dashboard .qf-fleet-card.bot-card .bot-quick-trade :is(button,input) { min-width: 44px; min-height: 44px; white-space: nowrap; }
  #dashboard .qf-fleet-card.bot-card .bot-actions { flex-wrap: wrap; }
  #dashboard .qf-fleet-card.bot-card .bot-actions button { min-width: 44px; min-height: 44px; white-space: nowrap; }
}

/* Dashboard resources share the fleet card shell and UUID drag surface. */
#dashboard .dashboard-resource-card { box-sizing:border-box; min-width:0; border:1px solid var(--border); border-radius:18px; background:var(--surface); box-shadow:0 12px 30px #0002; }
#dashboard .dashboard-resource-card.account-card::before { display:none; }
#dashboard .account-card-head { padding:16px; }
#dashboard .account-details { padding-inline:16px; }
#dashboard .account-card-actions { flex-wrap:wrap; justify-content:flex-start; padding:12px 16px; }
#dashboard .account-card-actions .danger { margin-left:0; }
#dashboardAccountsPanel .account-manager { padding:0; background:transparent; border:0; box-shadow:none; }
#dashboardAccountsPanel .account-manager::before { display:none; }
#settings .settings-grid { align-items:start; }
#settings .settings-preferences-stack { display:grid; gap:20px; align-content:start; }
#settings #memberVaultPanel:empty { display:none; }
.notification-group { display:grid; gap:8px; }
.notification-group > summary { cursor:pointer; overflow-wrap:anywhere; }
.notification-group .notification-item { margin-top:8px; }

/* The account tab is a collection surface, without nested form-card gutters. */
#appShell #dashboardAccountsPanel .account-manager { padding:0; border:0; background:transparent; box-shadow:none; }
#appShell #dashboardAccountsPanel .account-manager-head { padding:0 0 16px; min-width:0; align-items:center; gap:12px; }
#appShell #dashboardAccountsPanel .account-manager-title { min-width:0; flex:1 1 180px; }
#appShell #dashboardAccountsPanel .account-manager-title > div { min-width:0; }
#appShell #dashboardAccountsPanel .account-manager-title p { margin:6px 0 0; }
#appShell #dashboardAccountsPanel .account-manager-title h2 { font-size:22px; }
#appShell #dashboardAccountsPanel .account-list-panel { padding:0; min-width:0; }
#appShell #dashboardAccountsPanel .account-list-heading { margin:8px 0 16px; }
#appShell #dashboardAccountsPanel .account-card { padding:20px; }
#appShell #dashboardAccountsPanel .account-card-head { padding:0 0 16px; gap:12px; }
#appShell #dashboardAccountsPanel .account-details { padding:0; margin:14px 0; }
#appShell #dashboardAccountsPanel .account-capital-grid { padding:12px 0; }
#appShell #dashboardAccountsPanel .account-card-actions { padding:12px 0 0; background:transparent; }
#appShell #dashboardAccountsPanel .account-card-title h4 { font-size:18px; }
@media (max-width:760px) {
  #appShell #dashboardAccountsPanel .account-manager-head { flex-wrap:wrap; }
  #appShell #dashboardAccountsPanel .account-manager-head > button { margin-left:auto; }
  #appShell #dashboardAccountsPanel .account-title-icon { display:none; }
  #appShell #dashboardAccountsPanel .account-card { padding:16px; }
}

/* Toast severity has one icon in either compact or expanded presentation. */
#toast .toast-icon { display: inline-grid; place-items: center; width: 22px; height: 22px; flex: 0 0 auto; font-weight: 800; }
#toast.compact-notice > .toast-icon { display: none !important; }
#toast.toast-warning { border-color: #b88938; background: #47351d; color: #ffe4ab; }

#toast.compact-notice.compact-notice-open { width: min(390px, calc(100vw - 52px)); max-width: calc(100vw - 52px); padding: 16px 44px 16px 12px; box-sizing: border-box; }
#toast .toast-text { min-width: 0; overflow-wrap: anywhere; }

/* Two selectors and their drag handle share row one; narrow pane tools use row two. */
@container (max-width: 680px) {
  .wb-stage-rail { grid-template-rows: auto auto; }
  .wb-stage-rail > .wb-stage-head.wb-stage-head,
  html[data-host="web"] .wb-stage-rail > .wb-stage-head.wb-stage-head {
    grid-template-columns: 22px minmax(0, 1fr);
    grid-template-rows: 36px auto;
    height: auto;
    min-height: 0;
    gap: 4px 6px;
    padding: 4px;
  }
  .wb-stage-head > .wb-pane-drag-handle { grid-column: 1; grid-row: 1; }
  .wb-stage-head > .wb-pane-picker,
  html[data-host="web"] .wb-stage-head > .wb-pane-picker {
    grid-column: 2;
    grid-row: 1;
    grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
    width: 100%;
    height: 36px;
    min-height: 36px;
    gap: 6px;
  }
  .wb-stage-head .wb-pane-group-picker > summary,
  .wb-stage-head .wb-pane-combined-picker > summary {
    box-sizing: border-box;
    height: 36px;
    min-height: 36px;
    padding-block: 0;
  }
  .wb-stage-head > .wb-stage-tools { grid-column: 1 / -1; grid-row: 2; }
}

.bot-missed-order-policy { display: grid; gap: 10px; min-width: 0; }
.bot-missed-order-policy[hidden] { display: none; }
.bot-missed-order-policy-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px auto minmax(0, 1.4fr);
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.bot-missed-order-policy-row label { margin: 0; }
.bot-missed-order-policy-row input,
.bot-missed-order-policy-row select { min-width: 0; width: 100%; }
@media (max-width: 480px) {
  .bot-missed-order-policy-row { grid-template-columns: minmax(0, 1fr) 84px auto; }
  .bot-missed-order-policy-row select { grid-column: 1 / -1; }
}

.wb-stage-rail > .wb-stage-head.wb-stage-head,
html[data-host="web"] .wb-stage-rail > .wb-stage-head.wb-stage-head { grid-template-columns: 20px minmax(0, 1fr); grid-template-rows: auto auto; gap: 8px; min-height: 48px; height: auto; padding: 6px 8px; }
.wb-stage-head > .wb-pane-picker,
html[data-host="web"] .wb-stage-head > .wb-pane-picker { grid-column: 2; grid-row: 1; display: grid; grid-template-columns: minmax(104px, .35fr) minmax(0, 1.65fr); gap: 8px; min-width: 0; width: 100%; height: auto; min-height: 44px; }
.wb-stage-head .wb-pane-group-picker > summary,
.wb-stage-head .wb-pane-combined-picker > summary { height: 44px; min-height: 44px; padding: 0 9px; font-size: 14px; }
.wb-stage-head > .wb-stage-tools { grid-column: 1 / -1; grid-row: 2; gap: 6px; height: auto; min-height: 38px; padding: 0; justify-content: flex-end; }
/* One row when the pane can retain a readable bot name beside the tools. */
@container (min-width: 580px) {
  .wb-stage-rail > .wb-stage-head.wb-stage-head,
  html[data-host="web"] .wb-stage-rail > .wb-stage-head.wb-stage-head { grid-template-columns: 12px minmax(0, 1fr) auto; grid-template-rows: auto; gap: 6px; }
  .wb-stage-head > .wb-pane-picker,
  html[data-host="web"] .wb-stage-head > .wb-pane-picker { grid-template-columns: minmax(104px, 112px) minmax(0, 1fr); gap: 6px; }
  .wb-stage-head > .wb-stage-tools { grid-column: 3; grid-row: 1; }
}
.wb-stage-head .wb-pane-tabs { grid-template-columns: repeat(3, 36px); }
.wb-stage-head .wb-pane-tabs button, .wb-stage-head .wb-stage-window-tools > button { width: 36px; min-width: 36px; height: 36px; min-height: 36px; padding: 6px; }
.wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-row { grid-template-columns: 9px 32px minmax(0, 1fr); }
.wb-stage-head .wb-pane-combined-picker > summary .bot-avatar-display { width: 32px; min-width: 32px; max-width: 32px; height: 32px; min-height: 32px; max-height: 32px; aspect-ratio: 1; }
.wb-stage-head .wb-pane-combined-picker > summary .wb-bot-picker-name { font-size: 14px; }
.wb-menu-action-icon { width: 17px; height: 17px; flex: 0 0 17px; margin-right: 8px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.wb-menu button[data-menu] { display: flex; align-items: center; }
.account-platform-heading { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; margin: 8px 0 0; }
.account-platform-heading img { width: 24px; height: 24px; object-fit: contain; }
.account-status-line { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.account-status-line .account-status { white-space: nowrap; }
.notification-review-button { min-height: 44px; white-space: nowrap; }
.ai-conversation-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 12px; }
.ai-conversation-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; padding: 16px; border: 1px solid var(--border, #39404c); border-radius: 12px; min-width: 0; }
.ai-conversation-card-open { text-align: left; overflow-wrap: anywhere; min-width: 0; background: transparent; border: 0; color: inherit; font: inherit; font-weight: 600; cursor: pointer; }
.ai-conversation-card small { grid-column: 1 / -1; color: var(--muted, #929aaa); }
.ai-conversation-rescue-status { display: flex; gap: 8px; align-items: start; }
.ai-conversation-rescue-status [data-bound="false"] { opacity: .4; }
.ai-conversation-rescue-status [data-bound="true"] { color: var(--accent, #60a5fa); }
.ai-conversation-binding-controls { display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 480px) {
  .ai-conversation-card { padding: 12px; }
  .ai-conversation-binding-controls > button { flex: 1; min-width: 120px; }
}
.settings-grid { align-items: start; gap: 16px; }
.settings-grid > .interface-card { grid-column: 1 / -1; }
.settings-grid > .about-card { grid-column: 1 / -1; }

.settings-startup-stack { display: grid; align-content: start; gap: 16px; min-width: 0; }

@media (max-width: 700px) {
  #dashboardAccountsPanel .account-card-head { flex-wrap: wrap; }
  #dashboardAccountsPanel .account-status-line { flex-basis: 100%; justify-content: flex-end; }
}

/* Operation account evidence is an event snapshot; account trade controls are view-only. */
.wb-account-record-title { font-size: 16px; }
.wb-pane-record-controls > label { display: grid; gap: 4px; flex: 1 1 160px; min-width: min(160px, 100%); max-width: 100%; margin: 0; }
.wb-pane-record-controls > label > select { flex: initial; width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box; }
.operation-table td:nth-child(2) { overflow-wrap: anywhere; }

/* Pane density follows the card on desktop and mobile; record rows retain
   a 44px interaction target without inheriting full-page cell heights. */
.wb-pane-record-table > thead > tr > th { box-sizing: border-box; height: 36px; padding-block: 4px; line-height: 1.35; }
.wb-pane-record-table > tbody > tr > td { box-sizing: border-box; height: 44px; padding-block: 6px; line-height: 1.35; }

/* Record tools share one target size. Range fields expand in the existing
   controls flow so nested workbench clipping cannot cut off the date panel. */
.wb-pane-record-controls:has(.wb-record-tool) { overflow: visible; }
.wb-pane-record-controls:has(.wb-record-date-popover:not([hidden])) { flex: 0 0 auto; min-height: 48px; max-height: calc(100% - 80px); overflow: auto; }
.wb-record-date-control { display: contents; }
.wb-pane-record-controls .wb-record-tool { position: relative; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 40px; box-sizing: border-box; width: 40px; min-width: 40px; max-width: 40px; height: 40px; min-height: 40px; padding: 0; line-height: 1; }
.wb-record-tool > svg { width: 18px; height: 18px; flex: 0 0 18px; }
.wb-record-tooltip { position: absolute; top: calc(100% + 6px); right: 0; z-index: 90; display: none; width: max-content; max-width: min(240px, calc(100vw - 32px)); padding: 6px 9px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface, #10192c); color: var(--text); font-size: 12px; line-height: 1.4; font-weight: 400; white-space: normal; pointer-events: none; box-shadow: 0 5px 16px #0005; }
.wb-record-tool:not([data-tooltip-dismissed="true"]):focus-visible .wb-record-tooltip { display: block; }
@media (hover: hover) and (pointer: fine) {
  .wb-record-tool:not([data-tooltip-dismissed="true"]):hover .wb-record-tooltip { display: block; }
}
.wb-record-date-popover { display: flex; flex: 1 1 100%; order: 10; flex-wrap: wrap; align-items: end; gap: 8px; min-width: 0; box-sizing: border-box; width: 100%; padding: 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface, #10192c); }
.wb-record-date-popover[hidden] { display: none !important; }
.wb-record-date-popover > label { flex: 1 1 140px; min-width: 0; margin: 0; font-size: 12px; }
.wb-pane-record-controls .wb-record-date-popover input[type="date"] { display: block; box-sizing: border-box; width: 100%; min-width: 0; max-width: none; height: 40px; min-height: 40px; padding: 6px 8px; }
.wb-record-date-popover input[type="date"]::-webkit-datetime-edit { display: inline-block; }
.wb-record-date-popover input[type="date"]::-webkit-calendar-picker-indicator { margin: 0; }
.wb-record-date-shortcuts { display: flex; flex: 1 1 100%; flex-wrap: wrap; gap: 6px; min-width: 0; }
.wb-pane-record-controls .wb-record-date-popover button { height: 36px; min-height: 36px; padding: 0 10px; }
.wb-record-date-popover :is(p, small) { flex-basis: 100%; margin: 0; color: var(--muted); font-size: 12px; }

/* One hierarchy for peer headings and body copy; compact records keep their own density. */
:root { --qw-section-size: 20px; --qw-subsection-size: 16px; --qw-body-size: 14px; }
.subsection-heading h2, .template-head h2, .settings-card h2 { font-size: var(--qw-section-size); line-height: 1.35; }
.alert-block-head h3, .webhook-allowlist-group h3 { font-size: var(--qw-subsection-size); line-height: 1.4; }
.form-card > p, .template-head p, .alert-fields, .alert-rules { font-size: var(--qw-body-size); line-height: 1.6; }
.account-details, .account-detail-row, .account-detail-row dd { min-width: 0; }
/* Labels take their actual width; the complete username uses the remaining value column. */
#dashboardAccountsPanel .account-detail-row:has(.account-username) { grid-template-columns: max-content minmax(0, 1fr); column-gap: 12px; }
.account-detail-row .account-username { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--qw-body-size); }
.primary, .start-all.primary { background: var(--qf-primary-background, linear-gradient(135deg, #2579ef, #25a5e8)); border-color: var(--qf-primary-border, #2579ef); color: var(--qf-primary-text, #fff); }
.start-all.primary:hover:not(:disabled) { filter: brightness(1.12); }
.wb-stage-head { container-type: inline-size; }
@container (max-width: 260px) {
  .wb-stage-head > .wb-pane-picker { grid-template-columns: minmax(0, 1fr); }
  .wb-stage-head .wb-pane-group-picker > summary { min-height: 36px; height: 36px; }
  .wb-stage-head .wb-stage-tools { flex-wrap: wrap; }
}

/* Overview uses the shared record calendar; dates follow each broker report calendar. */
.overview-period-control { display:flex; flex-wrap:wrap; align-items:center; gap:8px; min-width:0; max-width:100%; margin:8px 0; }
#overviewPeriodLabel { overflow-wrap:anywhere; font-size:13px; }
#overviewPeriodCalendar { flex:1 1 100%; min-width:0; max-width:100%; }
#overviewPeriodCalendar .wb-record-date-control { min-width:0; max-width:100%; flex-wrap:wrap; }
#overviewPeriodCalendar input[type="date"] { display:block; box-sizing:border-box; width:100%; min-width:0; max-width:100%; height:40px; }
#overviewPeriodCalendar .wb-record-date-shortcuts { display:flex; flex-wrap:wrap; gap:6px; }
#overviewPeriodCalendar button { min-height:40px; max-width:100%; }

/* Keep the loading message visible before horizontally scrollable record rows arrive. */
.workbench-log .record-sync-status {
  display: block;
  max-inline-size: calc(100vw - 7rem);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Record scroll owns one sticky header; cells retain resize-handle positioning. */
:is(.wb-pane-record-scroll, .workbench-log) > :is(.history-table, .operation-table) { border-collapse: separate; border-spacing: 0; }
:is(.wb-pane-record-scroll, .workbench-log) > :is(.history-table, .operation-table) > thead { position: sticky; inset-block-start: 0; z-index: 4; background: #182040; }
:is(.wb-pane-record-scroll, .workbench-log) > :is(.history-table, .operation-table) > thead > tr > th { position: relative; inset-block-start: auto; background: #182040; }
.wb-pane-record-scroll { padding-block-start: 0; }

/* Initial record hydration stays inside its existing scroll surface. */
:is(.wb-pane-record-scroll, .workbench-log) > table:has(.record-loading-cell) { block-size: 100%; }
:is(.wb-pane-record-scroll, .workbench-log) .record-loading-cell { vertical-align: middle; padding: 0; border: 0; }
:is(.wb-pane-record-scroll, .workbench-log) .record-loading-cell .record-sync-status { display: flex; align-items: center; justify-content: center; gap: 8px; inline-size: 100%; max-inline-size: none; margin: 0; white-space: normal; overflow-wrap: anywhere; }
.wb-pane-record td.record-cache-sync-cell { block-size: 36px; box-sizing: border-box; padding: 3px 8px; overflow: visible; white-space: normal; }
.wb-pane-record .record-cache-sync-cell .record-sync-status { position: sticky; inset-inline-start: 8px; display: flex; align-items: center; gap: 8px; inline-size: max-content; max-inline-size: min(calc(100cqw - 40px), calc(100vw - 7rem)); white-space: normal; overflow-wrap: anywhere; }
.wb-pane-record .record-cache-sync-copy { min-inline-size: 0; line-height: 18px; }
@media (max-width: 600px) { .wb-pane-record .record-cache-sync-cell { padding: 3px 8px; } }
@media (pointer: coarse) { .wb-pane-record .record-cache-sync-cell { block-size: 44px; } }
/* Keep the shared filter controls compact in narrow tiles. */
@container (max-width: 440px) {
  .wb-pane-record-controls { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 40px 40px 40px; gap: 4px; padding: 5px; }
  .wb-pane-record-controls:not(:has([data-wb="record-side"])) { grid-template-columns: minmax(0, 1fr) 40px 40px; }
  .wb-pane-record-controls input[data-wb="record-search"] { grid-column: 1 / -1; width: 100%; max-width: none; min-width: 0; }
  .wb-pane-record-controls select, .wb-pane-record-controls select[data-wb="record-side"] { width: 100%; min-width: 0; max-width: none; padding-inline: 5px 18px; }
  .wb-pane-record-scroll { flex: 1 1 168px; min-height: 134px; }
  .wb-pane-record-table.history-table { min-width: 1180px; table-layout: fixed; }
  .wb-pane-record-table.history-table :is(th, td):nth-child(1) { width: 112px; }
  .wb-pane-record-table.history-table :is(th, td):nth-child(2) { width: 128px; }
  .wb-pane-record-table.history-table :is(th, td):nth-child(3) { width: 96px; }
}
.record-sync-spinner { display: inline-block; inline-size: 14px; block-size: 14px; box-sizing: border-box; flex: 0 0 14px; border: 2px solid currentColor; border-inline-end-color: transparent; border-radius: 50%; animation: record-sync-spin .75s linear infinite; }
@keyframes record-sync-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .record-sync-spinner { animation: none; } }
/* Local presentation only; original card draft/catalog/send owners remain unchanged. */
.ai-chat-instruction-draft{position:relative;min-width:0}
.ai-chat-instruction-draft[hidden],.ai-chat-instruction-options[hidden],.ai-chat-instruction-error[hidden]{display:none}
.ai-chat-instruction-chips{display:flex;flex-wrap:wrap;gap:4px;min-width:0}
.ai-chat-instruction-chip{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;padding-inline-start:8px;border:1px solid var(--border,#394354);border-radius:12px;background:var(--surface-2,#193449);font-size:var(--fs-sm,14px)}
.ai-chat-instruction-chip>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ai-chat-instruction-chip>button{flex:0 0 32px;width:32px;min-width:32px;min-height:32px;padding:0;border:0;background:transparent;color:inherit}
.ai-chat-instruction-options{position:absolute;inset-inline:0;bottom:calc(100% + 4px);z-index:36;display:grid;gap:2px;max-height:176px;overflow:auto;overscroll-behavior:contain;padding:4px;border:1px solid var(--border,#394354);border-radius:12px;background:var(--card-bg,#131b25);box-shadow:0 8px 24px #0006}
.ai-chat-instruction-options>button{width:100%;min-width:0;min-height:36px;padding:6px 10px;text-align:start;white-space:normal;overflow-wrap:anywhere;font-size:var(--fs-sm,14px)}
.ai-chat-instruction-options>button[aria-selected=true]{background:var(--surface-2,#193449);outline:1px solid var(--cyan,#7bcaff);outline-offset:-1px}
.ai-chat-instruction-error{display:block;font-size:var(--fs-sm,14px);line-height:1.4;color:var(--muted,#a4adbd)}
@media(pointer:coarse){.ai-chat-instruction-chip>button{flex-basis:44px;width:44px;min-width:44px;min-height:44px}.ai-chat-instruction-options>button{min-height:44px}}

/* Original metric/card owners: keep a number atomic and fullscreen inside its viewport. */
#dashboard .ai-chat-card.is-presentation-fullscreen {
  min-height: 0;
  max-height: calc(100dvh - var(--desktop-titlebar-height, 0px));
}
html[data-host="tauri"] #dashboard .ai-chat-card.is-presentation-fullscreen {
  max-height: calc(100dvh - var(--qw-titlebar-h, 44px));
}

/* Live image presentation only; remote viewport and input channel stay owned by the existing viewer. */
.wb-stage-live.is-presentation-zoomed { overflow: hidden; }
.wb-stage-img { transform-origin: center; }

/* Healthy foreign viewing needs only the explicit operation entry. */
.wb-stream-notice[data-stream-presentation="observer"] { inset: 6px 8px auto auto; width: max-content; max-width: calc(100% - 16px); max-height: none; overflow: visible; gap: 0; padding: 0; border: 0; color: var(--text); background: transparent; }
.wb-stream-notice[data-stream-presentation="observer"] > :not([data-viewport-operate]) { display: none; }
.wb-stream-notice[data-stream-presentation="observer"] > [data-viewport-operate] { margin: 0; }

/* Diagnostics share the bounded, scrollable problem row, never broker pixels. */
.wb-stage-problem-layer > .wb-stream-notice,
.wb-stage-problem-layer > .wb-stream-notice[data-stream-presentation="observer"] {
  position: static;
  inset: auto;
  z-index: auto;
  width: auto;
  max-width: 100%;
  max-height: none;
  box-sizing: border-box;
}

.wb-problem-carousel { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch; gap: 6px; block-size: 56px; min-width: 0; }
.wb-problem-pages { min-width: 0; min-height: 0; overflow: hidden; }
.wb-problem-pages > .wb-stage-problem-strip { box-sizing: border-box; block-size: 100%; overflow: hidden auto; padding: 6px 8px; font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
.wb-problem-pages > .wb-stage-problem-strip > strong { margin-inline-end: 8px; }
.wb-problem-pages > .wb-stage-problem-strip[hidden], .wb-problem-nav[hidden] { display: none !important; }
.wb-problem-nav { display: flex; align-items: center; gap: 4px; min-width: 0; white-space: nowrap; font-size: 12px; }
.wb-problem-nav > button { flex: none; min-width: 28px; min-height: 32px; padding: 3px 6px; }
.wb-problem-nav > [data-wb-problem-count] { white-space: normal; max-width: 5em; text-align: center; }
.wb-problem-carousel:has([data-wb-problem-item="connection-recovery"]) { block-size: 96px; }
.wb-problem-pages > [data-wb-problem-item="connection-recovery"] { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto minmax(0, 1fr); gap: 4px 8px; overflow: hidden; }
[data-wb-problem-item="connection-recovery"] > strong { grid-column: 1; grid-row: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
[data-wb-problem-item="connection-recovery"] > span { grid-column: 1; grid-row: 2; min-height: 0; max-height: 100%; overflow: auto; }
[data-wb-problem-item="connection-recovery"] > [data-wb="connection-retry"] { grid-column: 2; grid-row: 1; }
[data-wb-problem-item="connection-recovery"] > [data-wb="connection-stop"] { grid-column: 2; grid-row: 2; align-self: start; }
@media (max-width: 720px) { .wb-problem-carousel { block-size: 96px; } }

/* Only visible diagnostics consume canvas space. The existing canvas resize
   observer handles the changed local box without restarting its stream. */
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile):has(> .wb-stage-viewer-layer:not([hidden])) > .wb-stage-problem-layer {
  block-size: auto;
  min-block-size: 0;
  max-block-size: 72px;
  box-sizing: border-box;
  align-self: stretch;
  align-content: start;
  grid-auto-rows: max-content;
  overflow: hidden auto;
  overscroll-behavior: contain;
  pointer-events: auto;
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile):has(> .wb-stage-viewer-layer:not([hidden])) > .wb-stage-problem-layer:has([data-wb-problem-item="connection-recovery"]) {
  max-block-size: 112px;
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile):has(> .wb-stage-viewer-layer:not([hidden])) > .wb-stage-problem-layer:not(:has(> .wb-stage-problem-content > :not([hidden]), > .wb-stream-notice:not([hidden]))) {
  display: none !important;
}
:is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile):has(> .wb-stage-viewer-layer:not([hidden])) > .wb-stage-problem-layer[hidden] {
  display: none !important;
  visibility: hidden;
  pointer-events: none;
}
@media (max-width: 720px) {
  :is(.workbench-stage[data-layout="single"], .workbench-stage[data-layout="split"] .wb-focus-pane, .workbench-stage[data-layout="grid"] .wb-grid-tile):has(> .wb-stage-viewer-layer:not([hidden])) > .wb-stage-problem-layer {
    max-block-size: 112px;
  }
}

/* One header presentation for dialogs, detail pages and the image viewer.
   Equal side tracks keep the real title centred regardless of button width. */
:is(.dialog-title, .qf-detail-header, .shot-viewer-bar, .overview-pnl-settings-head, .rescue-chat-header, header).qf-dialog-navigation {
  display: grid;
  grid-template-columns: minmax(76px, 1fr) minmax(0, 2fr) minmax(76px, 1fr);
  align-items: center;
  column-gap: 8px;
  row-gap: 8px;
  padding-inline: 16px;
  min-width: 0;
  box-sizing: border-box;
}
.qf-dialog-navigation .qf-dialog-navigation-copy { display: contents; }
.qf-dialog-navigation .qf-dialog-navigation-title {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
  max-width: 100%;
  margin: 0;
  text-align: center;
  overflow-wrap: anywhere;
  justify-self: stretch;
}
.qf-dialog-navigation-copy > :not(.qf-dialog-navigation-title):not(.qf-dialog-navigation-copy) {
  grid-column: 1 / -1;
  min-width: 0;
  text-align: center;
}
/* 「〈返回」唯一母版（2026-10-18）：對話框、抽屜、整頁共用。⛔ 不得在其他地方另寫返回鈕外觀。 */
.qf-dialog-navigation-back,
.qf-dialog-navigation .qf-dialog-navigation-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  justify-self: start;
  align-self: center;
  width: auto;
  min-width: 0;
  min-height: 40px;
  height: auto;
  margin: 0;
  padding: 0 16px 0 12px;
  border: 1px solid rgba(190, 198, 255, .16);
  border-radius: 999px;
  background: rgba(255, 255, 255, .05);
  color: var(--text, #eef2ff);
  box-shadow: none;
  font: 600 15px/1 inherit;
  font-family: inherit;
  white-space: nowrap;
  text-align: left;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .15s ease;
}
.qf-dialog-navigation .qf-dialog-navigation-back { grid-column: 1; grid-row: 1; }
.qf-dialog-navigation-back:hover { background: rgba(255, 255, 255, .10); border-color: rgba(190, 198, 255, .30); }
.qf-dialog-navigation-back:active { transform: translateY(1px); }
.qf-dialog-navigation-back:disabled { opacity: .45; cursor: not-allowed; }
.qf-dialog-navigation-back > svg { display: none; }
.qf-dialog-navigation-back:focus-visible { outline: 2px solid var(--accent, #84aaff); outline-offset: 3px; }
.qf-dialog-navigation-back[hidden] { display: none !important; }
.qf-dialog-navigation > .qf-dialog-navigation-tools { grid-column: 3; grid-row: 1; justify-self: end; min-width: 0; }
@media (max-width: 600px) {
  :is(.dialog-title, .qf-detail-header, .shot-viewer-bar, .overview-pnl-settings-head, .rescue-chat-header, header).qf-dialog-navigation { grid-template-columns: minmax(64px, 1fr) minmax(0, 2fr) minmax(64px, 1fr); }
  .qf-dialog-navigation > .shot-viewer-tools { grid-column: 1 / -1; grid-row: 2; justify-self: center; flex-wrap: wrap; }
}
/* F3: duplicate alerts placed no order (app.js deliveryDuplicateBadge). */
.delivery-status.duplicate { color: #ffd38a; background: rgba(90,62,14,.7); border-color: rgba(255,200,90,.25); margin-left: 6px; }

/* TradingView account / bot fields (P3). The global `label { display: block }`
   overrides the browser's [hidden] rule, so a hidden label stayed visible
   (username/password under a browser-login broker, the generic 類別 select). */
#accountDialog .credential-form label[hidden],
.tv-account-fields[hidden],
.tv-bot-fields[hidden] { display: none !important; }
.tv-account-fields { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; margin: 0; padding: 0; border: 0; }
.tv-account-fields > label:first-child,
.tv-account-fields > .account-env-note,
.tv-account-fields > .form-grid-full { grid-column: 1 / -1; }
.tv-account-fields textarea { width: 100%; box-sizing: border-box; }
.tv-bot-fields { border: 1px solid var(--border, rgba(255,255,255,.12)); border-radius: 10px; padding: 12px 16px; }
.bot-tv-summary { margin: 0 0 8px; color: var(--muted); line-height: 1.6; }
/* TradingView real-money limits (P4). */
.tv-live-limits[hidden], #accountTvConfirmLive[hidden] { display: none !important; }
.tv-live-limits { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; margin: 8px 0 0; padding: 12px 16px;
  border: 1px solid rgba(255, 180, 180, .35); border-radius: 10px; }
.tv-live-limits > legend { padding: 0 6px; color: #ffb4b4; }
.tv-live-limits > .account-env-note, .tv-live-limits > button { grid-column: 1 / -1; }
/* 類別兩層（2026-10-21）：Live／Demo → 子分類。#accountEnvironment 是值的主人（視覺隱藏、仍 required）。 */
.account-env-field { position: relative; }
.account-env-field .account-env-native {
  position: absolute; inset: 0 auto auto 0; width: 1px !important; height: 1px !important; min-width: 0 !important; min-height: 0 !important;
  padding: 0; margin: 0; border: 0; clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.account-env-tiers { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.account-env-tier {
  min-height: 52px; border-radius: 12px; border: 1px solid var(--border, #34435d);
  background: var(--input-bg, #09121e); color: var(--text, #eaf2ff); font: inherit; font-size: 17px; font-weight: 700; cursor: pointer;
}
.account-env-tier.is-selected { border-color: var(--accent, #7ddfff); background: #16314a; box-shadow: inset 0 0 0 1px var(--accent, #7ddfff); }
.account-env-tier[data-env-tier="live"].is-selected { border-color: #ffb4b4; background: #3a1c22; box-shadow: inset 0 0 0 1px #ffb4b4; }
.account-env-tier:disabled { opacity: .45; cursor: not-allowed; }
.account-env-subs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.account-env-subs:empty { display: none; }
.credential-form .account-env-tier, .credential-form .account-env-sub { margin: 0; align-self: auto; }
.account-env-sub {
  min-height: 40px; padding: 6px 16px; border-radius: 999px; border: 1px solid var(--border, #34435d);
  background: transparent; color: var(--text, #eaf2ff); font: inherit; cursor: pointer;
}
.account-env-sub small { margin-left: 6px; color: #ffb4b4; font-size: 13px; }
.account-env-sub.is-selected { border-color: var(--accent, #7ddfff); background: #16314a; }
.account-env-sub:disabled { opacity: .45; cursor: not-allowed; }
.account-env-tier:focus-visible, .account-env-sub:focus-visible { outline: 2px solid var(--accent, #7ddfff); outline-offset: 2px; }
.account-credential-heading { grid-column: 1 / -1; margin: 0 0 4px; color: var(--muted); font-size: 14px; line-height: 1.55; }
.account-credential-heading[hidden] { display: none !important; }
.account-credential-heading.is-locked { color: #ffb4b4; }
.account-clear-credentials { display: flex !important; align-items: center; gap: 8px; }
#accountDialog .credential-form label.account-clear-credentials[hidden] { display: none !important; }
#botTvBrokerField[hidden] { display: none !important; }
.wb-stage-img.is-external-signin-locked { filter: grayscale(1) brightness(.55); pointer-events: none; }
.wb-external-signin-lock { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center; padding: 24px; text-align: center; color: #fff; background: rgba(15,23,42,.22); cursor: not-allowed; }
.wb-external-signin-lock[hidden] { display: none; }
.account-login-actions { display: flex; gap: 10px; flex-wrap: wrap; }
