/* Signova 台股智慧選股 —— 設計系統
   深色專業金融風：底色分層、青藍紫品牌漸層、台股慣例紅漲綠跌、
   AI 分數三階色、統一元件庫（按鈕/卡片/徽章/表格/tabs/modal/skeleton/toast）。
   手機優先、768/1024 斷點響應式；prefers-reduced-motion 尊重。 */

:root {
  /* 主題工程：色彩配色由 --color-scheme 代幣決定（預設 dark，淺色主題區塊
     覆寫成 light），fallback 保留 dark，任何未定義情境維持現行深色外觀。 */
  color-scheme: var(--color-scheme, dark);
  /* ---- 底色分層 ---- */
  --bg-0: #0b0f1a;
  --bg-1: #0e1424;
  --bg-2: #101a30;
  --card-bg: #151f33;
  --card-bg-hover: #182644;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.14);

  /* ---- 文字層級 ---- */
  --text: #e8eefb;
  --text-muted: #8fa3c8;
  /* 對比修復（SEO/AEO 修復波 2026-08-01）：原值 #5b6b83 在深色四層底上的
     對比只有 2.77～3.53（--bg-0 3.53／--bg-1 3.39／--bg-2 3.20／--card-bg 3.04／
     --card-bg-hover 2.77），連 WCAG AA 大字的 3:1 都過不了，正文的 4.5:1 更
     不用說——而 --text-faint 實際掛的是資料基準日、附註、輔助說明這類**正文
     等級的小字**。改成 #7e8ea5：五層底最差 4.50，全部達標；仍明顯淡於
     --text-dim(#8b95a7) 與 --text-muted(#8fa3c8)，三層文字階序不變。
     淺色三主題的 --text-faint 於 2026-07-28 已各自修過（4.77～4.92），不動。 */
  --text-faint: #7e8ea5;

  /* ---- 品牌漸層（Logo 青藍紫） ---- */
  --brand-cyan: #00d4ff;
  --brand-blue: #20a0ff;
  --brand-violet: #6020d0;
  --brand-gradient: linear-gradient(135deg, var(--brand-cyan), var(--brand-blue), var(--brand-violet));
  --brand-gradient-soft: linear-gradient(135deg, rgba(0, 212, 255, 0.16), rgba(96, 32, 208, 0.16));
  --accent: #20a0ff;
  --accent-bg: rgba(32, 160, 255, 0.12);
  --glow: 0 0 24px rgba(0, 212, 255, 0.25);

  /* ---- 語意色：台股慣例紅漲綠跌 ---- */
  --up: #ff5d5d;
  --up-bg: rgba(255, 93, 93, 0.12);
  /* 熱度列高亮（2026-07-28 站長抓包「表格兩段顏色」）：與漲跌語意脫鉤的
     專屬底色——深色值＝原借用的 --up-bg 零變化；淺色改極淡暖褐，避免
     前五名變成大片粉紅與後段斷成兩截。 */
  --hot-row-bg: rgba(255, 93, 93, 0.12);
  --down: #2fbf71;
  --down-bg: rgba(47, 191, 113, 0.12);
  --flat: var(--text-muted);

  /* buy/watch/skip 語意徽章色（沿用漲=買進 紅系、觀察=琥珀、略過=中性） */
  --buy-fg: #ff5d5d;
  --buy-bg: rgba(255, 93, 93, 0.14);
  --watch-fg: #f5a623;
  --watch-bg: rgba(245, 166, 35, 0.14);
  --skip-fg: var(--text-muted);
  --skip-bg: rgba(143, 163, 200, 0.12);
  --warn-bg: rgba(245, 166, 35, 0.1);
  --warn-border: rgba(245, 166, 35, 0.35);
  --warn-fg: #f5a623;
  --danger: #ff5d5d;
  --danger-bg: rgba(255, 93, 93, 0.12);

  /* ---- AI 分數三階 ---- */
  --score-high: #2fe0a8;
  --score-mid: #f5a623;
  --score-low: var(--text-faint);

  /* ---- 尺寸 ---- */
  --radius: 14px;
  --radius-sm: 9px;
  --radius-lg: 20px;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.28);
  --shadow-pop: 0 20px 60px rgba(0, 0, 0, 0.5);
  --nav-bg: #0b0f1a;
  --nav-fg: #ffffff;
  --nav-sub: #8fa3c8;
  --bg: var(--bg-1);

  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* ---- 右下角浮鈕避讓 clearance（案⑥ 全域規則②，任務新增） ----
     任何貼右下角的固定/sticky 操作列（例如 .settings-actionbar 的儲存
     鈕）在右側留這麼多空間，避免被 .feedback-fab（right:20/bottom:20）
     疊住點不到——這是全域設計代幣，不是單頁 hack；日後新增任何貼右下角
     固定/sticky 操作列，一律加 `padding-right: var(--fab-clearance-right)`
     （或視覺上等效的右側留白）。手機斷點浮鈕縮到 44px、邊距也變窄，
     見下方 767px 媒體查詢覆寫。 */
  --fab-clearance-right: 76px; /* 48px 圓形浮鈕 + 20px 右邊距 + 8px 緩衝 */

  /* ==================================================================
     四主題制地基（2026-07-28 波次 0 新增）
     以下全部是「新增」代幣，值一律等於現行深色主題的實際生效值
     （孤兒代幣取其使用處 var() fallback、語意代幣取其使用處寫死色），
     所以預設（無 data-theme 或 data-theme="dark"）外觀零變化。
     後續波次才把各元件的寫死色換成這些代幣。
     ================================================================== */

  /* ---- (a) RGB 拆包：讓 rgba(var(--x-rgb), α) 的半透明色跟著主題走 ---- */
  --brand-cyan-rgb: 0, 212, 255;
  --brand-blue-rgb: 32, 160, 255;
  --brand-violet-rgb: 96, 32, 208;
  --up-rgb: 255, 93, 93;
  --down-rgb: 47, 191, 113;
  --watch-rgb: 245, 166, 35;
  --text-rgb: 232, 238, 251;
  --text-muted-rgb: 143, 163, 200;
  /* 深色底用「微白」提亮表面（rgba(255,255,255,.03~.06) 慣例）；
     淺色主題會翻成深色 tint（15,23,42）做「微深壓暗」。 */
  --surface-tint-rgb: 255, 255, 255;
  /* ---- 深底三分家（判準：這層底「上面放不放字」，不是「色值等不等」）----
     ① --scrim-rgb        純遮罩：蓋住整頁、上面不放字（字裝在 --card-bg 白卡裡）。
                          四主題一律暗色。
     ② --surface-scrim-rgb 半透明「表面」：tabs/footer/sticky 動作列…上面會放字，
                          且跟著頁面表面走。深色＝①同值，淺色必須翻白系。
     ③ --overlay-surface-rgb 深色浮層承字面：tooltip/氣泡/術語浮層…上面會放字，
                          但刻意四主題都維持暗底（浮在圖表之上要壓得住）。
                          它的字一律用 --on-overlay* 那組，不准用 --text*。
                          定義見下方 (h) 區塊。 */
  --scrim-rgb: 11, 15, 26;
  --surface-scrim-rgb: 11, 15, 26;
  --shadow-rgb: 0, 0, 0;     /* 陰影基色 */

  /* ---- (b) 孤兒代幣補齊：全站有 var(--x, fallback) 引用但從未定義，
     值＝使用處 fallback（grep 實查），定義後渲染結果與現在完全相同 ---- */
  --text-dim: #8b95a7;              /* etf.css:1230/1247/1273 fallback */
  --muted: #8b98a5;                 /* app.css:1725 / signals.css:89 fallback */
  --border-faint: var(--border);    /* news.css:621 等處 fallback 即 var(--border) */
  --text-2: var(--text);            /* admin.css:397/430/460 無 fallback，現行為繼承 var(--text) */
  --fg-muted: #8fa3c8;              /* funnel.css:752 / signals.css:330 fallback */
  --fg: #e6ebf2;                    /* etf.css:1251 fallback */
  --bg-alt: rgba(255, 255, 255, 0.04); /* kline_guide.css:71 fallback */
  --input-bg: var(--bg);            /* portfolio.css:515 fallback */
  --radius-md: 10px;                /* app.css:5937/6040 fallback（非色） */
  --w-nav-h: 62px;                  /* welcome.css:79 / welcome.js:189 fallback（非色） */

  /* ---- (c) 語意代幣：值＝現行使用處的寫死色，本波只定義不接線 ---- */
  --on-accent: #fff;                            /* 強調色上的文字 */
  --chart-grid: rgba(255, 255, 255, 0.08);      /* stock.js 圖表格線 */
  --chart-axis-text: #8fa3c8;                   /* 圖表軸標字 */
  /* ---- 主K線三條均線（2026-07-28 波次 3b 正名）----
     值一律以 stock.js drawCandles() 實際畫出來的線色為準。波次 0 建檔時
     ma5/ma20 兩顆對調（線色 MA5 是琥珀、MA20 是藍），ma60 也抄成了
     --tag-violet 的 #b39bff（真正線色是 #a060ff），本波一併校正；三顆
     在本波之前全站都還沒有使用處吃到錯值，故無外觀回歸。 */
  --chart-ma5: #e0a030;                         /* 琥珀 */
  --chart-ma20: #20a0ff;                        /* 藍 */
  --chart-ma60: #a060ff;                        /* 紫 */
  /* ---- 泛用資料線三色 ----
     非「均線」語意的折線/柱狀（股價線、累計買賣超、KD/RSI/MACD/乖離率、
     月營收＋YoY…）吃這組，不要借用 --chart-ma*：否則哪天主圖均線改色，
     會連坐一堆語意完全無關的圖。深色值＝改版前的寫死色，逐字相同。 */
  --chart-line-blue: #20a0ff;
  --chart-line-blue-rgb: 32, 160, 255;          /* 供 rgba() 半透明柱用 */
  --chart-line-amber: #e0a030;
  --chart-line-violet: #a060ff;
  /* 量能副圖的量均線 MA20：與主圖 MA60 同色但語意不同（一個是「量」的均線、
     一個是「價」的均線），獨立一顆，日後任一邊改色不會誤傷另一邊。 */
  --chart-vol-ma20: var(--chart-line-violet);
  /* 圖表刻度第二層級（X 軸日期/季度刻度，深色下比 --chart-axis-text 再淡
     一階）。淺色三主題受 9px 小字 4.5:1 對比下限所限，再淡就讀不到，
     故淺色版與該主題的 --chart-axis-text 同值（實測見交辦回報）。 */
  --chart-axis-faint: #5f7396;
  /* 雙軸圖左右軸刻度字：色隨各自的線色（大戶紅/散戶綠），深色下比
     --up/--down 再亮一階，免得 9px 小字糊在深底裡。 */
  --chart-axis-up: #ff8f8f;
  --chart-axis-down: #6fe0a0;
  /* K線標註「缺口」色帶：向上/向下兩色，只當半透明底用故只給 RGB。 */
  --chart-gap-up-rgb: 32, 160, 255;
  --chart-gap-down-rgb: 150, 90, 220;
  /* ⚠ --overlay / --overlay-strong 是「純遮罩」語意（scrim，上面不放字），
     所以三套淺色主題把它定成中灰半透明（α 0.62）。承字的浮層一律改用下方
     (h) 的 --overlay-surface，不要再接這兩顆——2026-08-01 tooltip 標籤被
     背景吃掉就是接錯這顆造成的。本波把僅有的三個承字使用處改掉後，
     這兩顆目前全站無使用處，保留作為日後純遮罩用。 */
  --overlay: rgba(11, 15, 26, 0.86);
  --overlay-strong: rgba(11, 15, 26, 0.95);
  --popover-bg: #131a2b;                        /* nav.js:1327 / points_banner.css:148 浮層底 */
  --grid-line: rgba(255, 255, 255, 0.06);       /* CSS 分隔格線（本波尚無使用處） */
  --tag-blue: #6fc2ff;                          /* app.css:5258 / news.css:937 */
  --tag-violet: #b39bff;
  --tag-slate: #a9bcdd;                         /* app.css:5260 / news.css:269 */
  --diag-a: #2ee6a8;                            /* stock.css:1043 支撐（K線標註） */
  --diag-b: #ff5ca8;                            /* stock.css:1049 壓力 */
  --light-red: #ff7a68;                         /* funnel.css:339 紅綠燈 */
  --light-amber: #f3ad4e;                       /* funnel.css:340 */
  --light-green: #4fd98b;                       /* funnel.css:341 */
  --brand-cyan-bright: #4ce0ff;                 /* nav.js:342 hover 亮青 */
  --promo: #c084fc;                             /* nav.js:346 促銷紫 */
  --color-scheme: dark;                         /* 原生控制項配色（見檔頭 color-scheme） */

  /* ---- (d) 裁字漸層（2026-07-28 波次 2 新增；深色值＝改版前寫死色，逐字相同）----
     background-clip:text 的標題漸層。深色是「亮字漸層」（白→淡青→淡紫），
     淺色主題必須翻成「深字漸層」（--text 起手，收在該主題的深色品牌色），
     否則淺底上的亮字漸層完全讀不到。使用處：welcome.css 的 .w-hero h1 與
     .w-stat-num；日後其他頁的裁字標題一律接這兩顆，不要再寫死。 */
  --gradient-hero: linear-gradient(96deg, #fff 12%, #baf0ff 60%, #d7c2ff 100%);
  --gradient-stat: linear-gradient(96deg, #fff, #baf0ff);

  /* ==================================================================
     (e) 波次 1.5 補齊代幣（2026-07-28）——深色值一律「逐字等於改版前的
     寫死色」，所以接線後預設外觀仍零變化；淺色三主題各給等效值。
     用途：回收波次 1 因「無對應代幣」而暫時豁免的寫死色。
     ================================================================== */

  /* 漏斗/流程階段的藍→紫漸進三階（settings-flow-stage-* 與 sv-funnel-stage-*
     共用；介於 --brand-blue 與 --brand-violet 之間，故獨立成三顆而非硬塞） */
  --funnel-ramp-1-rgb: 62, 122, 224;   /* env_guard 階段 */
  --funnel-ramp-2-rgb: 93, 90, 220;    /* industry 階段 */
  --funnel-ramp-3-rgb: 110, 70, 220;   /* candidate_limit 階段 */

  /* 回報狀態色票（.status-badge.status-*）：與漲跌語意無關的另一套 */
  --status-new: #6cc3ff;
  --status-progress: #ffcc66;
  --status-progress-rgb: 255, 179, 0;
  --status-resolved: #9dffcf;
  --status-resolved-rgb: 0, 200, 120;

  /* 連線狀態橫幅（.connstatus-banner[data-state]） */
  --conn-up: #9dffcf;
  --conn-up-rgb: 0, 200, 120;
  --conn-down: #ffb3b3;
  --conn-down-rgb: 255, 68, 68;

  /* 既有代幣的 RGB 拆包補齊（值＝各自代幣的 RGB，不是新顏色） */
  --score-high-rgb: 47, 224, 168;      /* = --score-high #2fe0a8 */
  --tag-violet-rgb: 179, 155, 255;     /* = --tag-violet #b39bff */
  --danger-rgb: 255, 93, 93;           /* = --danger #ff5d5d */
  --promo-rgb: 192, 132, 252;          /* = --promo #c084fc */

  /* 最強前景色：比 --text 再亮/再深一階的「強調字」。深色＝純白；淺色主題
     必須翻成近黑，否則 .tab-btn.active 這類白字在淺底上完全讀不到。 */
  --text-strong: #fff;

  /* nav 系：底漸層上停、下拉浮層底、品牌裁字標題漸層兩端 */
  --nav-bg-top: #0c1120;
  --nav-dropdown-bg: #101527;
  --brand-title-from: #fff;
  --brand-title-to: #cfeaff;
  /* ---- 品牌字標「AI」兩字專用色（站長 2026-08-22 12:09「我們的招牌」升級案）----
     三個設計變體各一組 token，切換只換 `.nav .title` 上的一顆 class
     （sv-brand-va / vb / vc，規則見 `.nav .title .sv-brand-ai` 一節）。
     gold＝A 香檳金漸層、aurora＝B 電光青藍漸層、solid＝C 雙色立體。
     edge 是立體硬邊（擠出面）、glow 是外圍柔光。
     深色 nav（#0b0f1a）上放亮，金與青都可以拉到最飽和。 */
  --sv-ai-gold-1: #fff3c9;
  --sv-ai-gold-2: #f5c95c;
  --sv-ai-gold-3: #c08a26;
  --sv-ai-gold-edge: rgba(46, 26, 0, 0.62);
  --sv-ai-gold-glow: rgba(245, 201, 92, 0.45);
  /* 跨棒共用（本檔尚無使用處，供其他波次接線） */
  --neutral-off-fg: #aab4c8;           /* 關閉/停用態文字 */
  --neutral-off-rgb: 91, 100, 120;
  --on-brand: #06222b;                 /* 品牌青底上的深字 */

  /* ==================================================================
     (f) 波次 2 棒A 補齊代幣（2026-07-28）——回收 stock.css/stock.html 因
     「無對應代幣」而暫時豁免的寫死色。深色值一律逐字等於改版前的寫死色，
     所以接線後深色外觀零變化；淺色三主題另給值。
     ⚠ 「實心底上的字」四顆（--on-diag-a/-b/--on-watch/--on-gap）在淺色主題
     不是一律給深字：淺色版 --diag-b(#c43c77)/--diag-gap(#2a72b8) 落在中亮度
     帶，純黑上限只有 4.26/4.20，深字數學上摸不到 4.5:1，故那兩顆淺色翻白字；
     --diag-a/--watch-fg 則是深字較優（純黑 4.84/5.13）。代幣語意是「這個底色
     該配的字色」，不是「一定要深色」。實測值見交辦回報。
     ================================================================== */
  --on-diag-a: #06231a;           /* 配 --diag-a 實心底（K線標註-支撐 chip） */
  --on-diag-b: #2b0716;           /* 配 --diag-b 實心底（壓力） */
  --on-watch: #2b1900;            /* 配 --watch-fg 實心底（事件） */
  --diag-gap: #2aa8ff;            /* K線標註-缺口層代表色（非 --brand-blue） */
  --on-gap: #04182b;              /* 配 --diag-gap 實心底 */
  /* 與既有 --on-brand(#06222b, survey 徽章用) 不同值，故另立一顆：
     這顆是品牌青「按鈕 hover 實心底」上的字（stock.css .report-preview-btn-primary）*/
  --on-brand-cyan: #001428;
  --on-brand-soft: #baf0ff;       /* 配 --brand-gradient-soft 半透明底的字 */
  --amber-alt-rgb: 224, 160, 48;  /* = --chart-ma5/--chart-line-amber 的 RGB，供半透明琥珀底用 */

  /* ==================================================================
     (g) 舉一反三修復 20260728——低對比前景／深底殘留全站掃描收斂。
     深色值一律逐字等於改版前的寫死色或原引用代幣的解析值，深色外觀
     零變化；淺色三主題在各自區塊另給深字版。
     ================================================================== */
  /* 文字專用強調色：原本全站 30+ 處拿 --accent/--brand-cyan 直接當小字
     用，淺色主題亮橘/亮青字對比 <3.5 全滅。拆出文字專用代幣後，
     --accent/--brand-cyan 保留給邊框、底線、icon 等非文字用途。
     深色值＝原代幣解析值（#20a0ff / #00d4ff），零變化。 */
  --accent-text: var(--accent);
  --brand-cyan-text: var(--brand-cyan);
  /* verify/forgot/reset 三頁「Signova AI」品牌標題字（原 inline #baf0ff） */
  --brand-logo-fg: #baf0ff;
  /* sticky 錨點 tab bar 承字底：原 anchor_tabs.css 借用 --scrim-rgb（純遮罩、
     上面不放字），淺色主題翻不過來變深底殘留；獨立成代幣後深色值＝原樣
     rgba(scrim, 0.7)，淺色改白系表面。 */
  --tabbar-bg: rgba(var(--scrim-rgb), 0.7);
  /* guide 小訣竅薄荷綠／使用時機琥珀（原 guide.css 寫死 #5eead4 / #ffb347） */
  --tips-teal: #5eead4;
  --tips-teal-rgb: 94, 234, 212;
  --usage-amber: #ffb347;
  --usage-amber-rgb: 255, 179, 71;
  /* AI 體檢鎖定徽章淡紫字（原 app.css .aireview-badge-locked #c9a0ff） */
  --aireview-locked-fg: #c9a0ff;
  /* ETF/產業資金流 情緒面分類徽章紫字（原 .perf-cat-sentiment #a67dff） */
  --perf-sentiment-fg: #a67dff;
  /* .sv-badge-violet 徽章底基色（原寫死 150,110,255） */
  --badge-violet-rgb: 150, 110, 255;
  /* handbook 頁尾「掃碼直達」字（原 inline #8fa3bd） */
  --hb-footer-fg: #8fa3bd;

  /* ==================================================================
     (h) 深色浮層承字面代幣族（2026-08-01 修復：站長回報「圖表 tooltip 的
     欄位標籤被背景吃掉」，三套淺色主題全滅，light-a 標籤僅 1.09:1）
     ------------------------------------------------------------------
     【為什麼要獨立一族】
     tooltip / 說明氣泡 / 術語浮層這類東西有個共同特徵：它「浮在圖表或
     內容之上」，所以底必須夠暗夠實才壓得住下面的線圖——四個主題都一樣。
     但它「上面會放字」，所以字**不能**用 --text / --text-muted 那組
     （那組在淺色主題會翻成深字，深底＋深字＝全滅）。
     原本的寫法是拿 --overlay-strong（純遮罩語意）當底、--text-muted 當字，
     兩顆的主題翻轉方向相反，淺色主題必炸。

     【使用契約】只要一個元素的底吃 --overlay-surface，它裡面所有文字就
     只能吃下面 --on-overlay* 這六顆，不准混用 --text / --text-muted /
     --up / --down / --watch-fg / --brand-cyan-text（那六顆是「頁面表面上
     的字」，會隨主題翻成深字）。反過來也成立。

     【為什麼前景只定義一次、不做主題覆寫】
     底四主題都是暗的，字自然也四主題共用一組亮色。單一定義＝日後任何人
     新增主題都不可能把它改壞。實測最差 4.95:1（light-b 的紅漲），全數
     通過 WCAG AA 正文 4.5:1；階序也保留：標籤比數值暗 2.19 倍。

     【新增浮層時】底接 --overlay-surface、邊框接 --overlay-surface-border、
     字接 --on-overlay*，四個主題各看一次才算完工。
     ================================================================== */
  /* 底色基色：色相跟著各主題的暖冷走（見三套淺色區塊的覆寫），但**明度
     一律維持暗色**——這是本族的硬約束，改值必須重算下面六顆的對比。 */
  --overlay-surface-rgb: 11, 15, 26;
  /* α 0.95 與原 --overlay-strong 深色值逐字相同 → 深色主題外觀零變化；
     0.95 也讓後方底色只剩 5% 影響力，浮在白卡或深卡上結果幾乎一致。 */
  --overlay-surface: rgba(var(--overlay-surface-rgb), 0.95);
  /* 邊框：原本接 --border-strong，淺色主題是米色實色，套在暗底浮層上會變
     成一圈搶眼亮框。改成固定的微白描邊，深色值＝原 --border-strong 同值。 */
  --overlay-surface-border: rgba(255, 255, 255, 0.14);
  /* ---- 浮層上的六顆前景（值＝深色主題原本的實際生效色，深色零變化）----
     對比（疊白卡最壞情況 / light-a｜light-b｜light-c）：              */
  --on-overlay: #e8eefb;        /* 數值、內文    13.08｜12.82｜13.12 */
  --on-overlay-muted: #8fa3c8;  /* 欄位標籤      5.97｜5.85｜5.99   */
  --on-overlay-up: #ff5d5d;     /* 紅漲數值      5.06｜4.95｜5.07   */
  --on-overlay-down: #2fbf71;   /* 綠跌數值      6.39｜6.26｜6.40   */
  --on-overlay-warn: #f5a623;   /* 琥珀提示/事件 7.51｜7.36｜7.53   */
  --on-overlay-link: #00d4ff;   /* 浮層內連結    8.60｜8.42｜8.62   */
}

/* ====================================================================
   淺色親和主題三選一（2026-07-28 波次 0 新增；色票正本＝
   docs/theme_preview_20260728.html 的甲/乙/丙三套變數）。
   只在 <html data-theme="light-a|light-b|light-c"> 時生效，
   不掛 data-theme（或掛 dark）一律走上面的藍黑經典主題。
   共同原則：紅漲綠跌不變、淺底加深版；霓虹光暈（--glow）大幅降低；
   --surface-tint-rgb 由「微白提亮」翻成「微深壓暗」。
   ==================================================================== */

/* ---- 甲・暖陽（米白 × 蜜橘）---- */
:root[data-theme="light-a"] {
  --bg-0: #f3ece0;
  --bg-1: #f8f4ec;
  --bg-2: #fcfaf4;
  --card-bg: #ffffff;
  --card-bg-hover: #fbf5ea;
  --border: #eadfce;
  --border-strong: #dccdb4;
  --border-faint: #f1e9dc;
  --text: #3b3630;
  /* 對比修復（SEO/AEO 修復波 2026-08-01）：原值 #7c7366 在本主題最暗的底
     （--bg-0 #f3ece0）上只有 3.97，未達正文 4.5:1；改 #726a5e 後為 4.54
     （bg-1 4.86／bg-2 5.11／card 5.33）。同色值的其餘去強調前景代幣
     （--text-dim／--muted／--fg-muted／--nav-sub／--chart-axis-text／
     --chart-axis-faint／--neutral-off-fg）一併同步——它們本來就是刻意設成
     同一個值的一組，只改其中兩顆會讓這組色票裂開。三主題同一手法。 */
  --text-muted: #726a5e;
  --text-faint: #6e6759; /* 舉一反三修復 20260728：faint 字疊 opacity 類全滅根治，bg1 上 4.4→5.1 */
  --text-dim: #726a5e;
  --muted: #726a5e;
  --fg: #3b3630;
  --fg-muted: #726a5e;
  --text-2: var(--text);
  --brand-cyan: #e1793a;
  --brand-blue: #b9622c;
  --brand-violet: #9a6e8a;
  --brand-cyan-bright: #c9662c;
  --brand-gradient: linear-gradient(135deg, var(--brand-cyan), var(--brand-blue), var(--brand-violet));
  --brand-gradient-soft: linear-gradient(135deg, rgba(225, 121, 58, 0.14), rgba(154, 110, 138, 0.12));
  --accent: #e1793a;
  --accent-bg: rgba(225, 121, 58, 0.12);
  --on-accent: #ffffff;
  --glow: 0 0 12px rgba(225, 121, 58, 0.18);
  --up: #c23c38; /* 舉一反三修復 20260728：紅 tint 徽章底 3.1→4.2、白底 5.25 */
  --up-bg: #fbe7e6;
  --hot-row-bg: rgba(225, 121, 58, 0.07);
  --down: #17814f; /* 舉一反三修復 20260728：白底 3.47→4.90、綠 tint 徽章 4.0+ */
  --down-bg: #e3f4eb;
  --flat: var(--text-muted);
  --buy-fg: #c23c38; /* 舉一反三修復 20260728：同 --up 紅字類一致收斂 */
  --buy-bg: rgba(214, 69, 65, 0.12);
  --watch-fg: #8f5a04; /* 舉一反三修復 20260728：amber tint 底 3.2→4.9 */
  --watch-bg: rgba(178, 110, 5, 0.14);
  --skip-fg: var(--text-muted);
  --skip-bg: rgba(138, 128, 113, 0.14);
  --warn-bg: rgba(178, 110, 5, 0.1);
  --warn-border: rgba(178, 110, 5, 0.32);
  --warn-fg: #8f5a04; /* 舉一反三修復 20260728 */
  --danger: #c23c38; /* 舉一反三修復 20260728 */
  --danger-bg: rgba(214, 69, 65, 0.1);
  --score-high: #1f8f63;
  --score-mid: #8f5a04; /* 舉一反三修復 20260728 */
  --score-low: var(--text-faint);
  --shadow-card: 0 1px 2px rgba(120, 96, 56, 0.06), 0 2px 10px rgba(120, 96, 56, 0.1);
  --shadow-pop: 0 18px 48px rgba(120, 96, 56, 0.2);
  --nav-bg: #ffffff;
  --nav-fg: #3b3630;
  --nav-sub: #726a5e;
  --bg: var(--bg-1);
  --bg-alt: rgba(15, 23, 42, 0.03);
  --input-bg: #ffffff;
  --brand-cyan-rgb: 225, 121, 58;
  --brand-blue-rgb: 185, 98, 44;
  --brand-violet-rgb: 154, 110, 138;
  --up-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --up */
  --down-rgb: 23, 129, 79; /* 舉一反三修復 20260728：跟隨 --down */
  --watch-rgb: 178, 110, 5;
  --text-rgb: 59, 54, 48;
  --text-muted-rgb: 138, 128, 113;
  --surface-tint-rgb: 15, 23, 42;
  --scrim-rgb: 30, 25, 20;
  --surface-scrim-rgb: 255, 255, 255;
  --shadow-rgb: 0, 0, 0;
  --chart-grid: rgba(15, 23, 42, 0.1);
  --chart-axis-text: #726a5e;
  /* 均線三色（波次 3b 正名）：琥珀/藍/紫的淺底加深版，順序對齊深色主題 */
  --chart-ma5: #c08019;
  --chart-ma20: #2a72b8;
  --chart-ma60: #7a5fb0;
  --chart-line-blue: #2a72b8;
  --chart-line-blue-rgb: 42, 114, 184;
  --chart-line-amber: #c08019;
  --chart-line-violet: #7a5fb0;
  --chart-axis-faint: #726a5e;
  --chart-axis-up: #b93a36;
  --chart-axis-down: #16794d;
  --chart-gap-up-rgb: 42, 114, 184;
  --chart-gap-down-rgb: 122, 95, 176;
  --overlay: rgba(30, 25, 20, 0.45);
  --overlay-strong: rgba(30, 25, 20, 0.62);
  /* 深色浮層承字面（見 :root 區塊 (h)）：只換色相跟上暖陽的暖調，明度
     必須維持暗色，否則 --on-overlay* 六顆亮字全部失效。 */
  --overlay-surface-rgb: 30, 25, 20;
  --popover-bg: #ffffff;
  --grid-line: rgba(15, 23, 42, 0.08);
  --tag-blue: #2a72b8;
  --tag-violet: #7a5fb0;
  --tag-slate: #5e6c86;
  --diag-a: #128a63;
  --diag-b: #c43c77;
  --light-red: #c8382e;
  --light-amber: #b26e05;
  --light-green: #1f8f63;
  --promo: #8b5fa8;
  /* 裁字漸層淺色版：深字漸層（--text 起手 → 品牌中間色 → 該主題最深的品牌
     色收尾），三套淺色主題共用同一組 var() 寫法、各自長出自己的顏色。 */
  --gradient-hero: linear-gradient(96deg, var(--text) 12%, var(--brand-violet) 60%, var(--brand-blue) 100%);
  --gradient-stat: linear-gradient(96deg, var(--text), var(--brand-blue));
  /* ---- 波次 1.5 補齊（甲・暖陽）：漸進三階取 --brand-blue → --brand-violet
     的 25%/55%/80% 內插，維持與深色版同樣的「越後段越紫」語意。 ---- */
  --funnel-ramp-1-rgb: 177, 101, 68;
  --funnel-ramp-2-rgb: 168, 105, 96;
  --funnel-ramp-3-rgb: 160, 108, 119;
  --status-new: #2563a0;
  --status-progress: #8b5604;
  --status-progress-rgb: 178, 110, 5;
  --status-resolved: #18704d;
  --status-resolved-rgb: 31, 157, 98;
  --conn-up: #18704d;
  --conn-up-rgb: 31, 157, 98;
  --conn-down: #ae3128;
  --conn-down-rgb: 200, 56, 46;
  --score-high-rgb: 31, 143, 99;
  --tag-violet-rgb: 122, 95, 176;
  --danger-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --danger */
  --promo-rgb: 139, 95, 168;
  --text-strong: #241f1a;
  --nav-bg-top: #ffffff;
  --nav-dropdown-bg: #ffffff;
  --brand-title-from: #3b3630;
  --brand-title-to: #b9622c;
  /* ---- 品牌字標「AI」兩字專用色（站長 2026-08-22 12:09「我們的招牌」升級案）----
     三個設計變體各一組 token，切換只換 `.nav .title` 上的一顆 class
     （sv-brand-va / vb / vc，規則見 `.nav .title .sv-brand-ai` 一節）。
     gold＝A 香檳金漸層、aurora＝B 電光青藍漸層、solid＝C 雙色立體。
     edge 是立體硬邊（擠出面）、glow 是外圍柔光。
     **淺底配深字**（站長 08-22 12:51 二次回饋：淺色三主題的 AI 被底色吃掉）。
     首版把三案的漸層當成「深色版壓一階」，在白 nav 上仍然是中明度色塊，
     和旁邊近黑的中文字比起來反而更弱。本版翻轉設計邏輯：淺底就走深色系，
     三案全部壓到 white 上 5.9:1 起跳（AA 正文門檻的 1.3 倍以上），
     靠「比中文字更深、更飽和、字級再大 1.42 倍」三件事一起跳出來。
     暖陽（橘系）底：A ＝ 深金→咖啡；B ＝ 深藍→靛紫；C ＝ 深湖藍正面＋焦橘擠出。 */
  --sv-ai-gold-1: #a86c0c;
  --sv-ai-gold-2: #7a4405;
  --sv-ai-gold-3: #4a2802;
  --sv-ai-gold-edge: rgba(36, 18, 1, 0.5);
  --sv-ai-gold-glow: rgba(74, 40, 2, 0.3);
  --neutral-off-fg: #726a5e;
  --neutral-off-rgb: 138, 128, 113;
  --on-brand: #2e1a0e;

  /* 波次 2 棒A（甲・暖陽）：壓力/缺口兩顆底色太暗改配白字，實測見回報 */
  --on-diag-a: #020a06;
  --on-diag-b: #ffffff;
  --on-watch: #180e00;
  --diag-gap: #2a72b8;
  --on-gap: #ffffff;
  --on-brand-cyan: #2a0f02;
  --on-brand-soft: #7a3a12;
  --amber-alt-rgb: 192, 128, 25;

  /* ---- 舉一反三修復 20260728（甲・暖陽）：低對比前景收斂 ---- */
  --accent-text: #a4490f;             /* 白底 5.93、accent 12% tint 底 5.26 */
  --brand-cyan-text: #a4490f;
  --brand-logo-fg: var(--on-brand-soft);   /* #7a3a12，bg1 上 7.84 */
  --tabbar-bg: rgba(var(--surface-scrim-rgb), 0.85); /* 白系表面，深底殘留根治 */
  --tips-teal: #1d7a66;               /* tips tint 底 5.03 */
  --usage-amber: #8f5a04;             /* usage tint 底 5.52 */
  --aireview-locked-fg: var(--tag-violet); /* #7a5fb0，violet 14% tint 底 4.36 */
  --perf-sentiment-fg: var(--tag-violet);  /* 16% tint 底 4.25 */
  --badge-violet-rgb: 122, 95, 176;   /* = --tag-violet-rgb，色相歸隊 */
  --hb-footer-fg: var(--text-faint);
  --color-scheme: light;
}

/* ---- 乙・青瓷（霧白 × 藍綠）---- */
:root[data-theme="light-b"] {
  --bg-0: #edf2f0;
  --bg-1: #f4f7f6;
  --bg-2: #f9fbfa;
  --card-bg: #ffffff;
  --card-bg-hover: #f2f8f5;
  --border: #dce6e1;
  --border-strong: #c6d6ce;
  --border-faint: #e8efec;
  --text: #2e3634;
  /* 對比修復 2026-08-01（同甲主題的理由）：#6b7872 在 --bg-0 #edf2f0 上
     4.07 未達標 → #64706b 為 4.56。同色值的其餘去強調前景代幣一併同步。 */
  --text-muted: #64706b;
  --text-faint: #626a66; /* 舉一反三修復 20260728：bg1 上 4.5→5.2 */
  --text-dim: #64706b;
  --muted: #64706b;
  --fg: #2e3634;
  --fg-muted: #64706b;
  --text-2: var(--text);
  --brand-cyan: #2e8c7f;
  --brand-blue: #24756a;
  --brand-violet: #6d7fa3;
  --brand-cyan-bright: #26766b;
  --brand-gradient: linear-gradient(135deg, var(--brand-cyan), var(--brand-blue), var(--brand-violet));
  --brand-gradient-soft: linear-gradient(135deg, rgba(46, 140, 127, 0.14), rgba(109, 127, 163, 0.12));
  --accent: #2e8c7f;
  --accent-bg: rgba(46, 140, 127, 0.12);
  --on-accent: #ffffff;
  --glow: 0 0 12px rgba(46, 140, 127, 0.18);
  --up: #c23c38; /* 舉一反三修復 20260728：紅 tint 徽章底 3.1→4.2、白底 5.25 */
  --up-bg: #fae8e7;
  --hot-row-bg: rgba(46, 140, 127, 0.07);
  --down: #17814f; /* 舉一反三修復 20260728：白底 3.47→4.90、綠 tint 徽章 4.0+ */
  --down-bg: #e2f2ea;
  --flat: var(--text-muted);
  --buy-fg: #c23c38; /* 舉一反三修復 20260728：同 --up 紅字類一致收斂 */
  --buy-bg: rgba(214, 69, 65, 0.12);
  --watch-fg: #8f5a04; /* 舉一反三修復 20260728：amber tint 底 3.2→4.9 */
  --watch-bg: rgba(178, 110, 5, 0.14);
  --skip-fg: var(--text-muted);
  --skip-bg: rgba(119, 133, 127, 0.14);
  --warn-bg: rgba(178, 110, 5, 0.1);
  --warn-border: rgba(178, 110, 5, 0.32);
  --warn-fg: #8f5a04; /* 舉一反三修復 20260728 */
  --danger: #c23c38; /* 舉一反三修復 20260728 */
  --danger-bg: rgba(214, 69, 65, 0.1);
  --score-high: #1f8f63;
  --score-mid: #8f5a04; /* 舉一反三修復 20260728 */
  --score-low: var(--text-faint);
  --shadow-card: 0 1px 2px rgba(46, 92, 82, 0.05), 0 2px 10px rgba(46, 92, 82, 0.09);
  --shadow-pop: 0 18px 48px rgba(46, 92, 82, 0.18);
  --nav-bg: #ffffff;
  --nav-fg: #2e3634;
  --nav-sub: #64706b;
  --bg: var(--bg-1);
  --bg-alt: rgba(15, 23, 42, 0.03);
  --input-bg: #ffffff;
  --brand-cyan-rgb: 46, 140, 127;
  --brand-blue-rgb: 36, 117, 106;
  --brand-violet-rgb: 109, 127, 163;
  --up-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --up */
  --down-rgb: 23, 129, 79; /* 舉一反三修復 20260728：跟隨 --down */
  --watch-rgb: 178, 110, 5;
  --text-rgb: 46, 54, 52;
  --text-muted-rgb: 119, 133, 127;
  --surface-tint-rgb: 15, 23, 42;
  --scrim-rgb: 20, 30, 28;
  --surface-scrim-rgb: 255, 255, 255;
  --shadow-rgb: 0, 0, 0;
  --chart-grid: rgba(15, 23, 42, 0.1);
  --chart-axis-text: #64706b;
  /* 均線三色（波次 3b 正名）：琥珀/藍/紫的淺底加深版，順序對齊深色主題 */
  --chart-ma5: #c08019;
  --chart-ma20: #2a72b8;
  --chart-ma60: #7a5fb0;
  --chart-line-blue: #2a72b8;
  --chart-line-blue-rgb: 42, 114, 184;
  --chart-line-amber: #c08019;
  --chart-line-violet: #7a5fb0;
  --chart-axis-faint: #64706b;
  --chart-axis-up: #b93a36;
  --chart-axis-down: #16794d;
  --chart-gap-up-rgb: 42, 114, 184;
  --chart-gap-down-rgb: 122, 95, 176;
  --overlay: rgba(20, 30, 28, 0.45);
  --overlay-strong: rgba(20, 30, 28, 0.62);
  /* 深色浮層承字面（見 :root 區塊 (h)）：色相跟上青瓷的冷調，明度維持暗色。 */
  --overlay-surface-rgb: 20, 30, 28;
  --popover-bg: #ffffff;
  --grid-line: rgba(15, 23, 42, 0.08);
  --tag-blue: #2a72b8;
  --tag-violet: #7a5fb0;
  --tag-slate: #5e6c86;
  --diag-a: #128a63;
  --diag-b: #c43c77;
  --light-red: #c8382e;
  --light-amber: #b26e05;
  --light-green: #1f8f63;
  --promo: #5f73a0;
  --gradient-hero: linear-gradient(96deg, var(--text) 12%, var(--brand-violet) 60%, var(--brand-blue) 100%);
  --gradient-stat: linear-gradient(96deg, var(--text), var(--brand-blue));
  /* ---- 波次 1.5 補齊（乙・青瓷）---- */
  --funnel-ramp-1-rgb: 54, 120, 120;
  --funnel-ramp-2-rgb: 76, 123, 137;
  --funnel-ramp-3-rgb: 94, 125, 152;
  --status-new: #2563a0;
  --status-progress: #8b5604;
  --status-progress-rgb: 178, 110, 5;
  --status-resolved: #18704d;
  --status-resolved-rgb: 31, 157, 98;
  --conn-up: #18704d;
  --conn-up-rgb: 31, 157, 98;
  --conn-down: #ae3128;
  --conn-down-rgb: 200, 56, 46;
  --score-high-rgb: 31, 143, 99;
  --tag-violet-rgb: 122, 95, 176;
  --danger-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --danger */
  --promo-rgb: 95, 115, 160;
  --text-strong: #1b211f;
  --nav-bg-top: #ffffff;
  --nav-dropdown-bg: #ffffff;
  --brand-title-from: #2e3634;
  --brand-title-to: #24756a;
  /* ---- 品牌字標「AI」兩字專用色（站長 2026-08-22 12:09「我們的招牌」升級案）----
     三個設計變體各一組 token，切換只換 `.nav .title` 上的一顆 class
     （sv-brand-va / vb / vc，規則見 `.nav .title .sv-brand-ai` 一節）。
     gold＝A 香檳金漸層、aurora＝B 電光青藍漸層、solid＝C 雙色立體。
     edge 是立體硬邊（擠出面）、glow 是外圍柔光。
     青瓷（冷綠）底，同上深色系原則：A 略帶橄欖的深金→咖啡；
     B 深藍→靛紫；C ＝ 深湖綠正面＋深琥珀擠出（冷暖對撞才看得出是兩色）。 */
  --sv-ai-gold-1: #97650c;
  --sv-ai-gold-2: #6d3f05;
  --sv-ai-gold-3: #422402;
  --sv-ai-gold-edge: rgba(32, 16, 1, 0.5);
  --sv-ai-gold-glow: rgba(66, 36, 2, 0.3);
  --neutral-off-fg: #64706b;
  --neutral-off-rgb: 119, 133, 127;
  --on-brand: #082421;

  /* 波次 2 棒A（乙・青瓷） */
  --on-diag-a: #020a06;
  --on-diag-b: #ffffff;
  --on-watch: #180e00;
  --diag-gap: #2a72b8;
  --on-gap: #ffffff;
  --on-brand-cyan: #02140f;
  --on-brand-soft: #1d5b52;
  --amber-alt-rgb: 192, 128, 25;

  /* ---- 舉一反三修復 20260728（乙・青瓷）：低對比前景收斂 ---- */
  --accent-text: #1f6e63;             /* 白底 6.05、accent 12% tint 底 5.25 */
  --brand-cyan-text: #1f6e63;
  --brand-logo-fg: var(--on-brand-soft);   /* #1d5b52，bg1 上 7.30 */
  --tabbar-bg: rgba(var(--surface-scrim-rgb), 0.85);
  --tips-teal: #1d7a66;
  --usage-amber: #8f5a04;
  --aireview-locked-fg: var(--tag-violet);
  --perf-sentiment-fg: var(--tag-violet);
  --badge-violet-rgb: 122, 95, 176;
  --hb-footer-fg: var(--text-faint);
  --color-scheme: light;
}

/* ---- 丙・珊瑚（奶茶 × 珊瑚橘）---- */
:root[data-theme="light-c"] {
  --bg-0: #f5ebe3;
  --bg-1: #faf3ee;
  --bg-2: #fcf7f2;
  --card-bg: #fffdfb;
  --card-bg-hover: #faf1e9;
  --border: #efdfd4;
  --border-strong: #e2ccbb;
  --border-faint: #f5e9e1;
  --text: #453e39;
  /* 對比修復 2026-08-01（同甲主題的理由）：#7e7269 在 --bg-0 #f5ebe3 上
     3.97 未達標 → #756961 為 4.53。同色值的其餘去強調前景代幣一併同步。 */
  --text-muted: #756961;
  --text-faint: #6f665d; /* 舉一反三修復 20260728：bg1 上 4.4→5.1 */
  --text-dim: #756961;
  --muted: #756961;
  --fg: #453e39;
  --fg-muted: #756961;
  --text-2: var(--text);
  --brand-cyan: #e26d5a;
  --brand-blue: #c05442;
  --brand-violet: #a0708f;
  --brand-cyan-bright: #c85b49;
  --brand-gradient: linear-gradient(135deg, var(--brand-cyan), var(--brand-blue), var(--brand-violet));
  --brand-gradient-soft: linear-gradient(135deg, rgba(226, 109, 90, 0.14), rgba(160, 112, 143, 0.12));
  --accent: #e26d5a;
  --accent-bg: rgba(226, 109, 90, 0.12);
  --on-accent: #ffffff;
  --glow: 0 0 12px rgba(226, 109, 90, 0.18);
  --up: #c23c38; /* 舉一反三修復 20260728：紅 tint 徽章底 3.1→4.2、白底 5.25 */
  --up-bg: #fae6e4;
  --hot-row-bg: rgba(226, 109, 90, 0.07);
  --down: #17814f; /* 舉一反三修復 20260728：白底 3.47→4.90、綠 tint 徽章 4.0+ */
  --down-bg: #e1f3ea;
  --flat: var(--text-muted);
  --buy-fg: #c23c38; /* 舉一反三修復 20260728：同 --up 紅字類一致收斂 */
  --buy-bg: rgba(214, 69, 65, 0.12);
  --watch-fg: #8f5a04; /* 舉一反三修復 20260728：amber tint 底 3.2→4.9 */
  --watch-bg: rgba(178, 110, 5, 0.14);
  --skip-fg: var(--text-muted);
  --skip-bg: rgba(148, 134, 124, 0.14);
  --warn-bg: rgba(178, 110, 5, 0.1);
  --warn-border: rgba(178, 110, 5, 0.32);
  --warn-fg: #8f5a04; /* 舉一反三修復 20260728 */
  --danger: #c23c38; /* 舉一反三修復 20260728 */
  --danger-bg: rgba(214, 69, 65, 0.1);
  --score-high: #1f8f63;
  --score-mid: #8f5a04; /* 舉一反三修復 20260728 */
  --score-low: var(--text-faint);
  --shadow-card: 0 1px 2px rgba(140, 92, 66, 0.06), 0 2px 10px rgba(140, 92, 66, 0.1);
  --shadow-pop: 0 18px 48px rgba(140, 92, 66, 0.2);
  --nav-bg: #fffdfb;
  --nav-fg: #453e39;
  --nav-sub: #756961;
  --bg: var(--bg-1);
  --bg-alt: rgba(15, 23, 42, 0.03);
  --input-bg: #fffdfb;
  --brand-cyan-rgb: 226, 109, 90;
  --brand-blue-rgb: 192, 84, 66;
  --brand-violet-rgb: 160, 112, 143;
  --up-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --up */
  --down-rgb: 23, 129, 79; /* 舉一反三修復 20260728：跟隨 --down */
  --watch-rgb: 178, 110, 5;
  --text-rgb: 69, 62, 57;
  --text-muted-rgb: 148, 134, 124;
  --surface-tint-rgb: 15, 23, 42;
  --scrim-rgb: 32, 24, 20;
  --surface-scrim-rgb: 255, 253, 251;
  --shadow-rgb: 0, 0, 0;
  --chart-grid: rgba(15, 23, 42, 0.1);
  --chart-axis-text: #756961;
  /* 均線三色（波次 3b 正名）：琥珀/藍/紫的淺底加深版，順序對齊深色主題 */
  --chart-ma5: #c08019;
  --chart-ma20: #2a72b8;
  --chart-ma60: #7a5fb0;
  --chart-line-blue: #2a72b8;
  --chart-line-blue-rgb: 42, 114, 184;
  --chart-line-amber: #c08019;
  --chart-line-violet: #7a5fb0;
  --chart-axis-faint: #756961;
  --chart-axis-up: #b93a36;
  --chart-axis-down: #16794d;
  --chart-gap-up-rgb: 42, 114, 184;
  --chart-gap-down-rgb: 122, 95, 176;
  --overlay: rgba(32, 24, 20, 0.45);
  --overlay-strong: rgba(32, 24, 20, 0.62);
  /* 深色浮層承字面（見 :root 區塊 (h)）：色相跟上珊瑚的暖調，明度維持暗色。 */
  --overlay-surface-rgb: 32, 24, 20;
  --popover-bg: #fffdfb;
  --grid-line: rgba(15, 23, 42, 0.08);
  --tag-blue: #2a72b8;
  --tag-violet: #7a5fb0;
  --tag-slate: #5e6c86;
  --diag-a: #128a63;
  --diag-b: #c43c77;
  --light-red: #c8382e;
  --light-amber: #b26e05;
  --light-green: #1f8f63;
  --promo: #96608a;
  --gradient-hero: linear-gradient(96deg, var(--text) 12%, var(--brand-violet) 60%, var(--brand-blue) 100%);
  --gradient-stat: linear-gradient(96deg, var(--text), var(--brand-blue));
  /* ---- 波次 1.5 補齊（丙・珊瑚）---- */
  --funnel-ramp-1-rgb: 184, 91, 85;
  --funnel-ramp-2-rgb: 174, 99, 108;
  --funnel-ramp-3-rgb: 166, 106, 128;
  --status-new: #2563a0;
  --status-progress: #8b5604;
  --status-progress-rgb: 178, 110, 5;
  --status-resolved: #18704d;
  --status-resolved-rgb: 31, 157, 98;
  --conn-up: #18704d;
  --conn-up-rgb: 31, 157, 98;
  --conn-down: #ae3128;
  --conn-down-rgb: 200, 56, 46;
  --score-high-rgb: 31, 143, 99;
  --tag-violet-rgb: 122, 95, 176;
  --danger-rgb: 194, 60, 56; /* 舉一反三修復 20260728：跟隨 --danger */
  --promo-rgb: 150, 96, 138;
  --text-strong: #2b2521;
  --nav-bg-top: #fffdfb;
  --nav-dropdown-bg: #fffdfb;
  --brand-title-from: #453e39;
  --brand-title-to: #c05442;
  /* ---- 品牌字標「AI」兩字專用色（站長 2026-08-22 12:09「我們的招牌」升級案）----
     三個設計變體各一組 token，切換只換 `.nav .title` 上的一顆 class
     （sv-brand-va / vb / vc，規則見 `.nav .title .sv-brand-ai` 一節）。
     gold＝A 香檳金漸層、aurora＝B 電光青藍漸層、solid＝C 雙色立體。
     edge 是立體硬邊（擠出面）、glow 是外圍柔光。
     珊瑚（暖紅）底，同上深色系原則：A 深金→咖啡；B 深藍→靛紫；
     C ＝ 深湖藍正面＋深珊瑚擠出（取本主題 --brand-title-to 的同族深色）。 */
  --sv-ai-gold-1: #a3660b;
  --sv-ai-gold-2: #754005;
  --sv-ai-gold-3: #462602;
  --sv-ai-gold-edge: rgba(34, 16, 1, 0.5);
  --sv-ai-gold-glow: rgba(70, 36, 2, 0.3);
  --neutral-off-fg: #756961;
  --neutral-off-rgb: 148, 134, 124;
  --on-brand: #331711;

  /* 波次 2 棒A（丙・珊瑚） */
  --on-diag-a: #020a06;
  --on-diag-b: #ffffff;
  --on-watch: #180e00;
  --diag-gap: #2a72b8;
  --on-gap: #ffffff;
  --on-brand-cyan: #2a0a05;
  --on-brand-soft: #8c3524;
  --amber-alt-rgb: 192, 128, 25;

  /* ---- 舉一反三修復 20260728（丙・珊瑚）：低對比前景收斂 ---- */
  --accent-text: #b04432;             /* 白底 5.65、accent 12% tint 底 4.91 */
  --brand-cyan-text: #b04432;
  --brand-logo-fg: var(--on-brand-soft);   /* #8c3524，bg1 上 7.22 */
  --tabbar-bg: rgba(var(--surface-scrim-rgb), 0.85);
  --tips-teal: #1d7a66;
  --usage-amber: #8f5a04;
  --aireview-locked-fg: var(--tag-violet);
  --perf-sentiment-fg: var(--tag-violet);
  --badge-violet-rgb: 122, 95, 176;
  --hb-footer-fg: var(--text-faint);
  --color-scheme: light;
}

/* ====================================================================
   丁・香檳金（金屬香檳 × 深金褐）—— 任務 #225，2026-08-18 新增
   --------------------------------------------------------------------
   【色票來源｜禁自創色】本主題所有金色一律取自品牌正本
   `social/tools/make_brand_cards.py:43-51`（C 版香檳金屬板，站長 2026-08-12
   定案，圖卡／影片／OG 卡共用同一組）：
     CARD #FFFDF4／CARD_D #F4E6C9／GOLD #C9A961／GOLD_LT #F2DFAC／
     GOLD_DK #7A5A1E／TXT #4A3618／MUTED_DK #6B5225，
   外加該檔 `.wm b` 的 #8A6218 與 `.chip` 的 #6B4A16。金屬板背景語彙
   （斜掃光＋角落打光＋明暗階）抄該檔 `_shell()` 的 background 寫法，
   見本檔下方「香檳金屬質感層」一節。

   【為什麼 id 不叫 light-d】站長交辦指定 `data-theme="champagne"`。代價是
   全站既有的 `[data-theme^="light-"]` 前綴選擇器（welcome.css 4 處、
   stock.css 1 處、privacy/disclaimer/free_disclosure 三支模板 inline 各
   1 處）抓不到它，本波已逐一補上 champagne 孿生選擇器。
   ⚠ 日後再新增非 `light-*` 命名的淺色主題，這 9 處必須一起補，否則會出現
   「只有那幾條規則沒跟上」的局部破相。

   【明度分工｜這是本主題的硬約束】
   代幣 --bg-*／--card-bg 一律是**素面淺色**（上面要放字，要顧對比）；
   金屬感一律由**另一層背景圖**（--champ-plate / --sv-card-sheen 等）疊上去，
   而且每一層的**最暗停**都實算過對比（見下方一節的實測數字）。
   絕不把金屬漸層寫進 --card-bg：全站有 20+ 處 `background-color: var(--card-bg)`
   與 color-mix(..., var(--card-bg))，那些語法只吃純色，塞漸層會整片失效。

   【對比實算（2026-08-18，WCAG 相對亮度公式）】五層底＝
   bg-0 #F4ECDB／bg-1 #FBF4E4／bg-2 #FDFAF0／card #FFFDF4／card-hover #FAF2DE
     --text        #4A3618   9.75｜10.46｜10.98｜11.25｜10.27  最差 9.75
     --text-muted  #6B5225   6.25｜ 6.70｜ 7.03｜ 7.21｜ 6.58  最差 6.25
     --text-faint  #6E5527   5.97｜ 6.41｜ 6.72｜ 6.89｜ 6.29  最差 5.97
     --text-strong #2E2109  13.36｜14.33｜15.03｜15.41｜14.07  最差 13.36
     --accent-text #7A5A1E   5.40｜ 5.79｜ 6.08｜ 6.23｜ 5.69  最差 5.40
   正文級全數 ≥4.5 通過 AA。--bg-0 刻意取 #F4ECDB 而非更暗的金屬階，就是為了
   讓語意色的最差對比**逐字打平 light-a 的既有基準**（up 4.47／down 4.17／
   tag-blue 4.26），新主題不比已上線的三套淺色差。
   ==================================================================== */
:root[data-theme="champagne"] {
  /* ---- 底色分層：素面淡香檳，金屬感另走背景圖層 ---- */
  --bg-0: #f4ecdb;
  --bg-1: #fbf4e4;
  --bg-2: #fdfaf0;
  --card-bg: #fffdf4;        /* ＝品牌正本 CARD */
  --card-bg-hover: #faf2de;
  --border: #e6d5ae;
  --border-strong: #c9a961;  /* ＝品牌正本 GOLD，金線 */
  --border-faint: #f3e9d2;
  --text: #4a3618;           /* ＝品牌正本 TXT */
  /* 次文字直接取品牌正本 MUTED_DK #6B5225：最暗底 bg-0 上 6.25，遠優於三套
     淺色主題的 4.53~4.56。同色值的其餘去強調前景代幣一併同步（與甲乙丙
     同一手法：這組本來就是刻意設成同值的一套，只改其中兩顆會讓色票裂開）。 */
  --text-muted: #6b5225;
  --text-faint: #6e5527;     /* bg-1 上 6.41 */
  --text-dim: #6b5225;
  --muted: #6b5225;
  --fg: #4a3618;
  --fg-muted: #6b5225;
  --text-2: var(--text);
  /* ---- 品牌漸層：三段金屬金（亮金 → 中金 → 深金），取代青藍紫 ---- */
  --brand-cyan: #c9a961;     /* GOLD，裝飾用亮端 */
  --brand-blue: #a8792b;     /* 中金 */
  --brand-violet: #7a5a1e;   /* GOLD_DK，深端 */
  --brand-cyan-bright: #b8912f;
  /* ⚠ --brand-gradient **刻意不由上面三顆 --brand-* 內插**（甲乙丙都是內插，
     本主題是唯一例外），因為金色同時要扮演兩個互斥的角色：
       ① 裝飾用亮金（金線、圖示、光暈）＝ --brand-cyan #C9A961，要亮才有金屬感；
       ② 實心填充面（.notice-banner／主按鈕／徽章，`color: var(--on-accent)` 白字）
          ＝ 必須夠深，白字才讀得到。
     實測白字對比：#C9A961 只有 2.25、#A8792B 3.86，兩顆都破 AA；所以填充面另
     走一條「中金 → 深金」的 ramp：#966C22 4.70／#8A6218 5.47／#6F5119 7.32，
     全程過 4.5。亮金留給線與框（那是裝飾，不承載文字）。
     改這一行前先確認：全站 18 處 `background: var(--brand-gradient)` 有 3 處
     明確配 `color: var(--on-accent)`（app.css:1686 .notice-banner／7317／7568）。 */
  --brand-gradient: linear-gradient(135deg, #966c22, #8a6218 45%, #6f5119);
  --brand-gradient-soft: linear-gradient(135deg, rgba(201, 169, 97, 0.22), rgba(122, 90, 30, 0.12));
  /* --accent 取品牌正本 .wm b 的 #8A6218：白字 5.47 過 AA（#A8792B 只有 3.86），
     當邊框／底線時對 bg-1 也有 4.99 的可見度，兩種用途都站得住。 */
  --accent: #8a6218;
  --accent-bg: rgba(138, 98, 24, 0.12);
  --on-accent: #ffffff;
  --glow: 0 0 12px rgba(201, 169, 97, 0.30);
  /* ---- 紅漲綠跌：逐字沿用三套淺色主題，台股慣例不動（紅線①）---- */
  --up: #c23c38;
  --up-bg: #fdf1ed;          /* 暖香檳版紅底：--up 上 4.75，優於 light-a 的 4.42 */
  --hot-row-bg: rgba(201, 169, 97, 0.12);
  --down: #17814f;
  --down-bg: #edf7f1;        /* --down 上 4.47，優於 light-a 的 4.29 */
  --flat: var(--text-muted);
  --buy-fg: #c23c38;
  --buy-bg: rgba(214, 69, 65, 0.12);
  --watch-fg: #8f5a04;
  --watch-bg: rgba(178, 110, 5, 0.14);
  --skip-fg: var(--text-muted);
  --skip-bg: rgba(122, 90, 30, 0.12);
  --warn-bg: rgba(178, 110, 5, 0.1);
  --warn-border: rgba(178, 110, 5, 0.32);
  --warn-fg: #8f5a04;
  --danger: #c23c38;
  --danger-bg: rgba(214, 69, 65, 0.1);
  --score-high: #1f8f63;
  --score-mid: #8f5a04;
  --score-low: var(--text-faint);
  /* 陰影染金褐（非中性灰），落在金屬板上才不會顯得髒 */
  --shadow-card: 0 1px 2px rgba(122, 90, 30, 0.10), 0 2px 10px rgba(122, 90, 30, 0.14);
  --shadow-pop: 0 18px 48px rgba(90, 58, 30, 0.26);
  --nav-bg: #fdf6e6;
  --nav-fg: #4a3618;
  --nav-sub: #6b5225;
  --bg: var(--bg-1);
  --bg-alt: rgba(122, 90, 30, 0.05);
  --input-bg: #fffdf4;
  --brand-cyan-rgb: 201, 169, 97;
  --brand-blue-rgb: 168, 121, 43;
  --brand-violet-rgb: 122, 90, 30;
  --up-rgb: 194, 60, 56;
  --down-rgb: 23, 129, 79;
  --watch-rgb: 178, 110, 5;
  --text-rgb: 74, 54, 24;
  --text-muted-rgb: 107, 82, 37;
  /* 淺色主題的「微深壓暗」tint 改用金褐而非藍灰（15,23,42），
     疊在金屬板上才是同一個色系的加深，不會出現冷灰髒斑。 */
  --surface-tint-rgb: 122, 90, 30;
  --scrim-rgb: 38, 28, 12;
  --surface-scrim-rgb: 255, 253, 244;
  --shadow-rgb: 90, 58, 30;
  --chart-grid: rgba(122, 90, 30, 0.14);
  --chart-axis-text: #6b5225;
  /* 均線三色：深金／藍／紫的香檳底加深版。MA5 走深金與主題同調，MA20/MA60
     維持藍紫——三條線必須互相可辨，全走金色會糊成一團。 */
  --chart-ma5: #a8792b;
  --chart-ma20: #2a72b8;
  --chart-ma60: #7a5fb0;
  --chart-line-blue: #2a72b8;
  --chart-line-blue-rgb: 42, 114, 184;
  --chart-line-amber: #a8792b;
  --chart-line-violet: #7a5fb0;
  --chart-axis-faint: #6b5225;
  --chart-axis-up: #b93a36;
  --chart-axis-down: #16794d;
  --chart-gap-up-rgb: 42, 114, 184;
  --chart-gap-down-rgb: 122, 95, 176;
  --overlay: rgba(38, 28, 12, 0.45);
  --overlay-strong: rgba(38, 28, 12, 0.62);
  /* 深色浮層承字面（見 :root 區塊 (h)）：色相跟上香檳的金褐調，明度維持暗色。
     實測 --on-overlay* 六顆疊白卡：13.94／6.36（標籤）／5.39（紅）／6.80（綠）／
     8.00（琥珀）／9.16（連結），全數過 AA 正文 4.5。 */
  --overlay-surface-rgb: 26, 20, 8;
  --popover-bg: #fffdf4;
  --grid-line: rgba(122, 90, 30, 0.10);
  /* ---- data-tone 四色制（紅線②）：amber／violet／blue／slate 四個色相各自
     獨立、無一為紅或綠，法遵不變。三顆冷色比甲乙丙**再加深一階**，因為本
     主題的卡面是暖白 #FFFDF4（不是純白），同樣的 14% tint 底會偏暖、對比略
     降；加深後實測 tint 底 violet 5.05／blue 5.01／slate 4.88／amber 4.66，
     四顆全數 ≥4.5，反而優於三套淺色主題的 4.15~4.34。 ---- */
  --tag-blue: #1f639f;
  --tag-violet: #6d51a2;
  --tag-slate: #56637c;
  --diag-a: #128a63;
  --diag-b: #c43c77;
  --light-red: #c8382e;
  --light-amber: #b26e05;
  --light-green: #1f8f63;
  --promo: #8b5fa8;
  --gradient-hero: linear-gradient(96deg, var(--text) 12%, var(--brand-blue) 60%, var(--brand-violet) 100%);
  --gradient-stat: linear-gradient(96deg, var(--text), var(--brand-violet));
  /* ---- 漏斗漸進三階：--brand-blue → --brand-violet 的 25%/55%/80% 內插 ---- */
  --funnel-ramp-1-rgb: 157, 113, 40;
  --funnel-ramp-2-rgb: 143, 104, 36;
  --funnel-ramp-3-rgb: 131, 96, 33;
  --status-new: #2563a0;
  --status-progress: #8b5604;
  --status-progress-rgb: 178, 110, 5;
  --status-resolved: #18704d;
  --status-resolved-rgb: 31, 157, 98;
  --conn-up: #18704d;
  --conn-up-rgb: 31, 157, 98;
  --conn-down: #ae3128;
  --conn-down-rgb: 200, 56, 46;
  --score-high-rgb: 31, 143, 99;
  --tag-violet-rgb: 109, 81, 162;
  --danger-rgb: 194, 60, 56;
  --promo-rgb: 139, 95, 168;
  --text-strong: #2e2109;
  --nav-bg-top: #fffaef;
  --nav-dropdown-bg: #fffdf4;
  --brand-title-from: #4a3618;
  --brand-title-to: #8a6218;
  /* ---- 品牌字標「AI」兩字專用色（站長 2026-08-22 12:09「我們的招牌」升級案）----
     三個設計變體各一組 token，切換只換 `.nav .title` 上的一顆 class
     （sv-brand-va / vb / vc，規則見 `.nav .title .sv-brand-ai` 一節）。
     gold＝A 香檳金漸層、aurora＝B 電光青藍漸層、solid＝C 雙色立體。
     edge 是立體硬邊（擠出面）、glow 是外圍柔光。
     香檳 nav（#fdf6e6）：A 案直接吃品牌正本的金屬金 ramp（亮金 #C9A961 對
     這個底只有 2.1，**刻意不當漸層起點**——起點改用中金 #B8912F 3.0，
     大字粗體剛好過 AA 的 3:1，往下 #8A6218 5.4 / #5E4413 8.4 越讀越穩）。
     C 案＝亮金正面 ＋ 深棕擠出，金屬壓凸字的經典組合。 */
  --sv-ai-gold-1: #b08627; /* 08-22 指揮官裁決：2.74→3.05 過 AA 大字線，肉眼無差 */
  --sv-ai-gold-2: #8a6218;
  --sv-ai-gold-3: #5e4413;
  --sv-ai-gold-edge: rgba(74, 54, 24, 0.34);
  --sv-ai-gold-glow: rgba(201, 169, 97, 0.55);
  --neutral-off-fg: #6b5225;
  --neutral-off-rgb: 122, 90, 30;
  --on-brand: #3a2a08;       /* 配 --brand-cyan #C9A961 實心底，6.16 */

  /* 實心底上的字：與甲乙丙同判準（哪一邊對比高就用哪一邊，不是一律深字） */
  --on-diag-a: #020a06;      /* 4.62 */
  --on-diag-b: #ffffff;      /* 4.93 */
  --on-watch: #ffffff;       /* 配 --watch-fg #8f5a04 實心底，5.78 */
  --diag-gap: #2a72b8;
  --on-gap: #ffffff;         /* 5.00 */
  --on-brand-cyan: #2e2109;  /* 6.98 */
  --on-brand-soft: #6b4a16;  /* ＝品牌正本 .chip 字色，配金色半透明底 */
  --amber-alt-rgb: 168, 121, 43;

  /* ---- 低對比前景收斂（同甲乙丙的處理）---- */
  --accent-text: #7a5a1e;             /* GOLD_DK，bg-0 上 5.40、accent 12% tint 底 5.45 */
  --brand-cyan-text: #7a5a1e;
  --brand-logo-fg: #6b4a16;
  --tabbar-bg: rgba(var(--surface-scrim-rgb), 0.85);
  --tips-teal: #186a58;               /* teal tint 底 5.16（light-a 為 4.30） */
  --usage-amber: #8f5a04;             /* amber tint 底 4.66；亦即 data-tone 的 amber */
  --aireview-locked-fg: var(--tag-violet);
  --perf-sentiment-fg: var(--tag-violet);
  --badge-violet-rgb: 109, 81, 162;   /* = --tag-violet-rgb，色相歸隊 */
  --hb-footer-fg: var(--text-faint);
  --color-scheme: light;
}

@media (max-width: 767px) {
  :root {
    --fab-clearance-right: 66px; /* 44px 圓形浮鈕 + 14px 右邊距 + 8px 緩衝 */
  }
}

* {
  box-sizing: border-box;
}

/* 只給輔助技術與爬蟲讀、視覺上完全不佔位（SEO/AEO 修復波 2026-08-01）。
   用途：市場脈動六頁（大盤／法人／期貨／產業／ETF／新聞）原本整頁最高階
   標題就是 h2，**一個 h1 都沒有**——搜尋引擎與 AI 抓取端因此讀不到「這頁
   是什麼」。這些頁面的視覺標題列是 nav 裡的 .logo-wrap .subtitle（設計已
   定案），硬把它升成 h1 會動到全站導覽版型；改成在 <main> 開頭補一個語意
   用 h1，視覺零變動。
   作法是無障礙圈的標準 clip 手法（不用 display:none／visibility:hidden
   ——那兩者會讓螢幕閱讀器也讀不到，等於白補）。 */
.sv-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

html {
  min-height: 100%;
  background: var(--bg-1);
  /* 手機字體膨脹關閉（2026-07-15 使用者回報「手機看新聞事件字體變大、
     大小不統一」根治）：iOS Safari / Android Chrome 的 font boosting 會
     「選擇性」放大它認為需要的長文字區塊（K線事件 tooltip 的 note、新聞
     說明等），短標籤不放大 → 同一畫面字體大小不一。全站設計已有完整的
     RWD 字級，不需要瀏覽器代客放大；設 100% 全域關閉（標準修法，桌面
     瀏覽器忽略此屬性、零影響）。 */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html, body {
  margin: 0;
  padding: 0;
  background-color: var(--bg-1);
  color: var(--text);
  font-family: 'Noto Sans TC', 'Segoe UI', 'Microsoft JhengHei', Arial, sans-serif;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

body {
  background:
    radial-gradient(circle at 12% -10%, rgba(var(--brand-violet-rgb), 0.16), transparent 45%),
    radial-gradient(circle at 88% 0%, rgba(var(--brand-cyan-rgb), 0.12), transparent 40%),
    var(--bg-1);
  /* 100vh 在瀏覽器縮放 / Windows 顯示比例下常有次像素捨入誤差，會在底部露出
     一條非主題色的縫隙；100dvh（動態視口高度）能跟著實際可視區域走，沒有
     dvh 支援的舊瀏覽器 fallback 回 100vh。min-height 疊加確保不管哪個生效
     都至少填滿一屏，不會比視口矮。 */
  min-height: 100vh;
  min-height: 100dvh;
}

#app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg-1);
}

a { color: var(--brand-blue); }

::selection {
  background: rgba(var(--brand-cyan-rgb), 0.28);
  color: var(--on-accent);
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(var(--text-muted-rgb), 0.25);
  border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(var(--text-muted-rgb), 0.4); }

/* ---------- 原生表單控制項全域深色化（2026-07-10 累犯根治：元件修復一律
   進全域層，不再逐頁補丁）----------
   `<select>` 展開後的選項清單（listbox）由 OS/瀏覽器另外繪製，不吃 select
   本身的深色背景／文字色——`:root` 的 color-scheme:dark（見檔頭）多數情況
   下已提示瀏覽器用深色配色渲染原生控制項，但仍有情境不生效（任務#66先在
   stock.css 對 .chip-select 補了 color-scheme + option 背景/文字色兩道
   保底才修好；教室頁 48 型態圖鑑的「方向」下拉沒套用該 class，白底淺字
   看不見的問題原樣重演）。這裡在全域層對「所有」select/option 補齊同一套
   保底，任何頁面現有或之後新增的原生 select 都自動繼承，不必逐頁補丁；
   各頁 CSS 對 select 閉合狀態外觀（padding/border/背景）的既有客製規則
   不受影響，只在 option 顏色與 color-scheme 這兩點統一收斂到這裡。 */
select {
  color-scheme: var(--color-scheme, dark);
}

select option {
  background: var(--card-bg);
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------- NAV ----------
   三分組 flex 佈局：品牌（brand）／中段連結（nav-links）／使用者區（nav-actions）。
   每組各自 flex-wrap，容器本身也 wrap；空間不足時中段連結整組換到第二行、
   靠左對齊，不會與品牌或使用者區交錯。所有項目一律 white-space:nowrap +
   彈性間距，不設固定寬，任何視口寬度都用同一套規則連續適應。 */

.nav {
  background: linear-gradient(180deg, var(--nav-bg-top) 0%, var(--nav-bg) 100%);
  color: var(--nav-fg);
  padding: 10px clamp(12px, 2vw, 20px);
  display: flex;
  align-items: center;
  gap: 8px 16px;
  flex-wrap: wrap;
  position: sticky;
  top: 0;
  z-index: 20;
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(10px);
}

/* 手機內距（原本寫在檔案最末段的 RESPONSIVE 區，2026-08-19 搬到這裡）。
   搬移理由是**來源順序**，不是排版潔癖：這條與下方 `@media (max-width:480px)`
   的 `.nav { padding-left/right: 10px }` 同為 (0,1,0) 特異度，媒體查詢不加
   權重——原本它排在 480 段之後（舊行號 6885），所以 480 段那條「窄幕騰挪
   空間」的內距收窄從寫下的第一天起就沒有生效過（實測 360px 量到的仍是
   14px）。搬到基底規則正下方後：481–767px 維持 14px（行為零變化），
   <=480px 才真的收到 10px。同型的來源順序失效在 `.tier-badge` 上也有一份，
   一併在該處修正。 */
@media (max-width: 767px) {
  .nav {
    padding: 10px 14px;
  }
}

.nav .logo-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 auto;
  min-width: 0;
  order: 1;
}

.nav svg {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  filter: drop-shadow(0 0 8px rgba(var(--brand-cyan-rgb), 0.35));
}

.nav .title {
  /* 2026-08-20 站長明令：App 名「台股AI解盤」升為 nav 主字且要顯眼——字級由
     clamp(14,~,16) 拉大約 1.5 倍；主字內容在各模板為「台股AI解盤」。 */
  font-size: clamp(20px, 1.2vw + 14px, 24px);
  font-weight: 800;
  /* 1.44（原 1.2，2026-08-22 品牌字標案）：行框要先容得下放大 1.42em 的
     「AI」（24px × 1.42 = 34.1px ≤ 24px × 1.44 = 34.6px），否則那兩個字會
     自己把行框撐開，nav 高度變成由字型度量決定、不由這裡決定。 */
  line-height: 1.44;
  white-space: nowrap;
  /* 裁切線放寬 8px（2026-08-22 品牌字標案）：`overflow: hidden` 的裁切線
     貼在 padding box 上，「AI」的柔光與立體硬邊會被裁成一個看得見的方框
     （首版實測上緣 -3.2px、下緣 -0.9px，深色主題肉眼可見一條矩形光暈邊）。
     `overflow: clip` ＋ `overflow-clip-margin` 是唯一「照裁但准出血 N px」
     的作法——不用加內距，所以 nav 一毫米都不會因為出血而長高。
     兩行並排是漸進增強：不支援 clip 的瀏覽器把第二行當無效宣告丟掉，
     退回既有的 hidden（＝改版前行為，只是光暈邊回來），版面不會壞。
     ellipsis 在 overflow:clip 下同樣生效（Chromium/WebKit 皆實作）。 */
  overflow: hidden;
  overflow: clip;
  overflow-clip-margin: 8px;
  text-overflow: ellipsis;
  letter-spacing: 0.02em;
  background: linear-gradient(90deg, var(--brand-title-from), var(--brand-title-to));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;

  /* 中文四字的取色幾何（站長 2026-08-22 12:51【bug】回饋的修法，見下方
     `.sv-brand-zh` 一節）。130.11px ＝ 改版前這條標題的**實測盒寬**，四個
     斷點（320/390/768/1280）量到的都是同一個數——因為那個寬度是由下面
     那行副標「Signova AI・台股智慧選股」撐出來的，與字級無關。
     3.09em ＝ 改版前「解」的左緣相對標題左緣的位移（實測 3.0898em，四個
     斷點完全一致，因為文字度量隨字級等比縮放）。 */
  --sv-brand-zh-ramp: 130.11px;
  --sv-brand-zh-offset: 3.09em;
}

/* ── 中文四字：取色與「AI」完全解耦（站長 2026-08-22 12:51【bug】）──────
   症狀：把「AI」放大之後，**「解盤」在多個主題跟著變色**（實測改版前後
   單通道最大偏移：light-a 解 +10 盤 +8、light-c 解 +9 盤 +8、light-b 解 +5、
   dark 解 +4）。

   根因不是 token 繼承、也不是基底色被改掉——`.nav .title` 的漸層一個字都
   沒動。是**幾何耦合**：那條 `linear-gradient(90deg, …)` 鋪在標題的**盒子**
   上，色標 0%→100% 對應盒子的左緣→右緣。放大「AI」做了兩件事：
     ① 主字實寬 123 → 138px，超過副標寬度，於是盒寬 130 → 138px，整條
        ramp 被拉長；
     ② 「解盤」被更寬的「AI」往右推了約 16px，取樣點整個往 ramp 後段移。
   兩者疊加，「解盤」就往 --brand-title-to 那一端偏——顏色確實變了，而且是
   數學上必然的：只要中文字的顏色由「它在盒子裡的 x 座標」決定，任何動到
   AI 寬度的改動都會連帶改到中文字。

   修法＝**把中文字的取色從盒子座標系搬到自己的固定座標系**。模板把中文
   拆成兩段 `.sv-brand-zh`，每段各自鋪同一條漸層，但：
     · `background-size` 鎖成 `--sv-brand-zh-ramp`（130.11px 絕對長度，
       ＝改版前的盒寬），ramp 長度不再跟著盒子跑；
     · 第二段（解盤）用 `background-position-x` 往左推 `--sv-brand-zh-offset`
       （3.09em ＝ 改版前「解」的位移），讓它取到 ramp 上原本那一段。
   於是「AI」怎麼放大、盒子怎麼變寬，中文字取到的都是改版前逐 px 相同的
   那一段漸層。實測結果：五主題 × 四斷點，中文四字 ΔmaxRGB 全部 = 0。

   `.nav .title` 自己的漸層宣告刻意保留不動：SW 是 cache-first，使用者手機
   上可能還釘著沒有 `.sv-brand-zh` 的舊 HTML，那份要能靠父層漸層照常顯示
   （＝改版前外觀），不能變成一片透明看不見。 */
.nav .title .sv-brand-zh {
  background-image: linear-gradient(90deg, var(--brand-title-from), var(--brand-title-to));
  background-repeat: no-repeat;
  background-size: var(--sv-brand-zh-ramp) 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.nav .title .sv-brand-zh-b {
  background-position-x: calc(-1 * var(--sv-brand-zh-offset));
}

/* ══ 品牌字標「AI」三變體（站長 2026-08-22 12:09 明令）══════════════════
   原話：「台股AI解盤」是我們的招牌，**AI 兩字**要換有質感的顏色、大一點、
   有立體漸層感。

   實作是 **CSS 字標、不是圖片**：模板把主字拆成
   `台股<span class="sv-brand-ai">AI</span>解盤`——文字性、可選取、可無限
   縮放、`textContent` 逐字不變，SEO 與螢幕閱讀器讀到的仍是「台股AI解盤」
   （所以 og:site_name／<title>／structured data 那一整套逐字釘死的守門
   測試一個都不受影響）。禁自繪圖形 logo，這裡只做文字樣式。

   三案同時進版，切換只換 `.nav .title` 上的一顆 class（模板預設掛 A）：
     .sv-brand-va  香檳金漸層   金→琥珀 ＋ 立體硬邊，呼應品牌香檳金
     （B 電光青藍 / C 雙色立體兩變體 08-22 站長比選後淘汰，規則與 token 已
     清除；模板固定掛 .sv-brand-va。歷史見 backups/app.css.backup.20260822_brandfinal）
   站長比選後留一案、其餘兩段連同 --sv-ai-* token 一起刪。

   ⚠ 為什麼 A/B 的立體層用 `filter: drop-shadow()` 而不是 `text-shadow`：
   text-shadow 畫在「元素背景層之上」，而 `background-clip: text` 的漸層
   本身就是背景層——用 text-shadow 會把漸層整片糊掉（這是這個組合最常見
   的踩雷）。drop-shadow 作用在元素**已繪製結果**的 alpha 上、畫在其下方，
   漸層完整保留，而且多個 drop-shadow 串接會層層疊加＝真正的擠出感。
   C 案沒有背景漸層，text-shadow 可以直接用，也才做得出多層硬邊。 */
.nav .title .sv-brand-ai {
  /* 1.42em ＝ 桌機 24 → 34px、手機 20 → 28.4px。站長對視覺改動的感知門檻
     高（血訓「視覺微調一次做到兩倍」），第一版就拉到規格上緣。 */
  font-size: 1.42em;
  font-weight: 900;
  /* line-height:0 而不是 1（實測修正）：中文字型的內容高度約 1.45em，行框
     高度是「各 inline box 的上緣／下緣相對基線取聯集」算出來的——line-height:1
     的 34px 字仍會把行框往上頂 5px（實測桌機標題列 28.80 → 39.55px，nav 整條
     高 10.75px）。歸 0 之後這顆 inline box 完全不參與行框計算，行框回到由
     .nav .title 的 line-height 單獨決定（24 × 1.44 ＝ 34.56px），而「AI」的
     大寫字高（≈0.72em × 34px ＝ 24.5px）本來就塞得進基線以上的 27.7px，
     一個像素都不會被裁；真有字型度量例外，上面的 overflow-clip-margin 8px
     還接得住。淨效果：桌機 nav 只長 5.8px、手機一毫米都不長。 */
  line-height: 0;
  letter-spacing: 0.01em;
  /* 拉丁字放大後會黏住前後的中文字，左右各補一點視覺間距（左邊「股」是
     方框字、右邊「解」左半開放，所以左補多一點）。 */
  margin: 0 0.07em 0 0.09em;
  font-style: normal;
  /* 大寫拉丁字放大後照基線對齊會顯得往上浮，壓 0.03em 把視覺重心壓回
     與前後中文字同一條線。 */
  position: relative;
  top: 0.03em;
}

/* ── A 香檳金漸層（預設）────────────────────────────────────────────── */
.nav .title.sv-brand-va .sv-brand-ai {
  background-image: linear-gradient(
    168deg,
    var(--sv-ai-gold-1) 0%,
    var(--sv-ai-gold-2) 46%,
    var(--sv-ai-gold-3) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  /* 父層 .nav .title 是 color:transparent，子層不覆寫就會連自己的漸層都
     裁不出來（color 會繼承）。 */
  color: transparent;
  filter:
    drop-shadow(0 1px 0 var(--sv-ai-gold-edge))
    drop-shadow(0 2px 0 var(--sv-ai-gold-edge))
    drop-shadow(0 0 7px var(--sv-ai-gold-glow));
}

/* ── B 電光青藍漸層 ────────────────────────────────────────────────── */


/* ── C 雙色立體（實心正面 ＋ 第二色擠出）──────────────────────────── */


.nav .subtitle {
  font-size: 11px;
  color: var(--nav-sub);
  line-height: 1.2;
  /* 站長 2026-08-18 08:50 手機截圖：副標（頁名）在窄幕折成兩行把 nav 撐高。
     副標是輔助資訊，折行不如截尾。 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 品牌文字欄的保底寬（站長 2026-08-18 08:50：「Signova AI」被截成
   「Signo…」）。84px ＝ 14px 字重 800 的「Signova AI」實寬（約 70px）留餘裕；
   空間不足時不再犧牲品牌字，改由 .nav 的 flex-wrap 讓右側元件掉到第二排
   （＝08-16 省空間改版前的既有降級路徑）。 */
.nav .logo-wrap > div {
  min-width: 118px; /* 2026-08-20 主字換「台股AI解盤」（5 字 20px+ 粗體）重算 */
}

/* 頁名與 logo 同行（任務#84，2026-07-10）：非首頁時 nav.js 把 .title 的
   父層（原本純堆疊 title/subtitle 的容器）升格成這個 flex row，把頁名
   從 logo 下方的小字副標搬到品牌名右側同一行、字級拉大更醒目；首頁不
   套用，`.subtitle` 留在原位顯示品牌副標「台股智慧選股」。 */
.nav-brand-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}

.nav-page-sep {
  color: var(--nav-sub);
  font-size: 14px;
  opacity: 0.5;
  flex-shrink: 0;
}

.nav-page-name {
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  line-height: 1.3;
  /* 主要資訊不截斷（2026-07-10 全站設計原則）：完整顯示、允許換行，不
     用 text-overflow:ellipsis。 */
  white-space: normal;
}

@media (max-width: 640px) {
  .nav-page-sep {
    display: none; /* 頁名折到第二行時分隔號沒有意義，隱藏 */
  }
  .nav-page-name {
    font-size: 13px;
    flex-basis: 100%; /* 折到第二行、置左，不擠壓右側漢堡/使用者選單 */
  }
}

/* 中段導覽連結群組：品牌與使用者區之間，空間不足時整組換行、靠左收齊。
   語意分組下拉（2026-07 重構）：選股台為單一連結，市場／研究／我的
   為 .nav-group，內含 .nav-group-label（觸發字＋▾）與 .nav-dropdown
   （hover / focus-within 展開的選單）。 */
.nav-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 6px;
  order: 2;
  flex: 0 1 auto;
}

.nav-group {
  position: relative;
}

.nav-group-label {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--nav-sub);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  padding: 6px 12px;
  border-radius: 8px;
  cursor: default;
  transition: color 150ms var(--ease), background 150ms var(--ease);
  user-select: none;
}

.nav-group-caret {
  font-size: 9px;
  opacity: 0.7;
  transition: transform 150ms var(--ease);
}

.nav-group .nav-group-label:focus-visible,
.nav-group.nav-group-active .nav-group-label,
.nav-group.open .nav-group-label {
  color: var(--nav-fg);
  background: rgba(var(--surface-tint-rgb), 0.06);
}

.nav-group.nav-group-active .nav-group-label {
  background: rgba(var(--brand-cyan-rgb), 0.12);
}

.nav-group.open .nav-group-caret {
  transform: rotate(180deg);
}

/* #173（2026-08-16）：所有 :hover 觸發的展開/高亮一律關進 @media (hover: hover)。
   iOS Safari 對「沒有真 hover 的觸控裝置」會模擬黏著式 hover——第一次點擊
   套上 :hover 並保留到點別處為止。右上使用者選單（.nav-user-menu 在
   .nav-actions，手機版仍是絕對定位下拉，不吃 .nav-links 的常駐展開規則）
   因此可能在手機上被 hover 卡在展開態、蓋住底下的東西。展開邏輯本來就由
   nav.js 的 click 主導（見該檔開頭設計說明），:hover 只是滑鼠輔助，收進
   hover-capable 裝置零功能損失。 */
@media (hover: hover) {
  .nav-group:hover .nav-group-label {
    color: var(--nav-fg);
    background: rgba(var(--surface-tint-rgb), 0.06);
  }

  .nav-group.nav-group-active:hover .nav-group-label {
    background: rgba(var(--brand-cyan-rgb), 0.12);
  }

  .nav-group:hover .nav-group-caret {
    transform: rotate(180deg);
  }
}

/* 死區修正（使用者回報「很難控制」的根因）：.nav-dropdown 過去用
   margin-top:4px 留出視覺間距，但那 4px 是一段沒有任何元素接住游標的
   死區，滑鼠稍微斜移就會被判定「滑出群組」而收合。現在改成 top:100%
   緊貼（無 gap），視覺間距改由下方 .nav-dropdown::before 這個透明橋接
   偽元素撐出來——它的高度等同原本的間距，涵蓋在 .nav-group 的 hover
   hit-box 內，滑鼠路徑上全程都有元素接住，不會再有「掉進死區」的問題。
   互動邏輯改由 nav.js 主導（click 展開為主、.open class 控制），此處
   :hover 保留作為滑鼠輔助展開 fallback。
   2026-07-13 使用者回報「舊的下拉不消失、越開越多」根治：下拉顯示條件
   移除 :focus-within——nav.js 給 label 設了 tabindex，點擊後焦點永遠留
   在 label 上，:focus-within 讓該組下拉無視 .open 被移除仍持續顯示，
   再 hover 其他組就多開疊加。鍵盤展開已由 nav.js 的 Enter/Space 切換
   .open 涵蓋，:focus-within 不需要；label 的鍵盤焦點視覺改用
   :focus-visible。 */
.nav-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0;
  min-width: 168px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--nav-dropdown-bg);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  box-shadow: 0 12px 28px rgba(var(--shadow-rgb), 0.45);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 150ms var(--ease), transform 150ms var(--ease), visibility 150ms;
  z-index: 25;
  /* 2026-07-15 使用者回報「滑到某位置選單一直跳」根治（自激振盪五條件之
     一刀）：隱藏/淡出中的下拉不得攔截滑鼠——否則相鄰組（「我的」168px
     下拉罩住「幫助」label）淡出過場的 hit-box 位移會與 mouseenter 互搶
     hover，兩組互相 closeAllExcept 形成無限循環。展開態於下方規則恢復
     pointer-events。 */
  pointer-events: none;
}

/* .nav-dropdown::before 橋接熱區已移除（2026-07-15 同一根治）：下拉
   top:100% 與 label 緊貼本就無縫可橋，這個 4px 全寬熱區唯一實際作用是
   把開啟中下拉的 hit-box 常駐延伸到「鄰組 label」底部，製造 hover 搶奪。 */

.nav-group.open .nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
}

/* #173：hover 展開同上收進 hover-capable 裝置（見上方 @media (hover: hover) 註解）。 */
@media (hover: hover) {
  .nav-group:hover .nav-dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
  }
}

.nav-dropdown .nav-link {
  display: block;
}

.nav-dropdown .nav-link-btn {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
}

/* 使用者選單（規格①）：與市場／研究／我的同構的 .nav-group，靠最右對齊，
   下拉選單改成靠右展開（避免超出視口右側）。標籤內含 email + tier 徽章。 */
.nav-user-menu {
  margin-left: 4px;
}

.nav-user-label {
  gap: 8px;
}

.nav-user-menu .nav-group-label {
  cursor: pointer;
}

.nav-dropdown-right {
  left: auto;
  right: 0;
}

/* 使用者資訊 + 操作按鈕群組：永遠靠最右，空間不足時整組換到第二行靠右。
   .nav-user 與 .btn-run 各自視為一個不可再拆的區塊（flex-shrink:0 加
   min-width:0 的組合避免其中一個先被擠爆行寬只剩它自己流出）；當兩塊
   合計仍放不下同一行時，靠 flex-wrap 讓 .btn-run 整塊換到下一行，
   而不是被拆散成三行。 */
.nav-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  order: 3;
  margin-left: auto;
  justify-content: flex-end;
  max-width: 100%;
}

.nav-actions > .nav-user-menu,
.nav-actions > .btn-run {
  flex-shrink: 0;
}

.back-link {
  color: var(--nav-sub);
  font-size: 12px;
  text-decoration: none;
  white-space: nowrap;
  padding: 6px 10px;
  border-radius: 8px;
  transition: color 150ms var(--ease), background 150ms var(--ease);
}

.back-link:hover {
  color: var(--nav-fg);
  background: rgba(var(--surface-tint-rgb), 0.06);
}

.nav-link {
  color: var(--nav-sub);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  padding: 6px 12px;
  border-radius: 8px;
  transition: color 150ms var(--ease), background 150ms var(--ease);
}

.nav-link:hover {
  color: var(--nav-fg);
  background: rgba(var(--surface-tint-rgb), 0.06);
}

.nav-link.active {
  color: var(--nav-fg);
  background: rgba(var(--brand-cyan-rgb), 0.12);
}

/* ---------- NAV 漢堡選單（手機收納，<900px） ----------
   CSS checkbox hack：nav-toggle-checkbox 控制 nav-links 的展開/收合，
   完全不需要 JS。桌面（>=900px）checkbox/label/overlay 一律隱藏，
   nav-links 維持原本水平排列。 */
.nav-toggle-checkbox {
  display: none;
}

.nav-toggle-label {
  display: none;
  order: 2;
  margin-left: auto;
  width: 38px;
  height: 34px;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  cursor: pointer;
  font-size: 20px;
  color: var(--text);
  background: rgba(var(--surface-tint-rgb), 0.04);
  border: 1px solid var(--border);
  transition: background 150ms var(--ease);
}

.nav-toggle-label:hover {
  background: rgba(var(--surface-tint-rgb), 0.08);
}

.nav-toggle-overlay {
  display: none;
}

@media (max-width: 899px) {
  /* #184：iOS 對「sticky 容器＋backdrop-filter＋內部捲動面板」組合的 click
     命中測試有缺陷（點選單連結有反白卻不導航，詳 nav.js #184 段）。手機版
     直接拿掉模糊——nav 底色本就近乎不透明的漸層，視覺差異微乎其微，換來
     繞開整條最容易出 bug 的合成路徑。桌面（>=900px）維持原樣。 */
  .nav {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .nav-toggle-label {
    display: flex;
  }

  /* 站長 2026-08-16 17:39（管理後台截圖圈註「往上移省空間」）：調色盤＋tier
     徽章＋使用者選單原本 order:3 排在漢堡之後——nav 是 wrap 容器、首排被
     品牌與漢堡（margin-left:auto）佔滿，這組永遠掉到第二排，整排高度只為
     兩顆小元件。改排品牌與漢堡之間（order:2）：.logo-wrap 本來就
     flex:1 1 auto + min-width:0、.title 有 ellipsis，擠不下時縮品牌字不換行。
     訪客的登入/註冊鈕若真塞不下仍允許 wrap 掉到次排（.nav-actions 未鎖
     nowrap）——最壞回到改動前的兩排現狀，不會橫向溢出。目錄吸頂位置由
     --sv-nav-h 即時跟隨（#177），nav 變矮頁籤自動貼上來。 */
  .nav-actions {
    order: 2;
    margin-left: auto;
  }

  .nav-toggle-label {
    order: 3;
    margin-left: 0;
  }

  /* wrap 容器的換行是用各項「自然寬」算的（先斷行才收縮）：品牌區
     flex:1 1 auto 的自然寬會把整排佔滿，漢堡照樣被擠到第二排。basis 歸零
     讓斷行計算時品牌不佔位（actions＋漢堡先上第一排），行內剩餘空間再由
     grow 分回品牌。（2026-08-18 修訂：原設計讓 .title 的 ellipsis 承接
     極端窄機截斷，站長不接受品牌字被截——改由 .logo-wrap > div 的
     min-width:84px 保底，擠不下時右側元件換行。）

     2026-08-19 根因修正（站長 09:38 手機截圖：品牌字／鈴鐺／調色盤／PRO
     徽章四者互相重疊）：上一段那個「擠不下時右側元件換行」的降級路徑
     **從來沒有發生過**，因為 min-width:84px 掛在 .logo-wrap 的**子層 div**
     上，不是掛在 flex item 自己身上。flex 演算法看的是 flex item 的最小
     尺寸，而基底 `.nav .logo-wrap` 帶 min-width:0 ＋ 這裡 flex-basis:0%，
     於是這一項被允許壓到遠小於內容寬：360px 實測 .logo-wrap 只拿到 17.6px，
     內容（svg 34 ＋ gap 8 ＋ 品牌欄 84 ＝ 126px）整片溢出自己的框往右流，
     直接壓在 .nav-actions 的調色盤與鈴鐺上（實測交集面積 571px²）。
     容器既然「沒有變寬」就永遠不會觸發 flex-wrap，換行降級因此死掉。

     修法＝把保底寬還給 flex item 本人：min-width:min-content 讓這一項不可
     能被壓到小於 svg＋間距＋品牌欄保底（仍由子層 min-width:84px 定義 84 這
     個數，兩者是同一個意圖的正確接線位置）。這樣一來擠不下時真的會換行，
     **重疊在幾何上不再可能發生**——換行只是變高，不會蓋字。實際上三個目標
     窄寬（360/390/412）都還是一排：右側同步做了徽章分階降級與間距收斂，
     算式見下方 max-width:480px／374px 兩段。 */
  /* 2026-08-21 18:11 站長手機截圖（開持股快捷後三槓被擠到第二排、header 高度
     翻倍 134px）：min-width:min-content 是那一版（08-19）為了「擠不下時觸發
     flex-wrap 換行」而設的——換行本身就是現在的病徵。右簇多一顆 💼 之後
     360–390px 一定擠不下（實測 390px：品牌 179 ＋ 右簇 172 ＋ 漢堡 44 ＋ 間距
     20 ＝ 415 > 可用 370），於是每次都換行。

     改法＝**不再靠換行降級，改靠品牌欄截斷**（站長 18:11 明令「標題/副標區
     min-width:0 允許截斷」）：min-width:0 讓這一項可以壓到內容寬以下，
     flex-basis:0% 使斷行計算時它不佔位——右簇與漢堡因此永遠同排，漢堡固定最右
     不落行。08-19 那個「內容溢出自己的框、壓在右側元件上」的重疊事故**不會**
     重演，因為那次的成因是子層 min-width:118px 讓內容硬是比框寬；這次連同子層
     一起放行（見下一條），內容真的會縮，靠 .title/.subtitle 既有的 ellipsis 收尾。
     overflow:hidden 是保險絲：萬一未來又有人給子層加回保底寬，溢出會被裁掉而
     不是壓到隔壁。

     實測（/market＋ADMIN 膠囊＋💼 快捷）：390/375/360 三寬 header 都是 82px
     單列、零橫向溢出。 */
  .nav .logo-wrap {
    flex: 1 1 0%;
    min-width: 0;
    overflow: hidden;
    gap: 8px;
  }

  /* 品牌文字欄跟著放行：基底的 min-width:118px 是「品牌字不許被截」的保底，
     與上面那條的新策略直接衝突——留著它，內容就仍然比框寬，等於把 08-19 的
     重疊事故原封不動搬回來。 */
  .nav .logo-wrap > div {
    min-width: 0;
  }

  /* 右簇（調色盤／💼／鈴鐺／使用者膠囊）視為一個不可拆的整體：內部不換行、
     整體不被壓縮。少了 nowrap，四顆小元件會在窄幕自己疊成兩排，nav 照樣變高
     ——那是同一個病的另一種長法。 */
  .nav-actions {
    flex-wrap: nowrap;
    flex-shrink: 0;
  }

  /* 漢堡固定最右、永不落行（order:3 已在下方設定）。 */
  .nav-toggle-label {
    flex-shrink: 0;
  }

  .nav-links {
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    /* #173 根因（2026-08-16 站長回報「手機漢堡選單頁面連結偶發按了沒反應」）：
       基底 .nav-links 帶 flex-wrap:wrap，本段只改了 flex-direction 沒改 wrap。
       column 方向的 flex 容器一旦主軸（＝高度）有定值上限（展開態的
       max-height:640px 就是），放不下的項目不是被裁掉，而是**換到第二欄**。
       nav 內容成長到 21 連結＋4 組名（約 807px）之後就跨過門檻，實測
       elementFromPoint：面板右半邊整片是第二欄（我的投資／幫助兩組），而
       第二欄有幾列對到的是**不可點的灰色組名 <span>**——使用者看到的是一
       塊整面板寬的選單，按靠右半邊就落在 span 上，「按了沒反應」；第一欄被
       擠到最後的「法說會」則落到視口外（.nav 是 sticky top:0，元素高過視口
       就永遠捲不到底）＝完全點不到。
       修法兩件缺一不可：①禁止換欄 ②面板自己可捲（見下方 :checked 段）。 */
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 2px;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(-6px);
    transition: max-height 200ms var(--ease), opacity 150ms var(--ease), transform 150ms var(--ease);
    background: rgba(var(--surface-scrim-rgb), 0.98);
    border-radius: 10px;
    margin-top: 4px;
  }

  .nav-link {
    padding: 10px 12px;
    border-radius: 8px;
  }

  /* 手機漢堡內：分組不再用 hover 下拉，改攤平常駐顯示——組名當
     小標題（不可點擊，純 label），組內項目縮排列出。
     限定在 .nav-links 內的分組（市場／研究／我的）——使用者選單
     （.nav-user-menu）位在 .nav-actions，不受漢堡選單開合控制，若套用
     同一套「常駐展開」樣式，登出等選項會永遠攤開顯示在畫面上，因此
     使用者選單在手機版要維持原本的點擊展開/收合下拉行為，這裡刻意排除。 */
  .nav-links .nav-group {
    display: flex;
    flex-direction: column;
  }

  /* #173 UX（站長 2026-08-16 同意方向）：手機選單的組名從「純裝飾灰字」升格
     成 accordion 開關——點一下收合整組、再點展開，預設全展開（＝與改動前
     同樣的視覺內容，只是多了一個可按的箭頭）。收合狀態由 nav.js 掛
     .nav-collapsed（只在 <900px 生效，桌機下拉行為零改動）。
     組名同時是開關就必須看得出「這可以按」：字級 11→12.5px、透明度
     0.75→0.92、箭頭從 display:none 恢復顯示並放大到 11px，下緣 padding 從
     2px 拉到 6px 讓手指有得按（原本 28px 高的觸控目標低於 44px 建議值）。 */
  .nav-links .nav-group-label {
    cursor: pointer;
    padding: 10px 12px 6px;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: 0.3px;
    color: var(--nav-sub);
    opacity: 0.92;
    justify-content: flex-start;
    gap: 6px;
  }

  .nav-links .nav-group .nav-group-caret {
    display: inline-block;
    /* 靠最右＝標準 accordion 標頭的樣子，一眼看得出整列可按（原本 9px 的
       灰箭頭貼在字尾，實測截圖幾乎看不見）。 */
    margin-left: auto;
    padding-right: 2px;
    font-size: 13px;
    opacity: 0.9;
    /* transform 明寫 none：桌機段的 .nav-group.open .nav-group-caret（同為
       三個 class 的權重）若因視窗縮放留下殘餘 .open，箭頭會卡在 180 度。
       本段在來源順序上較後，同權重下勝出。 */
    transform: none;
    transition: transform 180ms var(--ease);
  }

  .nav-links .nav-group.nav-collapsed .nav-group-caret {
    transform: rotate(-90deg);
  }

  /* 權重 0,4,0：高於桌機段任何一條下拉顯示規則，收合狀態不會被蓋回去。 */
  .nav-links .nav-group.nav-collapsed .nav-dropdown {
    display: none;
  }

  .nav-links .nav-dropdown {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0 0 0 10px;
    margin-top: 0;
    min-width: 0;
    /* 2026-07-18 使用者回報「手機版面要確認優化」掃描抓到：桌機 hover
       振盪修復（2026-07-15）給 .nav-dropdown 基底加了 pointer-events:none
       （只在 :hover/.open 恢復），手機常駐展開段沒覆蓋這屬性——手機選單
       所有群組子項（選股漏斗/我的持股/我的股利/自選股…）視覺正常但點擊
       全數穿透到底下，完全點不到（elementFromPoint 實測穿到 nav-group）。
       當時只驗了頂層連結沒驗群組子項＝漏網。常駐展開必須恢復可點。 */
    pointer-events: auto;
  }

  .nav-toggle-checkbox:checked ~ .nav-links {
    /* #173：上限改成跟著視口走＋面板自己可捲（原本是寫死 640px + overflow:hidden）。
       兩個理由：
       ①「捲不到」：.nav 是 position:sticky top:0，sticky 元素高過視口時底部
         永遠露不出來——面板若比視口高，最後幾個連結怎麼捲都到不了。
       ② 內容會繼續長：寫死的上限是「內容一超過就悄悄壞掉」的設計，這次就是
         nav 長到 807px 撞上 640px 才炸（見上方 flex-wrap 註解）。改成上限跟
         視口綁、超出的部分在面板內捲，之後再加幾個連結都不會再出事。
       160px＝nav 標頭（logo 列＋使用者列＋padding）的實測高度上緣：訪客帶
       CTA 條時面板起點量到 y=153，扣 140 會讓面板底端超出視口 13px（最後一
       列被切掉一截），扣 160 則兩種身分都留有餘裕。dvh 那行給 iOS 15.4+
       （網址列收合時 100vh 會比實際可視高度大），不支援的瀏覽器會忽略該行、
       落回上一行的 vh。 */
    max-height: calc(100vh - 160px);
    max-height: calc(100dvh - 160px);
    overflow-y: auto;
    /* #184 三輪（2026-08-22）：捲動容器不得再帶 transform——iOS 對「有
       transform 的 overflow 容器」只合成首塊、捲過去的區域空白且點不到
       （站長實機：面板半截空黑＋點了沒反應）。展開態 transform 歸 none，
       舊式 -webkit-overflow-scrolling:touch（iOS 13+ 已無作用且會放大此類
       畫面殘缺）一併移除。實際高度另由 nav.js 視口貼齊器 inline 覆寫。 */
    overscroll-behavior: contain;
    opacity: 1;
    transform: none;
    padding: 6px;
    /* 2026-07-15 使用者實機回報「手機選單點了沒反應」根治：overlay 與本面板
       同為 .nav（sticky, z=20 stacking context）子元素，overlay z=15 疊在
       無 z-index 的面板之上，整個選單被透明遮罩蓋住——點任何項目實際點到
       遮罩（= 關閉選單的 label）。面板設 z=16 疊回遮罩上；遮罩仍蓋頁面
       內容、點面板外空白仍可關閉，行為符合原設計意圖。 */
    position: relative;
    z-index: 16;
  }

  .nav-toggle-checkbox:checked ~ .nav-toggle-overlay {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 15;
    background: rgba(var(--shadow-rgb), 0.35);
  }
}

/* ---------- BUTTONS ---------- */

.btn-run,
.btn-save,
.btn-analyze,
.btn-primary {
  background: var(--brand-gradient);
  background-size: 160% 160%;
  color: var(--on-accent);
  border: none;
  border-radius: 10px;
  padding: 9px 18px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: transform 150ms var(--ease), box-shadow 150ms var(--ease), filter 150ms var(--ease);
  box-shadow: 0 4px 16px rgba(var(--brand-blue-rgb), 0.25);
}

.btn-run:hover:not(:disabled),
.btn-save:hover:not(:disabled),
.btn-analyze:hover:not(:disabled),
.btn-primary:hover:not(:disabled) {
  filter: brightness(1.08);
  box-shadow: 0 6px 22px rgba(var(--brand-blue-rgb), 0.4);
  transform: translateY(-1px);
}

.btn-run:active:not(:disabled),
.btn-save:active:not(:disabled),
.btn-analyze:active:not(:disabled) {
  transform: translateY(0);
}

.btn-run:disabled,
.btn-save:disabled,
.btn-analyze:disabled,
.btn-primary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.btn-ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 150ms var(--ease), background 150ms var(--ease);
}

.btn-ghost:hover:not(:disabled) {
  border-color: var(--brand-blue);
  background: rgba(var(--brand-blue-rgb), 0.08);
}

.btn-ghost:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn-danger {
  background: rgba(var(--up-rgb), 0.12);
  color: var(--up);
  border: 1px solid rgba(var(--up-rgb), 0.3);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: background 150ms var(--ease);
}

.btn-danger:hover:not(:disabled) {
  background: rgba(var(--up-rgb), 0.22);
}

.spinner {
  width: 12px;
  height: 12px;
  border: 2px solid rgba(var(--surface-tint-rgb), 0.35);
  border-top-color: var(--on-accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  display: inline-block;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ---------- TABS ---------- */

/* [#177] 2026-08-16：`top` 原本寫死 59px（＝當時量到的 nav 高度），但 .nav
   會被事後注入的內容撐高——nav.js 拿到 /auth/me 才插 tier 徽章與主題調色盤
   鈕，窄螢幕下 .nav-actions 一換行 nav 就從一排變兩排。寫死值會讓整條頁籤
   往下滑時滑進 nav（z-index 20 > 本條 19）底下被蓋住。改吃 nav.js 用
   ResizeObserver 持續發布的 `--sv-nav-h`（見 nav.js [#177] 區塊）；變數缺席
   時 fallback 回 59px＝改動前逐字相同的行為。共用錨點頁籤
   （anchor_tabs.css .sv-anchor-tabs）是同一套修法。 */
.tabs {
  display: flex;
  background: rgba(var(--surface-scrim-rgb), 0.7);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: var(--sv-nav-h, 59px);
  z-index: 19;
  backdrop-filter: blur(10px);
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs::-webkit-scrollbar { display: none; }

.tab-btn {
  flex: 1 0 auto;
  background: none;
  border: none;
  padding: 13px 16px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  transition: color 150ms var(--ease), border-color 150ms var(--ease);
}

.tab-btn:hover {
  color: var(--text);
}

.tab-btn.active {
  color: var(--text-strong);
  border-bottom-color: var(--brand-cyan);
}

/* ---------- MAIN CONTENT ---------- */

main {
  flex: 1;
  padding: clamp(14px, 2vw, 28px) clamp(12px, 2.4vw, 32px) clamp(32px, 3vw, 44px);
  max-width: 1600px;
  width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
  animation: fadeIn 200ms var(--ease);
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

.empty-state {
  text-align: center;
  color: var(--text-faint);
  padding: 16px;
  min-height: 90px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  box-sizing: border-box;
}

.empty-state .empty-icon {
  display: block;
  margin: 0 auto 14px;
  opacity: 0.6;
}

.notice-banner {
  background-color: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-fg);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 12px;
}

/* ---------- AI 內容「舊分析」誠實標註（W11 M3，2026-07-22）----------
   情境：後端資料已比 AI 評論的基準日新（例如期貨籌碼/融資融券傍晚落庫，
   AI 評論還沒追上），前端誠實告知「不是壞掉，是還在生成中」，不默默端出
   舊分析卻不說（見 docs/w11_ai_sync_spec_20260722.md）。全域層 class，
   目前接：市場頁大盤點評（market.js renderMarketReviewStaleNotice()）、
   期貨籌碼頁散戶多空比觀察（futures.js renderRetailRatioStaleNotice()）；
   未來其他 AI 區塊要接同款標註直接沿用這個 class，不要各頁各刻一份。
   顏色刻意用 --accent（藍）而非 --warn（橘）：這不是警示——資料本身沒有
   問題，只是分析還沒跟上，用中性告知色，與 .ai-review-freshness-banner
   （盤中資料未跟上今天，那才是真正的警示）區分開。 */
.ai-stale-notice {
  display: none;
  align-items: center;
  gap: 6px 10px;
  flex-wrap: wrap;
  background: var(--accent-bg);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.35);
  border-radius: var(--radius-sm);
  padding: 9px 14px;
  margin-bottom: 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-text);
  line-height: 1.5;
}

/* ---------- 大盤環境卡（首頁 TAIEX 指數卡）----------
   #200 質感重設計（2026-08-17，站長 08:40「指數顯示也改有質感的設計」）。

   舊版是「圓點＋三行素文字」：大數字 28px、漲跌與指數同一行接一段灰字、
   成交金額/筆數兩行純文字靠右貼邊，手機直排時圓點還會獨佔一行（見
   _screenshots/task200/*_before_card.png）。本次改成四段式：
     .market-eyebrow    寬度燈號＋「台股加權指數 TAIEX（MM-DD 收盤）」
     .market-index-row  大數字（主角，字級 1.5x）＋漲跌膠囊徽章
     .market-substats   成交金額／成交筆數兩塊並排 sub-stat 磚
   卡面／膠囊的質感配方**不自創**：卡面走 app.css 檔尾質感層共用代幣
   （`--sv-card-sheen`/`--sv-card-inset`/`--sv-card-shadow`，#193 統計卡同
   一支），膠囊逐項對齊大盤頁 market.css `.index-hero-chip`（同樣的
   color-mix 旋鈕命名與量級），全站兩張「指數主卡」講同一種話。

   四主題：深色底吃白高光、光暈可強；淺色三主題（light-a/b/c）白底吃不了
   光，一律把品牌暈與語意光暈收斂（同 .index-hero 的旋鈕邏輯）。本段零寫死
   色值，顏色一律由 --up/--down/--watch-fg/--brand-* 代幣現算。 */

.market-card {
  position: relative;
  /* ---- 強度旋鈕（深色主題基準；淺色三主題在下一條收斂）---- */
  --mkt-wash-1: 0.13;      /* 左上品牌藍角落暈 */
  --mkt-wash-2: 0.11;      /* 右上品牌紫角落暈 */
  --mkt-chip-a1: 26%;      /* 徽章底漸層亮端 */
  --mkt-chip-a2: 12%;      /* 徽章底漸層暗端 */
  --mkt-chip-border: 40%;
  --mkt-chip-glow: 30%;    /* 徽章柔光暈 */
  --mkt-chip-gloss: 26%;   /* 徽章內緣細高光 */
  --mkt-lift: 16%;         /* 大數字的極輕落影 */
  --mkt-dot-glow: 0.55;    /* 寬度燈號光暈 */
  --mkt-dot-ring: 0.16;

  /* 卡面四層：品牌角落暈（舊版 135deg 線性漸層的升級版，改成左上藍／右上
     紫兩顆 radial，卡面有方向感而不是一片糊）→ 質感層 sheen（上緣高光）
     → 卡底色。 */
  background:
    radial-gradient(118% 150% at 0% 0%, rgba(var(--brand-blue-rgb), var(--mkt-wash-1)), transparent 58%),
    radial-gradient(112% 150% at 100% 0%, rgba(var(--brand-violet-rgb), var(--mkt-wash-2)), transparent 60%),
    var(--sv-card-sheen),
    var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 22px;
  margin-bottom: 16px;
  display: grid;
  /* 右欄給 0.42fr（而非 auto）：auto 會讓兩塊磚縮到 max-content，1280 卡片
     中段留下一大片空白。0.42fr 讓磚跟著卡片長，桌機每塊約 170px、超寬螢幕
     也不會失控；minmax 下限 260px 保證中間尺寸（768–1000px）不擠爛。 */
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.42fr);
  align-items: center;
  gap: 14px 30px;
  box-shadow: var(--sv-card-shadow), var(--sv-card-inset);
}

:root[data-theme="light-a"] .market-card,
:root[data-theme="light-b"] .market-card,
:root[data-theme="light-c"] .market-card,
:root[data-theme="champagne"] .market-card {
  --mkt-wash-1: 0.07;
  --mkt-wash-2: 0.06;
  --mkt-chip-a1: 18%;
  --mkt-chip-a2: 8%;
  --mkt-chip-border: 34%;
  --mkt-chip-glow: 14%;
  --mkt-chip-gloss: 60%;
  --mkt-lift: 10%;
  --mkt-dot-glow: 0.34;
  --mkt-dot-ring: 0.13;
}

.market-card .market-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

/* eyebrow：燈號＋標題同一行。舊版燈號是卡片最左的孤立圓點，手機直排會被
   擠成獨佔一行的孤兒（#200 before 390px 實測），貼著標題才讀得出它在講
   哪張卡。 */
.market-card .market-eyebrow {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.market-card .market-light {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* 燈號＝實色點＋同色微光暈＋一圈極淡外環（把點從卡面抬起來，不是發光特效）。
   green 吃 --down、red 吃 --up 是台股紅漲綠跌慣例下的**顏色名對應**（--down
   在四主題都是綠系、--up 是紅系），不是寫反。 */
.market-light.green {
  background: var(--down);
  box-shadow: 0 0 0 3px rgba(var(--down-rgb), var(--mkt-dot-ring, 0.16)),
    0 0 12px rgba(var(--down-rgb), var(--mkt-dot-glow, 0.55));
}

.market-light.red {
  background: var(--up);
  box-shadow: 0 0 0 3px rgba(var(--up-rgb), var(--mkt-dot-ring, 0.16)),
    0 0 12px rgba(var(--up-rgb), var(--mkt-dot-glow, 0.55));
}

.market-light.yellow {
  background: var(--watch-fg);
  box-shadow: 0 0 0 3px rgba(var(--watch-rgb), var(--mkt-dot-ring, 0.16)),
    0 0 12px rgba(var(--watch-rgb), var(--mkt-dot-glow, 0.55));
}

.market-card .market-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  min-width: 0;
  line-height: 1.4;
}

.market-card .market-index-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
}

/* 主角數字：字級由舊版 clamp(20,…,28) 拉到 clamp(30,…,42)（手機/桌機各約
   1.5x），tabular-nums 讓盤中每秒跳動時位數不左右抖。 */
.market-card .market-index {
  font-size: clamp(30px, 2.2vw + 20px, 42px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.02;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  text-shadow: 0 1px 3px color-mix(in srgb, var(--text-strong) var(--mkt-lift), transparent);
}

/* ---- 漲跌膠囊徽章 ----
   結構由 app.js paintTaiexChangeBadge() 產生（箭頭／漲跌點／漲跌幅三顆子
   節點），tone class（up/down/flat）掛在膠囊自己身上：盤中 SSE 改寫時整顆
   一起重繪，底色與箭頭必定同步翻轉。字色由全域 .up/.down/.flat 負責，這裡
   只管底、邊、光。 */
.market-card .market-change {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  padding: 6px 13px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-2);
  font-size: 15px;
  font-weight: 800;
  line-height: 1.1;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.market-card .market-change-arrow {
  font-size: 11px;
  line-height: 1;
}

.market-card .market-change-pct {
  font-size: 13px;
  font-weight: 700;
  opacity: 0.88;
}

.market-card .market-change.up {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--up) var(--mkt-chip-a1), transparent),
    color-mix(in srgb, var(--up) var(--mkt-chip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--up) var(--mkt-chip-border), transparent);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--up) var(--mkt-chip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--up) var(--mkt-chip-gloss), white);
}

.market-card .market-change.down {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--down) var(--mkt-chip-a1), transparent),
    color-mix(in srgb, var(--down) var(--mkt-chip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--down) var(--mkt-chip-border), transparent);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--down) var(--mkt-chip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--down) var(--mkt-chip-gloss), white);
}

/* 平盤／缺值（假日快照沒帶漲跌，徽章只顯示「—」）：中性底，不上紅綠語意。 */
.market-card .market-change.flat {
  background: var(--bg-2);
  border-color: var(--border);
  box-shadow: var(--sv-pill-inset);
}

.market-card .market-change.is-missing {
  color: var(--text-faint);
  font-weight: 700;
}

/* ---- 櫃買 OTC 副指數膠囊（#204，2026-08-17）----
   站長 08-17 令「首頁兩處重複顯示加權指數，擇一顯示」：首頁停用市場脈搏
   速覽列（index.html 三處註解包裝），速覽列獨有的「櫃買 OTC」併進本卡，
   接在漲跌徽章後面。結構由 app.js buildOtcChip()/paintOtcChip() 產生。

   設計要點是**低一階、同一種話**：配方與上面的漲跌徽章同源（同一組
   color-mix 旋鈕命名、同樣的膠囊幾何），但每個量級都刻意收小——字級 16/12.5
   對 42/15、光暈 --mkt-otc-glow 只有徽章的一半、底漸層更淡。這樣它讀起來
   是「加權旁邊的副指數」，而不是第二個主角，也不會像事後補上的貼片。
   底盤用 --sv-pill-bg/--sv-pill-inset（與右側 sub-stat 磚同一支），
   讓卡內三種小元件（徽章／磚／膠囊）維持同一族。 */
.market-card .market-otc {
  --mkt-otc-a1: 15%;
  --mkt-otc-a2: 6%;
  --mkt-otc-border: 32%;
  --mkt-otc-glow: 14%;

  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--sv-pill-bg), var(--bg-2);
  box-shadow: var(--sv-pill-inset);
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  transition: border-color 150ms var(--ease), background 150ms var(--ease);
}

:root[data-theme="light-a"] .market-card .market-otc,
:root[data-theme="light-b"] .market-card .market-otc,
:root[data-theme="light-c"] .market-card .market-otc,
:root[data-theme="champagne"] .market-card .market-otc {
  --mkt-otc-a1: 11%;
  --mkt-otc-a2: 5%;
  --mkt-otc-border: 28%;
  --mkt-otc-glow: 8%;
}

/* 抓不到 OTC 報價時整顆不顯示（app.js paintOtcChip 用 `hidden` 屬性控制）。
   這條**不能省**：上面的 display:inline-flex 是作者樣式，會蓋掉瀏覽器預設
   給 [hidden] 的 display:none，沒有這條的話「隱藏」根本不會生效。 */
.market-card .market-otc[hidden] {
  display: none;
}

.market-card .market-otc:hover,
.market-card .market-otc:focus-visible {
  border-color: var(--border-strong);
  background: var(--card-bg-hover);
}

.market-card .market-otc-name {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--text-faint);
}

.market-card .market-otc-value {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text-strong);
}

.market-card .market-otc-change {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text-muted);
}

.market-card .market-otc-arrow {
  font-size: 9.5px;
  line-height: 1;
}

/* 資料日/盤中時間小字（比照 .market-substat-note 的字級與色）：不標日期的
   指數看起來永遠像今天的價（2026-07-10 使用者回報換來的規矩）。 */
.market-card .market-otc-note {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-faint);
}

.market-card .market-otc-note:empty {
  display: none;
}

.market-card .market-otc.up {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--up) var(--mkt-otc-a1), transparent),
    color-mix(in srgb, var(--up) var(--mkt-otc-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--up) var(--mkt-otc-border), transparent);
  box-shadow: 0 1px 6px color-mix(in srgb, var(--up) var(--mkt-otc-glow), transparent);
}

.market-card .market-otc.down {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--down) var(--mkt-otc-a1), transparent),
    color-mix(in srgb, var(--down) var(--mkt-otc-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--down) var(--mkt-otc-border), transparent);
  box-shadow: 0 1px 6px color-mix(in srgb, var(--down) var(--mkt-otc-glow), transparent);
}

/* 漲跌字色跟著 tone 走（tone class 掛在膠囊本體，不是掛在字上——盤中重繪
   整顆一起翻，底色與字色不可能各翻各的）。平盤維持中性灰，不上紅綠。 */
.market-card .market-otc.up .market-otc-change {
  color: var(--up);
}

.market-card .market-otc.down .market-otc-change {
  color: var(--down);
}

/* ---- 成交金額／成交筆數 sub-stat 磚 ----
   舊版是兩行素文字靠右貼邊（signals.css 還為此補過一條 border-left 把它
   拉離邊緣）；改成兩塊等高並排小磚：小標籤＋粗體數值＋資料日小字。
   資料日小字是 2026-07-09/07-10 兩次使用者回報換來的，一字不減。 */
.market-card .market-substats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  min-width: 0;
}

/* 成交筆數磚被時效閘門藏起來時（#201：筆數資料日不是最新那一場，見
   app.js renderMarketCard() 的 showTransaction），剩下的成交金額磚獨佔
   整欄，不要留半格空白——2 欄 grid 只放 1 塊磚會讓它縮在左半邊、右半邊
   開天窗，看起來像沒載完。 */
.market-card .market-substats.is-single {
  grid-template-columns: minmax(0, 1fr);
}

.market-card .market-substat {
  min-width: 128px;
  padding: 10px 14px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--sv-pill-bg), var(--bg-2);
  box-shadow: var(--sv-pill-inset);
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.market-card .market-substat-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  white-space: nowrap;
}

.market-card .market-substat-value {
  font-size: 19px;
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.market-card .market-substat-note {
  font-size: 10.5px;
  line-height: 1.35;
  color: var(--text-faint);
  margin-top: 1px;
}

/* 資料日/口徑標籤缺席時（FMTQIK 沒帶 date）整行收起，不留空白撐高磚。
   兩塊磚仍等高——grid 的 align-items 預設 stretch。 */
.market-card .market-substat-note:empty {
  display: none;
}

/* ---------- 環境分數卡「今日一句話」（W9 M1，2026-07-22新增，施工正本
   docs/w9_spec_20260722.md）----------
   獨立於上面 .market-card（TAIEX 指數卡，顯示原始行情）：這裡顯示規則式
   五分量環境溫度計判讀（datasource.market_environment.compute_environment()），
   首頁「今日精選」分頁頂部常駐。燈色沿用台股慣例紅漲綠跌語意
   （--up=偏多、--down=偏空，與 .market-light 同一套配色慣例），中性用
   --watch-fg（同 .market-light.yellow 既有用色）；class 名與 .market-light
   刻意不共用（值域不同：bullish/neutral/bearish vs green/yellow/red），
   避免未來各自改配色時誤動另一元件。 */
.env-score-card {
  background: linear-gradient(135deg, rgba(var(--brand-blue-rgb), 0.06), rgba(var(--brand-violet-rgb), 0.06)), var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 18px;
  margin-bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  box-shadow: var(--shadow-card);
}

.env-score-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}

.env-score-dot.bullish { background: var(--up); box-shadow: 0 0 12px rgba(var(--up-rgb), 0.55); }
.env-score-dot.bearish { background: var(--down); box-shadow: 0 0 12px rgba(var(--down-rgb), 0.55); }
.env-score-dot.neutral { background: var(--watch-fg); box-shadow: 0 0 12px rgba(var(--watch-rgb), 0.55); }

.env-score-main {
  flex: 1;
  min-width: 200px;
}

.env-score-label {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
}

/* ⚠ FT-52 M3-9（2026-08-06）起**全站無使用處**：分數改由卡內迷你儀表的中央
   數字顯示（見下方 .env-mini-gauge 區塊與 app.js renderEnvScoreTodayCard()），
   這顆規則保留只是為了讓讀到舊註解的人對得上，不要再接新的使用處。 */
.env-score-value {
  font-size: clamp(18px, 1.1vw + 14px, 24px);
  font-weight: 800;
  color: var(--text);
}

.env-score-light-text {
  font-size: 13px;
  font-weight: 700;
}
.env-score-light-text.bullish { color: var(--up); }
.env-score-light-text.bearish { color: var(--down); }
.env-score-light-text.neutral { color: var(--watch-fg); }

.env-score-today-line {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.5;
}

.env-score-more-link {
  font-size: 12px;
  color: var(--brand-cyan-text);
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}
.env-score-more-link:hover { text-decoration: underline; }

/* ---------- 迷你環境儀表＋燈號 chip（FT-52 M3-9，2026-08-06）----------
   站長 2026-08-06 19:58 七張截圖點名：素白框數字磚與同頁已升級的視覺放在
   一起顯舊。本卡的升級＝「小圓點＋純文字分數」換成 funnel.js envGaugeSVG()
   的縮小版儀表（幾何複製，見 app.js envMiniGaugeSVG() 註解；首頁不載入
   funnel.css，所以樣式在這裡各留一份，改一邊要同步另一邊），燈號文字包成
   與 /market 指數 hero chip（market.css .index-hero-chip）同款的漸層底 chip。
   顏色全部由主題代幣 color-mix() 現算，本區塊零寫死色；深/淺兩套強度旋鈕
   分開（深底吃得住光暈、白底要極輕否則髒）。 */
.env-score-gauge-wrap {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
}

.env-score-gauge {
  display: block;
  width: 120px;
}

/* viewBox 天生等比：給寬度就好，高度自動。 */
.env-mini-gauge {
  width: 100%;
  height: auto;
  display: block;
  --egm-lit: 55%;    /* 亮端保留多少原色（其餘混白） */
  --egm-shade: 74%;  /* 暗端保留多少原色（其餘混黑） */
  --egm-glow: 46%;   /* 指針柔光暈：小圖的光影就是質感本體，比大版再強一階 */
  --egm-ndl-lit: 34%;   /* 指針受光側保留多少原色（其餘混白） */
  --egm-ndl-shade: 56%; /* 指針背光側保留多少原色（其餘混黑） */
  --egm-hub-ring: 62%;  /* 軸帽外圈細環的金屬感強度 */
  /* 擬真錶盤（FT-52 M3-10）：錶圈金屬走中性代幣（--text-muted），刻意不吃
     accent——指針/旋鈕已經是 accent 金屬，整圈外環再上一次會變單色一坨。
     與 /funnel 大版（funnel.css .fn-env-gauge 同名旋鈕）逐顆同值。 */
  --egm-bez-lit: 30%;
  --egm-bez-mid: 46%;
  --egm-bez-shade: 66%;
  --egm-bez-gloss: 40%;
  --egm-face-a: 9%;     /* 錶面亮端：--text 疊在 --card-bg 上的比例 */
  --egm-face-b: 3%;     /* 錶面暗端 */
}

:root[data-theme="light-a"] .env-mini-gauge,
:root[data-theme="light-b"] .env-mini-gauge,
:root[data-theme="light-c"] .env-mini-gauge,
:root[data-theme="champagne"] .env-mini-gauge {
  --egm-lit: 70%;
  --egm-shade: 86%;
  --egm-glow: 22%;
  --egm-ndl-lit: 50%;
  --egm-ndl-shade: 72%;
  --egm-hub-ring: 74%;
  /* 白底：錶圈要更淡才不會像一圈黑框；錶面往深處走一點點（白上加白＝
     看不見錶盤）。 */
  --egm-bez-lit: 18%;
  --egm-bez-mid: 30%;
  --egm-bez-shade: 46%;
  --egm-bez-gloss: 72%;
  --egm-face-a: 7%;
  --egm-face-b: 2%;
}

/* 三段分區弧的漸層端色（<stop> 繼承上面 .env-mini-gauge 的自訂屬性）。
   分區色沿用 AI 分數三階代幣，與 /funnel 完整版逐顆相同。 */
.egm-stop-low-0 { stop-color: color-mix(in srgb, var(--score-low) var(--egm-lit), white); }
.egm-stop-low-1 { stop-color: var(--score-low); }
.egm-stop-low-2 { stop-color: color-mix(in srgb, var(--score-low) var(--egm-shade), black); }
.egm-stop-mid-0 { stop-color: color-mix(in srgb, var(--score-mid) var(--egm-lit), white); }
.egm-stop-mid-1 { stop-color: var(--score-mid); }
.egm-stop-mid-2 { stop-color: color-mix(in srgb, var(--score-mid) var(--egm-shade), black); }
.egm-stop-high-0 { stop-color: color-mix(in srgb, var(--score-high) var(--egm-lit), white); }
.egm-stop-high-1 { stop-color: var(--score-high); }
.egm-stop-high-2 { stop-color: color-mix(in srgb, var(--score-high) var(--egm-shade), black); }
/* 指針金屬稜線：受光側亮、背光側暗，分界是一條沿指針長軸的稜線
   （漸層方向垂直於軸向且跟著指針一起轉，見 app.js egm-grad-needle 座標）。 */
.egm-stop-needle-0 { stop-color: color-mix(in srgb, var(--accent) var(--egm-ndl-lit), white); }
.egm-stop-needle-1 { stop-color: var(--accent); }
.egm-stop-needle-2 { stop-color: color-mix(in srgb, var(--accent) var(--egm-ndl-shade), black); }
/* 中心旋鈕＝金屬帽：放射漸層（左上受光）用 accent 現算，與指針同一種金屬，
   不再是原本那顆卡片底色的深灰圓（小尺寸下會讀成「錶面破了一個洞」）。 */
.egm-stop-hub-0 { stop-color: color-mix(in srgb, var(--accent) 34%, white); }
.egm-stop-hub-1 { stop-color: color-mix(in srgb, var(--accent) 72%, black); }
/* 錶圈金屬三端（左上受光 → 主色 → 右下背光），來源是中性代幣 --text-muted
   疊在 --card-bg 上；與 /funnel 大版 .eg-stop-bezel-* 逐條相同。 */
.egm-stop-bezel-0 { stop-color: color-mix(in srgb, var(--text-muted) var(--egm-bez-lit), white); }
.egm-stop-bezel-1 { stop-color: color-mix(in srgb, var(--text-muted) var(--egm-bez-mid), var(--card-bg)); }
.egm-stop-bezel-2 { stop-color: color-mix(in srgb, var(--text-muted) var(--egm-bez-shade), black); }
/* 錶面：刻度印在上面的錶盤底，只跟卡面差一階。 */
.egm-stop-face-0 { stop-color: color-mix(in srgb, var(--text) var(--egm-face-a), var(--card-bg)); }
.egm-stop-face-1 { stop-color: color-mix(in srgb, var(--text) var(--egm-face-b), var(--card-bg)); }

/* 錶圈本體：填色由 SVG 屬性供應（外部樣式表的 url(#id) 會失效），這裡只加
   一層極輕落影把錶圈從卡面抬起來。 */
.egm-bezel {
  filter: drop-shadow(0 2px 4px rgba(var(--shadow-rgb), 0.3));
}

/* 錶圈內緣的 catch light＝金屬高光稜。 */
.egm-bezel-gloss {
  stroke: color-mix(in srgb, white var(--egm-bez-gloss), transparent);
}

.egm-face { stroke-linejoin: round; }

/* 主刻度（每 3 分一條；迷你版不標數字，見 app.js envMiniGaugeSVG() 註解）。 */
.egm-tick {
  stroke: var(--text-muted);
  stroke-width: 2.4;
  opacity: 0.62;
}

/* 懸浮感：小尺寸下光影就是質感的主要來源，落影比大版再重一階。 */
.egm-needle {
  filter: drop-shadow(0 3px 6px color-mix(in srgb, var(--accent) var(--egm-glow), transparent));
}

/* 軸帽外圈細環（金屬鏡框）：只有描邊、不填色。 */
.egm-hub-ring {
  stroke: color-mix(in srgb, var(--accent) var(--egm-hub-ring), transparent);
  stroke-width: 1.6;
}

/* 指針掃入：從錶面最左端（-9 分）轉到實際值。transform-origin 必須跟著
   app.js 的 cx/cy（150,150）——改幾何時兩邊要一起改。
   prefers-reduced-motion 由本檔全站規則壓成 0.01ms＝直接定格。 */
.egm-needle-g {
  transform-box: view-box;
  transform-origin: 150px 150px;
  transform: rotate(var(--egm-ndl-to, 0deg));
  animation: egm-needle-in 0.75s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes egm-needle-in {
  from { transform: rotate(var(--egm-ndl-from, 0deg)); }
  to { transform: rotate(var(--egm-ndl-to, 0deg)); }
}

/* 旋鈕本體：外圈細環已經負責金屬鏡框，這裡的描邊收細成一圈內緣線，
   不再是原本那顆 3px 粗邊小白點。 */
.egm-hub {
  stroke: color-mix(in srgb, var(--accent) 80%, transparent);
  stroke-width: 1.2;
  filter: drop-shadow(0 1px 3px rgba(var(--shadow-rgb), 0.35));
}

.egm-value {
  font-size: 48px;
  font-weight: 800;
  fill: var(--text);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}

/* 中央數字的燈色：class 名沿用本卡既有的 bullish/neutral/bearish
   （值域與 .market-light 的 green/yellow/red 不同，刻意不共用）。 */
.egm-value.bullish { fill: var(--up); }
.egm-value.bearish { fill: var(--down); }
.egm-value.neutral { fill: var(--watch-fg); }

.env-score-light-row {
  margin-top: 4px;
}

/* 燈號 chip：漸層底＋光暈＋內緣細高光，與 market.css .index-hero-chip
   同一套配方（那邊是漲跌色、這邊是環境燈色）。 */
.env-score-light-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--bg-2);
  white-space: nowrap;
  --envchip-a1: 26%;
  --envchip-a2: 12%;
  --envchip-border: 40%;
  --envchip-glow: 26%;
  --envchip-gloss: 26%;
}

:root[data-theme="light-a"] .env-score-light-chip,
:root[data-theme="light-b"] .env-score-light-chip,
:root[data-theme="light-c"] .env-score-light-chip,
:root[data-theme="champagne"] .env-score-light-chip {
  --envchip-a1: 18%;
  --envchip-a2: 8%;
  --envchip-border: 34%;
  --envchip-glow: 12%;
  --envchip-gloss: 60%;
}

.env-score-light-chip.bullish {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--up) var(--envchip-a1), transparent),
    color-mix(in srgb, var(--up) var(--envchip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--up) var(--envchip-border), transparent);
  box-shadow:
    0 2px 10px color-mix(in srgb, var(--up) var(--envchip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--up) var(--envchip-gloss), white);
}

.env-score-light-chip.bearish {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--down) var(--envchip-a1), transparent),
    color-mix(in srgb, var(--down) var(--envchip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--down) var(--envchip-border), transparent);
  box-shadow:
    0 2px 10px color-mix(in srgb, var(--down) var(--envchip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--down) var(--envchip-gloss), white);
}

.env-score-light-chip.neutral {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--watch-fg) var(--envchip-a1), transparent),
    color-mix(in srgb, var(--watch-fg) var(--envchip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--watch-fg) var(--envchip-border), transparent);
  box-shadow:
    0 2px 10px color-mix(in srgb, var(--watch-fg) var(--envchip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--watch-fg) var(--envchip-gloss), white);
}

/* chip 內的燈點：尺寸縮一階，燈色沿用上面 .env-score-dot.* 的既有規則。 */
.env-score-light-chip .env-score-dot {
  width: 9px;
  height: 9px;
}

@media (max-width: 640px) {
  .env-score-gauge {
    width: 96px;
  }
}

/* ---------- SIGNAL CARDS ----------
   連續流體格線：欄數由容器寬度 ÷ 卡片最小寬自動決定，不用固定斷點；
   中間任意寬度都會平順增減欄數，不會卡在整數斷點才變化。 */

.cards-grid {
  display: grid;
  /* 2026-07-15 三修（根因）：330px 最小卡寬的幾何不成立——卡頭「股名＋
     上櫃＋🆕新進」(~200px) 加右欄固定 130px 圖表欄＋內距，330px 卡只給
     名字 ~53px，一二修只是在不可能的空間裡挑犧牲者。380px 起名字至少
     98px（一般股名全顯，超長 ETF 名截尾配 hover 全名）。代價：~1400px
     視窗從 4 欄變 3 欄（每卡更寬更好讀）。 */
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
  gap: 12px;
}

.signal-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-card);
  transition: transform 150ms var(--ease), border-color 150ms var(--ease), box-shadow 150ms var(--ease);
  animation: fadeIn 200ms var(--ease);
}

/* ---------- 智選頁股票卡「完整/精簡」檢視切換（W6 M3，施工正本
   docs/w5w6_spec_20260722.md）----------
   幾何備註：精簡模式只是「隱藏」.sv-card-body（分析區塊），卡頭（股名／
   徽章／價格列，即 .signal-card 第一個 .row-head）在兩種模式下完全不變
   ——.cards-grid 380px 最小卡寬（見上方 2026-07-15 三修根因說明）本就是
   針對這個卡頭算出來的幾何下限，精簡模式移除的內容只會讓卡片變矮、不
   影響寬度需求，故不需要另外調整 grid minmax。 */

/* ---- 卡底列（FT-52 M3-12 第三輪，2026-08-07 站長 mockup）----
   左「更新 HH:MM:SS」小字、右「分析詳情 ›」文字連結。時間戳是從
   .price-head 搬下來的**同一個節點**（見 app.js renderSignalCard()），
   所以 SSE 推播照樣更新得到；沒有時間時 .card-quote-time 是空的，
   :empty 不佔位但 flex 的 space-between 仍把連結壓在右邊。 */
.sv-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

/* 觸發器從「整行虛線框按鈕」改成卡底右側文字連結（站長 mockup）。
   行為未變，只換外觀——沿用同一個 class 讓既有選擇器與測試不失效。 */
.sv-compact-expand-toggle {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 2px 0;
  color: var(--accent-text);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}

.sv-compact-expand-toggle:hover {
  text-decoration: underline;
}

/* 收折現在是**無條件**規則（M3-12 第三輪把完整/精簡切換整組移除：那個
   「完整」模式就等於現在的「已展開」，語意重複）。單卡獨立展開仍然只靠
   卡片自己的 .expanded class，行為與事件處理一個字沒改。 */
.signal-card .sv-card-body {
  display: none;
}

.signal-card.expanded .sv-card-body {
  display: block;
}

.signal-card:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(var(--shadow-rgb), 0.3), 0 14px 32px rgba(var(--shadow-rgb), 0.35);
}

/* 2026-08-06 跑版根治（站長 13:31 手機實拍：四張週選卡兩張把「AI 判讀」
   膠囊＋迷你 K 線掉到左欄下方、適配徽章被推到最右上）。
   === 幾何根因（B27：擠壓 bug 先算最小寬幾何）===
   390px 手機下這一列的可用寬只有 298px（390 −main 24 −group border 2
   −group padding 28 −card border 2 −card padding 36）。右欄 .signal-card-
   side 是 flex:none 的 130px，加 8px gap ＝ 138px，左欄只剩 160px。
   但**flex 換行的判斷用的是 flex item 的 hypothetical main size（flex-
   basis:auto → 內容 max-content 寬），不是收縮後的實寬**——左欄 max-
   content 實測 200.6~204.9px（股名列）、145.8~191.9px（價格列），一律
   遠超 160px，於是 `flex-wrap: wrap` 讓右欄整個掉到第二行；右欄一走，
   左欄變滿版，.stock-name-text 的 flex-grow 又把徽章推到最右緣。
   換言之舊寫法的排版結果完全由「這檔股票的字串多長」決定，同一組卡片
   必然出現兩種版型（站長截圖裡的四張卡兩種樣子）。
   === 修法 ===
   卡頭永不換行（nowrap）：左欄 min-width:0 收縮、右欄固定，「左資訊＋
   右圖」在任何寬度、任何資料下都是同一個結構。左欄放不下時由內部元件
   自行折行（.stock-line 本就 flex-wrap、.price-head 手機直排），不再把
   壓力轉嫁成整列換行。 */
.signal-card .row-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  flex-wrap: nowrap;
}

/* 2026-07-15 使用者回報修復（爆框＋長股名換行）：
   1. 卡頭左欄 min-width:0 允許收縮、右欄 .signal-card-side flex:none 固定
      ——「AI 判讀」徽章不再被擠出卡框（實測 385px 卡寬時徽章距右緣僅 3px，
      更窄視窗即溢出）。
   2. .stock-line 改 flex＋股名 .stock-name-text ellipsis 單行截斷（hover
      title 顯全名），市場/新進徽章 flex:none 永遠完整。 */
.signal-card .row-head > div:first-child {
  flex: 1 1 auto;
  min-width: 0;
}

.signal-card .stock-line {
  font-size: 15.5px;
  font-weight: 700;
  color: var(--text);
  display: flex;
  align-items: center;
  /* 2026-07-29 三修：允許整列換行——長 ETF 名（最長「凱基ESG BBB債15+」
     13 字＋6 碼代號）單行放不下時，徽章折到下一行而不是壓縮股名。 */
  flex-wrap: wrap;
  gap: 6px 6px;
  min-width: 0;
}

.signal-card .stock-name-text {
  /* 2026-07-29 三修（站長：「調整一下顯示全名」）：ETF 全名被 ellipsis
     截成「00981D 主動中信…」，而 hover title 在手機看不到＝行動端等於
     看不到全名。改為**允許折行、不截斷**：財經資訊的識別（買到哪一檔）
     優先於卡片高度齊一；同列卡片在 grid 內本就等高，折行只會讓該列整體
     長一點點，不會亂序（2026-07-13 排版一致性修法仍成立）。
     保留 min-width 9ch：窄幕下先吃滿可用寬再折行。
     2026-08-06 四修（跑版根治）：flex-grow 由 1 改 0。grow=1 時只要這一列
     有剩餘空間，股名就把自己撐滿、把「上市／適配 68」等徽章推到卡片最右
     緣（站長截圖上「適配 badge 被推到最右上」就是這個，不是徽章自己跑掉）。
     徽章的正確位置是緊貼股名，故只保留 shrink 不要 grow；窄幕下仍會收縮
     ＋折行，行為與三修一致。 */
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.3;
  min-width: 9ch;
  flex: 0 1 auto;
}

.signal-card .stock-line .market-tag,
.signal-card .stock-line .sv-new-badge {
  flex: none;
}

.signal-card .close-price {
  color: var(--text-muted);
  font-size: 13px;
  margin-top: 2px;
}

/* ---------- 漲跌語意色（全站共用；台股慣例紅漲綠跌） ---------- */

.up { color: var(--up); }
.down { color: var(--down); }
.flat { color: var(--text-muted); }

/* ---------- 現價 + 漲跌點數/% 頭部（訊號卡 / 自選股網格共用） ---------- */

/* 價位區固定兩行版式（2026-07-13 使用者回報「排版順序要一致」）：
   原本是 flex-wrap 列，價格位數與右側迷你圖擠壓寬度不同時，漲跌/更新
   時間會隨機折行，四張卡四種順序。改 grid 寫死：第一行＝大字價格＋
   漲跌並排，第二行＝更新時間戳（獨立整行），任何寬度下順序一致。 */
.price-head {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 8px;
  row-gap: 2px;
  align-items: baseline;
  margin-top: 4px;
}

.price-big {
  font-size: clamp(20px, 1vw + 16px, 26px);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  grid-row: 1;
  grid-column: 1;
}

/* 2026-08-06：white-space 由 nowrap 改 normal。內容是「漲跌點＋兩個空白＋
   漲跌幅」（見 app.js buildPriceHeadEl），nowrap 讓它的 min-content ＝整串
   （桌機 26px 價格＋四位數股價時實測價格列 max-content 218px＞卡頭左欄可用
   212px），擠不下時會直接壓到右邊的迷你 K 線上。改 normal 之後最窄情況只
   會在那兩個空白處折成兩行——兩段各自沒有空白，永遠不會被折斷或截字，
   財經數字不會被切一半。常態（放得下）行為與舊版完全相同。 */
.price-change {
  font-size: 12.5px;
  font-weight: 700;
  white-space: normal;
  grid-row: 1;
  grid-column: 2;
  justify-self: start;
}

/* 卡片更新時間戳（2026-07-13）：today 訊號卡與自選股磚共用，故放全域
   元件層（原在 signals.css 只有首頁吃得到）。:empty 隱藏不佔第二行。 */
.price-head .card-quote-time {
  font-size: 10.5px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  grid-row: 2;
  grid-column: 1 / -1;
}

.price-head .card-quote-time:empty {
  display: none;
}

.price-head .price-fallback-date-hint {
  grid-column: 1 / -1;
}

/* 冷載入骨架（規格 M4，切頁閃跳修正）：模組級記憶是空的（本次頁面
   work session 從未套用過即時報價）時，第一幀顯示淡色「—」，絕不先畫
   選股日/API 快照收盤價；等 applyLiveQuotesOnce() 回來才真正填值，
   或斷網時 fallback 顯示資料自帶收盤（見 .price-fallback-date-hint）。 */
.price-cold-skeleton {
  color: var(--text-faint);
  opacity: 0.55;
}

/* 斷網保底顯示的資料日期小標（如「2026-07-07 收盤」），避免使用者誤以為
   fallback 顯示的收盤價是當日即時價。 */
.price-fallback-date-hint {
  font-size: 11px;
  color: var(--text-faint);
  white-space: nowrap;
}

.signal-card-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  flex: none; /* 2026-07-15：固定右欄，AI 判讀徽章不被左欄擠出卡框 */
  /* 二修：右欄設寬度上限——任何內容（盤中走勢圖等）把右欄撐寬都會被鎖住，
     不再把擠壓轉嫁給左欄股名。 */
  max-width: 150px;
  overflow: hidden;
}

/* 二修：訊號卡內迷你走勢圖讓位（150→130px），股名多 20px 呼吸空間；
   自選股 watch-tile 的同 class 不受影響（該處另有 3393 行的專屬覆寫）。 */
.signal-card-side .mini-chart-canvas {
  width: 130px;
}

.mini-chart-canvas {
  width: 150px;
  height: 64px;
  display: block;
}

.score-big {
  font-size: clamp(22px, 1vw + 18px, 30px);
  font-weight: 800;
  line-height: 1;
  color: var(--score-mid);
}

.score-big.score-high { color: var(--score-high); text-shadow: 0 0 18px rgba(var(--score-high-rgb), 0.35); }
.score-big.score-mid { color: var(--score-mid); }
.score-big.score-low { color: var(--score-low); }

.score-big.empty {
  color: var(--text-faint);
  font-size: 20px;
}

/* ---------- 「這代表什麼？」說明彈窗（任務新增） ---------- */

/* 說明藥丸鈕（任務#154 重設計）：病灶——舊版 .info-icon-btn 是 22px 空心
   圓圈、只有 ⓘ 符號沒有文字，又獨立浮在 quick-filter-bar 正上方自成一
   行，使用者截圖回報「太小太不起眼」看不出是可互動的說明入口。改為帶
   文字的品牌 pill 鈕，直接併入 .quick-filter-bar 同一列（工具列最左，
   與下拉選單同高對齊）；視覺比照 .chip-theme 的品牌藍描邊風格但用
   brand-cyan 呼應原本的 ⓘ 配色。點擊行為不變，仍呼叫 showInfoModal()
   開同一份彈窗內容（見 app.js）。 */
.info-pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.35);
  background-color: rgba(var(--brand-cyan-rgb), 0.08);
  color: var(--brand-cyan-text);
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  flex: 0 0 auto;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), transform 150ms var(--ease);
}

.info-pill-btn:hover {
  background-color: rgba(var(--brand-cyan-rgb), 0.18);
  border-color: var(--brand-cyan);
}

.info-pill-btn:focus-visible {
  outline: 2px solid var(--brand-cyan);
  outline-offset: 2px;
}

.info-pill-btn:active {
  transform: translateY(1px);
}

.info-pill-icon {
  font-size: 15px;
  line-height: 1;
}

.info-pill-text {
  line-height: 1;
}

.info-pill-text-short {
  display: none;
}

/* 375px 等窄螢幕：文字縮短為「說明」（圖示＋文字兩者都保留，不退回純
   圖示），觸控目標同時加大到 40px 高，滿足行動裝置最小觸控尺寸建議。 */
@media (max-width: 480px) {
  .info-pill-btn {
    height: 40px;
    padding: 0 12px;
  }
  .info-pill-text-full {
    display: none;
  }
  .info-pill-text-short {
    display: inline;
  }
  .info-pill-icon {
    font-size: 17px;
  }
}

.info-modal-overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(var(--scrim-rgb), 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 200;
  animation: fadeIn 150ms var(--ease);
}

/* hidden 屬性免疫：上面的無條件 display:flex 會蓋過 hidden 屬性的 UA 樣式
   （display:none），任何用 el.hidden 開關這個 overlay 的元件都會「開得起來
   關不掉」——2026-07-09 意見回饋 modal 實際踩到（× 與取消都失效）。此規則
   讓 hidden 屬性永遠贏，保護所有現在與未來共用這個 class 的彈窗。 */
.info-modal-overlay[hidden] {
  display: none !important;
}

.info-modal-card {
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(var(--shadow-rgb), 0.5);
  padding: 22px 24px;
  max-width: 520px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
}

.info-modal-card h3 {
  margin: 0 0 6px;
  font-size: 17px;
  color: var(--text);
}

.info-modal-card h4 {
  margin: 16px 0 6px;
  font-size: 13.5px;
  color: var(--brand-cyan-text);
}

.info-modal-card p,
.info-modal-card li {
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--text-muted);
}

.info-modal-card ol,
.info-modal-card ul {
  margin: 4px 0;
  padding-left: 20px;
}

.info-modal-close {
  float: right;
  border: none;
  background: none;
  color: var(--text-faint);
  font-size: 18px;
  cursor: pointer;
  line-height: 1;
}

.info-modal-close:hover {
  color: var(--text);
}

/* 環境守門說明彈窗（任務#154 追加科目）：殼複用上面 .info-modal-*，這裡
   只補「今日判斷」段觸發時的警示紅、跟連到 /funnel 總經儀表板的箭頭
   連結樣式。 */
.info-modal-card p.env-guard-modal-triggered {
  color: var(--danger);
  font-weight: 600;
}

.env-guard-modal-link {
  display: inline-block;
  margin-top: 14px;
  font-size: 12.5px;
  color: var(--brand-cyan-text);
  text-decoration: none;
}

.env-guard-modal-link:hover {
  text-decoration: underline;
}

/* ---------- 個股 AI 深度體檢彈窗（aireview.js，任務新增） ----------
   三入口共用（選股卡／個股頁／持股列）；殼另立 .aireview-* 前綴，不複用
   .info-modal-*（那是純靜態說明彈窗，語意不同，混用日後改版容易互相牽連）。 */

.aireview-overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(var(--scrim-rgb), 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 210;
  animation: fadeIn 150ms var(--ease);
}

.aireview-card {
  position: relative;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(var(--shadow-rgb), 0.5);
  padding: 24px 26px;
  max-width: 620px;
  width: 100%;
  max-height: 82vh;
  overflow-y: auto;
}

.aireview-close {
  position: absolute;
  top: 14px;
  right: 16px;
  border: none;
  background: none;
  color: var(--text-faint);
  font-size: 20px;
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}

.aireview-close:hover {
  color: var(--text);
}

.aireview-header {
  margin-bottom: 14px;
  padding-right: 26px;
}

.aireview-header h3 {
  margin: 0 0 8px;
  font-size: 17px;
  font-weight: 800;
  color: var(--text);
}

.aireview-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.aireview-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.aireview-badge-cached {
  background-color: rgba(var(--down-rgb), 0.12);
  color: var(--down);
  border: 1px solid rgba(var(--down-rgb), 0.3);
}

.aireview-badge-fallback {
  background-color: rgba(var(--watch-rgb), 0.14);
  color: var(--watch-fg);
  border: 1px solid rgba(var(--watch-rgb), 0.3);
}

.aireview-badge-locked {
  background-color: rgba(var(--brand-violet-rgb), 0.14);
  color: var(--aireview-locked-fg);  /* 舉一反三修復 20260728：代幣化（深色值 #c9a0ff 零變化；淺色=--tag-violet） */
  border: 1px solid rgba(var(--brand-violet-rgb), 0.35);
}

.aireview-body {
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--text-muted);
}

.aireview-paragraph {
  margin: 0 0 12px;
  white-space: pre-line;
}

.aireview-paragraph:last-child {
  margin-bottom: 0;
}

.aireview-empty-hint {
  margin: 0;
  color: var(--text-faint);
}

.aireview-personal-block {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.aireview-personal-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--brand-cyan-text);
  margin-bottom: 6px;
}

.aireview-personal-block .aireview-paragraph {
  color: var(--text-muted);
  font-size: 13px;
}

.aireview-disclaimer {
  margin-top: 18px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-faint);
}

.aireview-loading {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px 0;
  font-size: 13.5px;
  color: var(--text-muted);
}

/* 生成中動態進度條（規格 M1）：漸進填充＋流光動畫，暗示系統仍在運作，
   非固定百分比（真實完成時間不可預測，用視覺動態取代精確進度值）。 */
.aireview-progress-bar {
  position: relative;
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background: rgba(var(--surface-tint-rgb), 0.08);
  overflow: hidden;
}

.aireview-progress-fill {
  position: absolute;
  top: 0;
  left: -30%;
  width: 30%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, var(--brand-cyan), transparent);
  animation: aireview-progress-flow 1.6s ease-in-out infinite;
}

@keyframes aireview-progress-flow {
  0% { left: -30%; }
  100% { left: 100%; }
}

.aireview-progress-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.aireview-progress-label {
  animation: fadeIn 300ms var(--ease);
}

/* 結果六段收摺（規格 M4）：預設展開，點標題收合/展開該段落 */
.aireview-section {
  margin-bottom: 12px;
}

.aireview-section:last-child {
  margin-bottom: 0;
}

.aireview-section-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  background: none;
  border: none;
  padding: 4px 0;
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}

.aireview-section-caret {
  display: inline-block;
  transition: transform 150ms var(--ease);
  color: var(--brand-cyan-text);
  font-size: 11px;
}

.aireview-section-collapsed .aireview-section-caret {
  transform: rotate(-90deg);
}

.aireview-section-collapsed .aireview-paragraph {
  display: none;
}

/* 重新產生按鈕（規格 M3） */
.aireview-actions {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
}

.aireview-regen-btn {
  background: transparent;
  color: var(--brand-cyan-text);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.35);
  border-radius: var(--radius-sm);
  padding: 7px 14px;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms var(--ease), border-color 150ms var(--ease);
}

.aireview-regen-btn:hover {
  background: rgba(var(--brand-cyan-rgb), 0.1);
  border-color: var(--brand-cyan);
}

.aireview-error-box {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 6px 0;
  font-size: 13.5px;
  color: var(--text-muted);
}

.aireview-error-box p {
  margin: 0;
  line-height: 1.65;
}

/* ---------- AI 點評「結論置頂＋條列＋語意分色」共用樣式（任務改版）
   個股 AI 深度體檢（aireview.js）與期貨籌碼 AI 點評（futures.js）共用
   這組 class；tone 語意：bull=偏多（紅，台股慣例）/bear=偏空（綠）/
   warn=風險（琥珀）/level=關鍵價位（青金）/neutral=中性（灰）。---------- */

.hl-bull,
.hl-bear,
.hl-warn,
.hl-level,
.hl-neutral {
  font-weight: 800;
  padding: 0 3px;
  border-radius: 4px;
  white-space: nowrap;
}

.hl-bull {
  color: var(--up);
  background-color: rgba(var(--up-rgb), 0.14);
}

.hl-bear {
  color: var(--down);
  background-color: rgba(var(--down-rgb), 0.14);
}

.hl-warn {
  color: var(--watch-fg);
  background-color: rgba(var(--watch-rgb), 0.16);
}

.hl-level {
  color: var(--brand-cyan-text);
  background-color: rgba(var(--brand-cyan-rgb), 0.14);
}

.hl-neutral {
  color: var(--text);
  background-color: rgba(var(--surface-tint-rgb), 0.08);
}

/* ---------- AI「長文正文」文章排版共用樣式（FT-52 M3-8，2026-08-06）----------
   上面那組 `.hl-*` 是**條列型**點評的語意分色（每則一句、0-1 個標記）；長文型
   正文（段標題×散文段落、每段 12-22 個標記）整段全套 chip 會變成一片碎塊，
   讀起來不是文章。M3-7（/market 大盤點評）先在 market.css 驗過分級規則，本波
   /stock 研究報告「🔭 AI 全景研判」接上時**升格成全站共用 class**，落在 `.hl-*`
   隔壁——降級後的數字與 chip 是同一個家族的兩級，放在一起才看得出彼此關係。

   兩條 class 的語意（規則本體是 JS/Jinja 的決定性演算法，見
   `web/static/stock.js renderArticleText()` 與 `report/pdf_engine.py
   _highlight_article()`，兩份實作＋harness 的 Python oracle 逐格對帳）：
     `.ai-article-lede` —— 段首引言：每段第一個 p 的首句自成一塊，左 3px 品牌色
       邊線＋字級放大一級（用 em，跟著各頁自己的正文字級走，不寫死 px）。
     `.ai-article-num`  —— 降級的中性數字：粗體＋等寬數字＋主文字色、**無底色**。
   `.ai-article` 是容器 class（正文區塊本身），只管段落節奏，不管顏色。

   /market 目前仍用 market.css 內的頁面局部版（`.ai-review-lede`／
   `.ai-review-num`，M3-7 落地）——語意與這裡逐條相同，遷移到這組共用 class
   是後續獨立一棒的事（會動到 /market 的線上樣式，不併進本波）。 */
.ai-article p {
  line-height: 1.85;
  margin: 0 0 1.2em;
}

.ai-article p:last-child {
  margin-bottom: 0;
}

.ai-article-lede {
  display: block;
  border-left: 3px solid rgba(var(--brand-cyan-rgb), 0.55);
  padding: 1px 0 1px 12px;
  margin-bottom: 12px;
  font-size: 1.09em;
  line-height: 1.7;
  font-weight: 600;
  color: var(--text);
}

.ai-article-num {
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  white-space: nowrap;
}

/* 長文裡保留下來的 chip 必須能斷行：`.hl-*` 的 `white-space: nowrap` 是為了
   保護條列型裡的短數字（「1,234.5 元」不該被拆兩行），但正文的語意色標記
   常常是十幾個字的判斷句（實例：「價格與籌碼已經轉強，獲利數字還在後面追」），
   nowrap 會把整個卡片撐破——2026-08-06 harness 實測 390 寬時正文區橫向溢出
   61px。降級後的 `.ai-article-num` 仍維持 nowrap：那些是純數字，本來就不該拆。 */
.ai-article .hl-bull,
.ai-article .hl-bear,
.ai-article .hl-warn,
.ai-article .hl-level,
.ai-article .hl-neutral {
  white-space: normal;
}

/* 手機：引言左內距與段距收一點，避免小螢幕被邊線吃掉太多行寬。 */
@media (max-width: 480px) {
  .ai-article-lede {
    padding-left: 10px;
    margin-bottom: 10px;
  }
}

/* 結論卡：永遠置頂、不可收合（規格：結論放最上面） */
.ai-conclusion-card {
  background: rgba(var(--brand-cyan-rgb), 0.05);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.2);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  margin-bottom: 16px;
}

.ai-conclusion-head {
  margin-bottom: 8px;
}

.ai-verdict-badge {
  display: inline-block;
  font-size: 13px;
  font-weight: 800;
  padding: 4px 14px;
  border-radius: 999px;
  white-space: nowrap;
}

.ai-verdict-badge-bull {
  background-color: rgba(var(--up-rgb), 0.16);
  color: var(--up);
  border: 1px solid rgba(var(--up-rgb), 0.4);
}

.ai-verdict-badge-bear {
  background-color: rgba(var(--down-rgb), 0.16);
  color: var(--down);
  border: 1px solid rgba(var(--down-rgb), 0.4);
}

.ai-verdict-badge-warn {
  background-color: rgba(var(--watch-rgb), 0.18);
  color: var(--watch-fg);
  border: 1px solid rgba(var(--watch-rgb), 0.4);
}

.ai-verdict-badge-level {
  background-color: rgba(var(--brand-cyan-rgb), 0.16);
  color: var(--brand-cyan-text);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.4);
}

.ai-verdict-badge-neutral {
  background-color: rgba(var(--surface-tint-rgb), 0.1);
  color: var(--text);
  border: 1px solid var(--border-strong);
}

/* 「未生成結論」徽章（QA R3 P1-5）：verdict 缺席時用**灰階、明顯低調**於
   四種方向徽章的樣式——它不是第五種方向判讀，是「這裡沒有結論」的誠實
   標示，視覺上必須讀起來像 metadata 而不是像一個方向。 */
.ai-verdict-badge-none {
  background-color: rgba(var(--surface-tint-rgb), 0.04);
  color: var(--muted);
  border: 1px dashed var(--border-strong);
  font-weight: 500;
}

.ai-verdict-reason {
  margin: 8px 0 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text);
  font-weight: 600;
}

.ai-data-notice {
  margin: 6px 0 0;
  font-size: 11.5px;
  color: var(--text-faint);
}

.ai-conclusion-card .ai-bullet-list {
  margin-top: 10px;
}

/* bullet 條列：每點左邊色條依 tone 上色 */
.ai-bullet-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ai-bullet {
  position: relative;
  padding: 2px 0 2px 14px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--text-muted);
  border-left: 3px solid var(--border-strong);
}

.ai-bullet-bull {
  border-left-color: var(--up);
}

.ai-bullet-bear {
  border-left-color: var(--down);
}

.ai-bullet-warn {
  border-left-color: var(--watch-fg);
}

.ai-bullet-level {
  border-left-color: var(--brand-cyan);
}

.ai-bullet-neutral {
  border-left-color: var(--border-strong);
}

/* 訊號卡 / 個股頁 / 持股列共用的「AI 體檢」小按鈕 */
.btn-ai-review {
  background: transparent;
  color: var(--brand-cyan-text);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.35);
  border-radius: var(--radius-sm);
  padding: 5px 11px;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms var(--ease), border-color 150ms var(--ease);
}

.btn-ai-review:hover:not(:disabled) {
  background: rgba(var(--brand-cyan-rgb), 0.1);
  border-color: var(--brand-cyan);
}

.btn-ai-review:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.badge {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 700;
  padding: 4px 11px;
  border-radius: 999px;
  white-space: nowrap;
  letter-spacing: 0.02em;
}

.badge-buy { background-color: var(--buy-bg); color: var(--buy-fg); }
.badge-watch { background-color: var(--watch-bg); color: var(--watch-fg); }
.badge-skip { background-color: var(--skip-bg); color: var(--skip-fg); }

.chips {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chip {
  background-color: rgba(var(--text-muted-rgb), 0.1);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 3px 10px;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* 主題 chip（規格 M3，訊號卡命中原因標示）：沿用 .chip 基底樣式，用品牌藍
   色調跟一般規則 chip 略為區隔，讓使用者能分辨「這是所屬主題分類」而非
   「這是命中的選股規則」；有 title 屬性時（該主題確實在使用者篩選中）
   瀏覽器原生 tooltip 即可顯示因果句，不需要額外的 hover JS。 */
.chip-theme {
  background-color: rgba(var(--brand-blue-rgb), 0.1);
  border-color: rgba(var(--brand-blue-rgb), 0.3);
  color: var(--brand-blue);
}

.data-summary {
  margin-top: 10px;
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.55;
}

/* ---------- 訊號卡分數列（規格 M3：sv-ring + sv-sparkline-canvas 並排） ---------- */
.score-row-with-spark {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
}

/* ---------- 分數環下方「總分」小標（規格 P2 M1，任務#74新增） ----------
   使用者原始痛點「圓圈的60跟旁邊的曲線……看不出重點跟什麼意義」，環形
   本身只有一個數字容易誤讀成任意指標，加小標明講「這是總分」。 */
.sv-ring-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.sv-ring-caption {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-faint);
  letter-spacing: 0.02em;
}

/* ---------- 分數等式 + 候選池白話排名兩行（規格 P2 M1，任務#74新增） ----------
   取代舊版單純的 .score-percentile-badge 小徽章：第一行把「公式分＋AI
   複評＝總分」的算式攤開，第二行把百分位換成白話排名句，回應使用者原始
   痛點「看不出重點跟什麼意義，到底好還是壞」。 */
.sv-score-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  font-size: 12px;
}

.sv-score-equation {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}

.sv-eq-term {
  color: var(--text-muted);
  font-weight: 600;
}

.sv-eq-op {
  color: var(--text-faint);
  font-size: 11px;
}

.sv-eq-ai {
  color: var(--brand-blue);
}

.sv-eq-total {
  color: var(--text);
  font-weight: 800;
}

.sv-pr-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  color: var(--text-muted);
  font-size: 11.5px;
  cursor: help;
}

/* 強弱梯隊 chip：中性教育性描述，刻意沿用 sv-ring 的 slate/blue/violet
   三階（不用紅綠——這是分數強度分級，不是行情漲跌，也不是買賣建議）。 */
.sv-pr-tier-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  white-space: nowrap;
  border: 1px solid var(--border);
}

.sv-pr-tier-top {
  color: var(--tag-violet);
  background: rgba(var(--brand-violet-rgb), 0.14);
  border-color: rgba(var(--tag-violet-rgb), 0.35);
}

.sv-pr-tier-upper {
  color: var(--brand-blue);
  background: rgba(var(--brand-blue-rgb), 0.12);
  border-color: rgba(var(--brand-blue-rgb), 0.3);
}

.sv-pr-tier-mid {
  color: var(--text-muted);
  background: rgba(var(--text-muted-rgb), 0.1);
}

.sv-pr-tier-low {
  color: var(--text-faint);
  background: rgba(var(--text-muted-rgb), 0.06);
}

/* ---------- 迷你走勢線外框：標「近N日」+ 尾端漲跌幅（規格 P2 M1） ----------
   紅漲綠跌是這裡少數允許使用紅綠語意的地方——這是真實 5 日價格變動，
   不是分數。 */
.sv-sparkline-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.sv-sparkline-label {
  font-size: 10px;
  color: var(--text-faint);
  font-weight: 600;
}

.sv-sparkline-tail {
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.sv-sparkline-tail.up { color: var(--up); }
.sv-sparkline-tail.down { color: var(--down); }

/* ---------- 未命中規則灰 chip（規格 P2 M2①，任務#74新增） ----------
   沿用 .chip 基底樣式，降低不透明度＋虛線框做「淡色」處理，跟命中的實色
   chip 一眼可辨：「設了 N 條中命中幾條」的全貌。 */
.chip-miss {
  opacity: 0.55;
  border-style: dashed;
  color: var(--text-faint);
}

/* ---------- 四維度橫向迷你 progress bar（規格 P2 M2②，任務#74新增） ----------
   直接畫在卡片上（不藏在評分明細手風琴後面），四條同寬對齊方便橫向比較
   各維度落差；顏色統一用品牌藍，不做紅綠語意。 */
.sv-dim-bars {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.sv-dim-bar-row {
  display: grid;
  grid-template-columns: 52px 1fr 44px;
  align-items: center;
  gap: 8px;
  font-size: 11px;
}

.sv-dim-bar-label {
  color: var(--text-muted);
  white-space: nowrap;
}

.sv-dim-bar-track {
  height: 6px;
  border-radius: 999px;
  background: rgba(var(--text-muted-rgb), 0.14);
  overflow: hidden;
}

.sv-dim-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--brand-cyan), var(--brand-blue));
  transition: width 300ms var(--ease);
}

.sv-dim-bar-value {
  color: var(--text-faint);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------- 🆕 新進榜徽章（規格 P2 M2③，任務#74新增） ---------- */
.sv-new-badge {
  display: inline-block;
  margin-left: 6px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--brand-cyan-text);
  background: rgba(var(--brand-cyan-rgb), 0.12);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.3);
  border-radius: 999px;
  padding: 1px 8px;
  vertical-align: middle;
  white-space: nowrap;
}

/* ---------- 加自選按鈕（規格 P2 M2④，任務#74新增） ----------
   與 .btn-ai-review 並列於卡片底部操作列，用品牌藍區隔（AI 體檢用青色）。 */
.btn-add-watchlist {
  background: transparent;
  color: var(--brand-blue);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.35);
  border-radius: var(--radius-sm);
  padding: 5px 11px;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  margin-left: 8px;
  transition: background 150ms var(--ease), border-color 150ms var(--ease);
}

.btn-add-watchlist:hover:not(:disabled) {
  background: rgba(var(--brand-blue-rgb), 0.1);
  border-color: var(--brand-blue);
}

.btn-add-watchlist:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---------- 上次在榜、本次掉出（規格 P2 M2③，任務#74新增） ----------
   今日訊號區尾的摺疊小節，樣式比照 .score-detail-* 系列的深色卡片語言。 */
.sv-dropped-section {
  margin-top: 16px;
}

/* 「與上次選股比較」摘要行（新手稽核 2026-07-15）：比對結果一律明講，
   含「名單相同」「尚無前次紀錄」，不再整片靜默。 */
.sv-run-compare-note {
  font-size: 12.5px;
  color: var(--text-muted);
  margin-bottom: 8px;
}

.sv-dropped-toggle {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-muted);
  background: none;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  cursor: pointer;
  width: 100%;
  text-align: left;
}

.sv-dropped-toggle:hover {
  color: var(--text);
  border-color: var(--text-muted);
}

.sv-dropped-list {
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.sv-dropped-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  font-size: 12px;
  text-decoration: none;
  border-top: 1px solid var(--border);
  transition: background 150ms var(--ease);
}

.sv-dropped-row:first-child {
  border-top: none;
}

.sv-dropped-row:hover {
  background: var(--card-bg-hover);
}

.sv-dropped-stock {
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
}

.sv-dropped-reason {
  color: var(--text-faint);
  text-align: right;
}

/* ---------- 評分明細展開（規格 M3，免費功能） ----------
   資料源 signals API 的 review_json.score_breakdown；視覺邏輯照抄
   web/templates/report_email.html 既有渲染（四維度小計 + 逐項得分/滿分/
   依據），這裡深色化。 */

.score-detail-toggle {
  display: inline-block;
  margin-left: 8px;
  font-size: 11px;
  font-weight: 700;
  color: var(--brand-cyan-text);
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
  vertical-align: middle;
}

.score-detail-toggle:hover {
  text-decoration: underline;
}

.score-detail-panel {
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.score-detail-empty {
  padding: 10px 12px;
  font-size: 12px;
  color: var(--text-faint);
}

.score-detail-header {
  background: rgba(var(--surface-tint-rgb), 0.04);
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 700;
  padding: 7px 12px;
  letter-spacing: 0.02em;
}

.score-detail-dim {
  padding: 0 12px;
  border-top: 1px solid var(--border);
}

.score-detail-dim-head {
  padding: 8px 0 3px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
}

.score-detail-dim-score {
  color: var(--text-faint);
  font-weight: 400;
}

.score-detail-item {
  padding: 2px 0 6px;
  font-size: 11.5px;
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px;
}

.score-detail-points {
  display: inline-block;
  min-width: 36px;
  font-weight: 700;
}

.score-detail-hit { color: var(--down); }
.score-detail-miss { color: var(--text-faint); }

.score-detail-item-name {
  color: var(--text);
  font-weight: 600;
}

.score-detail-item-value {
  color: var(--text-muted);
}

.score-detail-item-note {
  color: var(--text-faint);
}

.signal-card-actions {
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
}

.advice-box {
  margin-top: 8px;
  font-size: 13px;
  color: var(--brand-cyan-text);
  background-color: var(--accent-bg);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.2);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  line-height: 1.55;
}

/* ---------- HISTORY TABLE ---------- */

.runs-table-wrap {
  overflow-x: auto;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}

table.runs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

table.runs-table th,
table.runs-table td {
  padding: 11px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

table.runs-table th {
  color: var(--text-muted);
  font-weight: 700;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

table.runs-table tbody tr {
  cursor: pointer;
  transition: background 120ms var(--ease);
}

table.runs-table tbody tr:hover {
  background-color: rgba(var(--surface-tint-rgb), 0.03);
}

table.runs-table tbody tr.selected {
  background-color: var(--accent-bg);
}

table.runs-table tbody tr:last-child td {
  border-bottom: none;
}

.status-pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
}

.status-success { background-color: var(--down-bg); color: var(--down); }
.status-running { background-color: var(--watch-bg); color: var(--watch-fg); }
.status-failed { background-color: var(--up-bg); color: var(--up); }
.status-ai_skipped { background-color: var(--skip-bg); color: var(--skip-fg); }
.status-cancelled { background-color: var(--warn-bg); color: var(--warn-fg); }

.history-detail {
  margin-top: 16px;
}

/* ---------- 選股紀錄白話化（規格 B，原「歷史」分頁） ---------- */

.history-intro {
  margin-bottom: 12px;
  font-size: 13px;
  color: var(--text-muted);
}

.run-fail-reason {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-muted);
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

table.runs-table tbody tr.run-row-faded {
  opacity: 0.45;
}

table.runs-table tbody tr.run-detail-row {
  cursor: default;
}

table.runs-table tbody tr.run-detail-row:hover {
  background-color: transparent;
}

.run-detail-cell {
  white-space: normal;
  background-color: rgba(var(--surface-tint-rgb), 0.02);
  padding: 12px 14px !important;
}

.run-signal-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.run-signal-row {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12.5px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  background-color: var(--card-bg);
  border: 1px solid var(--border);
}

.run-signal-id {
  font-weight: 700;
  color: var(--text);
  min-width: 46px;
}

.run-signal-name {
  flex: 1 1 auto;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.run-signal-score {
  color: var(--score-mid);
  min-width: 64px;
}

.run-signal-close {
  min-width: 60px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ---------- SETTINGS FORM（login/register/setup-admin 共用的卡片外觀基底） ---------- */

.settings-form {
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  max-width: 520px;
  box-shadow: var(--shadow-card);
}

/* ---------- SETTINGS TAB：12 欄網格＋明確 span（僅設定分頁使用） ----------
   改用固定 12 欄＋每張卡明確指定 grid-column，取代先前的
   auto-fit + minmax。原因：auto-fit 讓欄數隨視窗寬度浮動，一旦搭配
   grid-column: span 2 的寬卡，CSS Grid 的 sparse auto-placement 演算法
   會把後續卡片塞進寬卡右側不對稱的空隙裡，造成「孤兒卡浮在右側」「另一
   張卡被擠到左下孤立」的失衡排版。固定欄數＋明確 span 讓任何寬度下的
   排列都是可預期、有紀律的網格。 */

.settings-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 20px;
  align-items: start;
  /* sticky 操作列高度預留，避免最後一張卡被遮住 */
  padding-bottom: 76px;
}

.settings-card {
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 22px;
  box-shadow: var(--shadow-card);
}

/* 全寬（選股規則／我的選股策略） */
.settings-card-wide {
  grid-column: span 12;
}

/* 半寬，兩張一排（執行節奏／AI 智能複評） */
.settings-card-half {
  grid-column: span 6;
}

/* 三分之一寬，三張同排等寬（產業篩選／主題群組／通知管道） */
.settings-card-third {
  grid-column: span 4;
}

@media (max-width: 1023px) {
  .settings-card-wide,
  .settings-card-half,
  .settings-card-third {
    grid-column: span 12;
  }
}

.settings-card-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 16px;
}

.settings-card-icon {
  font-size: 15px;
  line-height: 1;
}

.field-group {
  margin-bottom: 16px;
}

.field-group:last-child {
  margin-bottom: 0;
}

.field-group > label.group-label {
  display: block;
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 8px;
  color: var(--text);
}

.field-group-hint {
  font-size: 12px;
  color: var(--text-faint);
  margin-bottom: 8px;
}

/* 緊湊行內排列：label 固定寬度＋輸入框緊接在旁、皆靠左，不撐滿整行；
   窄螢幕（卡片可用寬度不足）時允許換行，避免輸入框把容器撐爆。 */
.field-inline {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 6px 12px;
}

.field-inline > label.group-label {
  margin-bottom: 0;
  flex: 0 0 auto;
  width: 120px;
  font-weight: 600;
  color: var(--text-muted);
}

.field-inline .text-input,
.field-inline .number-input {
  width: 140px;
  min-width: 0;
  flex: none;
}

.field-inline .text-input-password {
  width: 320px;
  max-width: 100%;
  min-width: 0;
  flex: 1 1 auto;
}

.field-inline.field-disabled {
  opacity: 0.45;
}

.radio-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.radio-row label {
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: var(--text-muted);
}

.text-input, .number-input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font-size: 14px;
  background: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text);
  transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease);
}

.text-input-compact {
  width: 140px;
}

.text-input-password {
  width: 320px;
  max-width: 100%;
}

.number-input {
  width: 90px;
}

.text-input::placeholder, .number-input::placeholder {
  color: var(--text-faint);
}

.text-input:focus, .number-input:focus {
  outline: none;
  border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(var(--brand-blue-rgb), 0.18);
}

input[type="checkbox"], input[type="radio"] {
  accent-color: var(--brand-blue);
  width: 15px;
  height: 15px;
}

.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 0;
  font-size: 13px;
  color: var(--text-muted);
}

.toggle-row + .toggle-row {
  border-top: 1px solid var(--border);
}

.save-status {
  margin-top: 10px;
  font-size: 13px;
}

.save-status.ok { color: var(--down); }
.save-status.err { color: var(--up); }

/* ---------- 帳戶：Telegram 推播綁定卡（任務新增） ---------- */

.telegram-bind-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.telegram-bound-status {
  font-size: 13px;
  font-weight: 700;
  color: var(--down);
}

.telegram-bound-status::before {
  content: "\2705 ";
}

.telegram-bind-code {
  align-self: stretch;
  text-align: center;
  font-size: 28px;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--text-strong);
  background: rgba(var(--brand-blue-rgb), 0.1);
  border: 1px dashed var(--brand-blue);
  border-radius: var(--radius-sm);
  padding: 14px 10px;
}

.telegram-deep-link-btn {
  text-decoration: none;
  align-self: stretch;
  justify-content: center;
}

.telegram-steps {
  margin: 0;
  padding-left: 20px;
  font-size: 12.5px;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.telegram-pref-hint {
  color: var(--warn-fg);
}

/* ---------- 設定：底部滿寬 sticky 操作列 ---------- */

.settings-actionbar {
  grid-column: 1 / -1;
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: rgba(var(--surface-scrim-rgb), 0.92);
  backdrop-filter: blur(8px);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 12px 18px;
  /* 案⑥ 血訓：這條列右側緊貼容器邊緣時會被 .feedback-fab 疊住點不到
     （2026-07-12 使用者實測：儲存設定鈕按不到）。用全域 clearance 代幣
     （見 :root --fab-clearance-right）在右側多留白，讓儲存鈕的右緣落在
     浮鈕左緣之外，不是這一頁單獨 hack。 */
  padding-right: calc(18px + var(--fab-clearance-right));
  box-shadow: 0 -4px 20px rgba(var(--shadow-rgb), 0.35);
}

.settings-actionbar-status {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 20px;
}

.settings-actionbar .save-status {
  margin-top: 0;
}

.unsaved-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--watch-fg);
  box-shadow: 0 0 0 3px rgba(var(--watch-rgb), 0.18);
}

.settings-actionbar .btn-save {
  flex: none;
}

/* ==========================================================================
   設定頁選股流程圖（任務#132，2026-07-12新增）
   --------------------------------------------------------------------------
   settings-flow-*：設定分頁頂部可摺疊區，把「執行節奏→全市場→規則掃描→
   至少命中N→環境守門→產業篩選→入選上限→AI複評→今日訊號」九站畫成流程
   圖，每站同時標「目前設定值」與「上次選股實際走位數字」。配色沿用
   .sv-funnel-stage 既有的藍→紫漸層語言（見本檔「透明漏斗色帶條」區塊），
   桌機橫向、375px 以下改直向堆疊（見底部媒體查詢）。
   ========================================================================== */

.settings-flow-section {
  margin-bottom: 20px;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.settings-flow-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 16px 20px;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--text);
  font-size: 14px;
  font-weight: 700;
  text-align: left;
  font-family: inherit;
}

.settings-flow-toggle-caret {
  color: var(--text-muted);
  font-size: 12px;
  transition: transform 160ms var(--ease);
}

.settings-flow-toggle[aria-expanded="false"] .settings-flow-toggle-caret {
  transform: rotate(-90deg);
}

.settings-flow-body {
  padding: 0 20px 20px;
}

.settings-flow-toggle[aria-expanded="false"] + .settings-flow-body {
  display: none;
}

.settings-flow-intro {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0 0 14px;
}

.settings-flow-row {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 14px;
}

.settings-flow-stage {
  flex: 1 1 152px;
  min-width: 132px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  padding: 12px 13px;
}

.settings-flow-stage-title {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 7px;
  white-space: nowrap;
}

.settings-flow-stage-icon {
  font-size: 13px;
  line-height: 1;
}

.settings-flow-stage-setting,
.settings-flow-stage-actual {
  font-size: 11.5px;
  line-height: 1.5;
}

.settings-flow-stage-setting {
  color: var(--text-muted);
  margin-bottom: 3px;
}

.settings-flow-stage-setting b {
  color: var(--brand-cyan-text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.settings-flow-stage-actual {
  color: var(--text-faint);
}

.settings-flow-stage-actual b {
  color: var(--tag-violet);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.settings-flow-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: 15px;
  flex: 0 0 auto;
  padding: 0 1px;
}

/* 九站漸層色：呼應 .sv-funnel-stage 既有的藍→紫語言，起點淺、終點深飽和。 */
.settings-flow-stage-cadence {
  background: rgba(var(--brand-cyan-rgb), 0.05);
  border-color: rgba(var(--brand-cyan-rgb), 0.18);
}
.settings-flow-stage-universe {
  background: rgba(var(--brand-cyan-rgb), 0.08);
  border-color: rgba(var(--brand-cyan-rgb), 0.22);
}
.settings-flow-stage-rules {
  background: rgba(var(--brand-blue-rgb), 0.1);
  border-color: rgba(var(--brand-blue-rgb), 0.28);
}
.settings-flow-stage-min_hit {
  background: rgba(var(--brand-blue-rgb), 0.12);
  border-color: rgba(var(--brand-blue-rgb), 0.3);
}
.settings-flow-stage-env_guard {
  background: rgba(var(--funnel-ramp-1-rgb), 0.13);
  border-color: rgba(var(--funnel-ramp-1-rgb), 0.34);
}
.settings-flow-stage-industry {
  background: rgba(var(--funnel-ramp-2-rgb), 0.15);
  border-color: rgba(var(--funnel-ramp-2-rgb), 0.38);
}
.settings-flow-stage-candidate_limit {
  background: rgba(var(--funnel-ramp-3-rgb), 0.16);
  border-color: rgba(var(--funnel-ramp-3-rgb), 0.4);
}
.settings-flow-stage-ai_review {
  background: rgba(var(--brand-violet-rgb), 0.16);
  border-color: rgba(var(--brand-violet-rgb), 0.42);
}
.settings-flow-stage-final {
  background: rgba(var(--brand-violet-rgb), 0.2);
  border-color: rgba(var(--brand-violet-rgb), 0.48);
}
.settings-flow-stage-final .settings-flow-stage-title {
  color: var(--tag-violet);
}

.settings-flow-evidence {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 11px 13px;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong);
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.6;
}

.settings-flow-evidence-icon {
  flex: none;
  font-size: 14px;
}

.settings-flow-evidence a {
  color: var(--brand-cyan-text);
  text-decoration: none;
}

.settings-flow-evidence a:hover,
.settings-flow-evidence a:focus-visible {
  text-decoration: underline;
}

@media (max-width: 480px) {
  .settings-flow-row {
    flex-direction: column;
  }
  .settings-flow-stage {
    flex-basis: auto;
    width: 100%;
  }
  .settings-flow-arrow {
    transform: rotate(90deg);
    padding: 3px 0;
  }
}

/* ==========================================================================
   AI 智選配置顧問（O棒 M3，計畫正本 docs/strategy_advisor_plan_20260715.md）
   --------------------------------------------------------------------------
   advisor-*：設定分頁 settings-form **之外**的獨立卡片區塊（卡片自帶套用
   鈕，避免跟表單 submit 邏輯糾纏）。可收折面板（全原型排行榜／產生流程）
   沿用既有 .settings-flow-toggle/.settings-flow-body 摺疊機制與外觀，不
   重造一套。穩健度標籤沿用既有「AI 分數三階」中性色語言
   （--score-high/mid/low）——鐵律「禁紅綠語意色（紅綠只用於漲跌）」，
   不可用 --up/--down。 ========================================================================== */

.advisor-section {
  margin-bottom: 20px;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 20px 22px;
}

.advisor-inner .settings-card-title {
  margin: 0 0 10px;
}

.advisor-summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

/* 膠囊時間戳（FT-52 M3-10，站長 2026-08-06 22:38：「頂部兩顆膠囊時間戳…
   半透明底＋細邊框膠囊」）。原本只有實色 tint 底、沒有邊框，在淺色主題上
   幾乎看不出是一顆膠囊；加一圈低 alpha 細邊框＋內距放大半階，與漏斗上方的
   3D 碗才是同一個材質語言。此 class 也用在 /advisor 頁的同款摘要 chip
   （同一個元件的兩個使用處，統一升級）。 */
.advisor-summary-chip {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--accent-bg);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  color: var(--brand-cyan-text);
  font-size: 11.5px;
  font-weight: 600;
}

.advisor-summary-chip.is-fallback {
  background: var(--warn-bg);
  color: var(--warn-fg);
}

.advisor-fallback-note {
  padding: 10px 13px;
  margin-bottom: 16px;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--warn-border);
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: 12.5px;
  line-height: 1.6;
}

.advisor-candidates-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
  margin-bottom: 20px;
}

.advisor-candidate-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.advisor-card-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.advisor-card-title {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
  flex: 1 1 auto;
}

.advisor-robustness-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.advisor-robustness-high { background: rgba(var(--score-high-rgb), 0.14); color: var(--score-high); }
.advisor-robustness-mid { background: var(--watch-bg); color: var(--score-mid); }
.advisor-robustness-low { background: var(--skip-bg); color: var(--score-low); }

.advisor-current-match-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--skip-bg);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.advisor-card-rationale {
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.65;
  margin: 0;
}

.advisor-card-watchout {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

.advisor-card-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-2);
}

.advisor-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.advisor-stat-label {
  font-size: 10.5px;
  color: var(--text-faint);
}

.advisor-stat-value {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.advisor-card-picks-title {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.advisor-picks-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.advisor-pick-chip {
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.advisor-card-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: auto;
  padding-top: 4px;
}

.advisor-subsection-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 10px;
}

.advisor-evidence-wrap {
  margin-bottom: 16px;
}

.advisor-table-scroll {
  overflow-x: auto;
}

.advisor-evidence-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  white-space: nowrap;
}

.advisor-evidence-table th,
.advisor-evidence-table td {
  padding: 8px 10px;
  text-align: right;
  border-bottom: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}

.advisor-evidence-table th {
  color: var(--text-muted);
  font-weight: 700;
  text-align: right;
}

.advisor-evidence-table th:first-child,
.advisor-evidence-table td.advisor-evidence-row-label {
  text-align: left;
  color: var(--text-muted);
  font-variant-numeric: normal;
}

.advisor-evidence-window-note {
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.6;
}

.advisor-ranking-section,
.advisor-transparency-section {
  margin-bottom: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.advisor-ranking-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.advisor-ranking-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 11.5px;
  color: var(--text-muted);
}

.advisor-ranking-row.is-selected {
  background: var(--accent-bg);
  color: var(--text);
}

.advisor-ranking-rank {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.advisor-ranking-name {
  font-weight: 700;
  color: var(--text);
}

.advisor-selected-badge {
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent-bg);
  color: var(--brand-cyan-text);
  font-size: 10.5px;
  font-weight: 700;
}

.advisor-ranking-stat {
  font-variant-numeric: tabular-nums;
}

.advisor-ranking-reason {
  flex-basis: 100%;
  color: var(--text-faint);
  font-size: 11px;
}

.advisor-transparency-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.advisor-step-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--brand-cyan-text);
  margin: 0 0 6px;
}

.advisor-step-list {
  margin: 6px 0;
  padding-left: 18px;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.7;
}

.advisor-step-note {
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.6;
  margin: 4px 0 0;
}

.advisor-step2-list,
.advisor-step3-block,
.advisor-step4-block {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.advisor-step2-row {
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.6;
}

.advisor-step2-row.is-selected {
  background: var(--accent-bg);
  color: var(--text);
}

.advisor-step2-name {
  font-weight: 700;
  color: var(--text);
  display: block;
}

.advisor-step3-block,
.advisor-step4-block {
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin-bottom: 4px;
}

.advisor-step3-name {
  font-weight: 700;
  color: var(--text);
}

.advisor-disclaimer {
  padding: 10px 13px;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong);
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.6;
}

@media (max-width: 640px) {
  .advisor-candidates-grid {
    grid-template-columns: 1fr;
  }
  .advisor-card-stats {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---------- 帳戶 tab：帳戶資訊／變更密碼／訂閱方案／通知訂閱 ----------
   採獨立三欄（每欄自己的 flex 直向容器），不用單一 grid 讓 4 張卡自由
   auto-placement。原因：帳戶資訊卡矮、通知訂閱卡要接在它正下方，若和
   「設定」分頁一樣共用一個 auto-placement grid，帳戶資訊所在的 row track
   高度會被同排最高的變更密碼卡撐開，導致帳戶資訊卡底部與通知訂閱卡之間
   出現一大片不相關的空白（實測約 170px 高的幽靈區塊）。改成「每欄各自
   累加高度」的 flex column，此問題不會發生。 */

.account-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  align-items: start;
}

.account-col {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

@media (max-width: 1023px) {
  .account-grid {
    grid-template-columns: 1fr;
  }
}

.account-info-value {
  font-size: 13px;
  color: var(--text);
  font-weight: 600;
}

.change-password-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.change-password-form .btn-save {
  align-self: flex-start;
}

/* ---------- 產業 / 主題篩選（checkbox 群） ---------- */

.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  max-height: 180px;
  overflow-y: auto;
  padding: 4px 2px;
}

.checkbox-group label {
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  white-space: nowrap;
  color: var(--text-muted);
}

.checkbox-group .subgroup-title {
  width: 100%;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  margin-top: 6px;
}

/* 「（已儲存）」標記：已儲存但不在目前動態清單中的產業/主題，聯集防護
   仍要照樣渲染出來，這裡加一個次要色小字提示，避免使用者誤以為是資料
   異常（見 app.js renderCheckboxGroup 的說明）。 */
.checkbox-saved-hint {
  font-size: 11px;
  color: var(--text-faint);
}

/* ---------- 設定頁：選股規則勾選與參數 ---------- */

.rules-config-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* 規則分類籤（規格 P1.5 M3，任務#76新增）：技術/籌碼/基本/消息環境/AI獨家，
   沿用 .tab-btn 的視覺語言但獨立命名，避免與頂層頁籤互相牽動樣式。 */
.rules-category-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 2px;
}

.rules-category-tab-btn {
  background: none;
  border: none;
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: 8px 8px 0 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color 150ms var(--ease), border-color 150ms var(--ease), background 150ms var(--ease);
}

.rules-category-tab-btn:hover {
  color: var(--text);
  background: rgba(var(--surface-tint-rgb), 0.03);
}

.rules-category-tab-btn.active {
  color: var(--text-strong);
  border-bottom-color: var(--brand-cyan);
}

.rules-category-panel {
  display: none;
}

.rules-category-panel.active {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 10px;
  align-items: start;
}

/* AI獨家：灰卡「即將推出」佔位，非互動元件（無 checkbox），視覺上明確
   與可勾選的規則卡區分。 */
.rule-ai-exclusive-card {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 14px 15px;
  background: rgba(var(--surface-tint-rgb), 0.015);
  opacity: 0.7;
  position: relative;
}

.rule-ai-exclusive-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
  background: rgba(var(--surface-tint-rgb), 0.06);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 2px 9px;
  margin-bottom: 6px;
}

/* 環境守門切換列（規格 P1.5，任務#76新增）：與一般 .rule-row 外觀一致，
   但無 data-rule/enabled 語意（收集邏輯獨立於 collectRulesConfig，見
   app.js collectEnvGuard()），視覺上稍作區分（左側色條）供使用者辨識這是
   管線層開關而非一般規則。 */
.env-guard-row {
  border-left: 3px solid var(--brand-cyan);
}

/* 教室深連結（沿用 web/static/learn_links.js 的 .sv-learn-link 基底樣式，
   這裡補設定頁專屬的排版位置——inline 顯示在說明文字後方）。 */
.rule-row-learn-link {
  display: inline-block;
  margin-left: 6px;
  font-size: 11.5px;
  color: var(--brand-cyan-text);
  text-decoration: none;
}

.rule-row-learn-link:hover {
  text-decoration: underline;
}

/* pattern_signal 型態子集多選（規格 P1.5 M3，任務#76新增）。 */
.rule-pattern-checkboxes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 10px;
  padding-left: 24px;
}

.rule-pattern-checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text-muted);
  cursor: pointer;
}

.rule-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  background: rgba(var(--surface-tint-rgb), 0.02);
  transition: border-color 150ms var(--ease);
}

.rule-row:hover {
  border-color: var(--border-strong);
}

.rule-row-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  cursor: pointer;
}

.rule-row-head input[type="checkbox"] {
  margin-top: 3px;
}

.rule-row-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

.rule-row-desc {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

.rule-row-params {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  margin-top: 10px;
  padding-left: 24px;
}

.rule-param-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-muted);
}

.rule-param-field input {
  width: 90px;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 13px;
  background: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text);
}

.rule-min-hit-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-muted);
}

.rule-min-hit-row input {
  width: 80px;
}

/* ---------- 今日訊號：快速產業/主題下拉 ---------- */

.quick-filter-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.quick-filter-bar select,
select {
  padding: 7px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font-size: 13px;
  background-color: var(--card-bg);
  color: var(--text);
  max-width: 100%;
  box-sizing: border-box;
}

select:focus {
  outline: none;
  border-color: var(--brand-blue);
}

/* 檢視模式切換（完整/精簡）的 .advisor-view-toggle / .advisor-view-btn 樣式
   已於 FT-52 M3-12 第三輪（2026-08-07）隨控制項一起移除——緊湊卡成為唯一
   版式後，「完整」模式等於「已展開」，切換器本身沒有語意了。不留孤兒樣式。 */

.industry-badge {
  background-color: rgba(var(--brand-blue-rgb), 0.12);
  color: var(--brand-blue);
  border-radius: 999px;
  padding: 4px 11px;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}

/* 產業 badge + 主題 chips 並排容器（規格 M3）：靠右對齊、允許換行，避免
   一檔股票同時屬於多個主題時把卡片撐爆。 */
.industry-theme-group {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-end;
  align-items: center;
}

/* ---------- FOOTER ---------- */

footer {
  padding: 18px 16px;
  text-align: center;
  font-size: 11px;
  color: var(--text-faint);
  line-height: 1.6;
  border-top: 1px solid var(--border);
  background-color: rgba(var(--surface-scrim-rgb), 0.6);
}

/* ---------- 會員系統：nav 使用者資訊 / 分級鎖定 / 管理後台 ---------- */

.nav-user {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-size: 12px;
  color: var(--nav-sub);
  min-width: 0;
}

/* 帳號 email 顯示（2026-07-10 累犯根治：頂欄是全站共用元件，修在 app.css
   全域層，不做單頁修補）——舊版 max-width:180px 在桌機也把正常長度帳號
   （如 30+ 字元的 worker71-test@example.com）截斷成
   「worker71-test@example.…」看不出完整帳號。桌機/平板不設寬度上限，
   讓 .nav-user-menu／.nav-actions 既有的 flex-wrap 換行策略去處理版面，
   完整顯示不截斷；title 屬性（見 nav.js renderNavUser()）當保底，任何
   情境 hover／長按都看得到完整帳號。 */
#nav-user-email {
  max-width: none;
  overflow: visible;
  white-space: nowrap;
}

/* 窄螢幕（<520px）：空間有限，先降一階字級撐住不截斷；仍放不下才啟用
   省略號截斷（title 保底看完整帳號）。 */
@media (max-width: 520px) {
  #nav-user-email {
    font-size: 11px;
    max-width: 42vw;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* tier 徽章基底。
   ⚠ 2026-08-19 位置搬移（原本在下方 max-width:480px 那段**之後**）：兩者
   同為 (0,1,0) 特異度、媒體查詢不加權重，所以窄幕那段的 `padding: 3px 7px`
   從寫下的第一天起就被這條基底規則蓋掉、從未生效（實測 360px 徽章仍是
   左右各 10px 內距）。搬到窄幕段之前後，基底照舊管 >480px，窄幕覆蓋才真的
   會贏。同型的來源順序失效在 `.nav` 內距上也有一份，已在 NAV 區段一併修正。 */
.tier-badge {
  background: rgba(var(--surface-tint-rgb), 0.08);
  color: var(--nav-fg);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.tier-badge.tier-pro,
.tier-badge.tier-admin {
  background: var(--brand-gradient-soft);
  border-color: rgba(var(--brand-cyan-rgb), 0.35);
  /* 站長 2026-07-28 21:25 手機驗收抓包：淡青字疊淺色軟漸層底＝隱形。
     收齊 --on-brand-soft（深色值逐字＝原 #baf0ff 零變化，淺色各主題深字）。 */
  color: var(--on-brand-soft);
}

/* 極窄手機（≈480px 以下）：email 屬次要資訊，先讓路給 tier badge／登出／
   立即選股這些操作按鈕，避免 nav-actions 被撐成 3 行（超過二行上限）。
   這是排列策略切換，不是像素斷點式格線，門檻以下規則連續適用。

   ── 2026-08-19 窄機 nav 重疊修復的右側收斂（站長 09:38 手機截圖）──
   幾何（改動前實測，三寬完全相同，因為右側每一項都是 nowrap 固定寬）：
     nav 內距 14×2 = 28（那時 480 段的 10px 沒生效，見上方 .nav 註解）
     品牌區 .logo-wrap 需求寬 126（svg 34 ＋ gap 8 ＋ 品牌欄保底 84）
     .nav-actions 需求寬 250.4 ＝ 調色盤 30 ＋10＋ 鈴鐺 34 ＋10＋ 使用者膠囊
       166.4（label 內距 12×2 ＋ 徽章 129.7 ＋ gap 5 ＋ 箭頭 7.7）
     漢堡 44、容器間距 10×2
     合計需求 468.4px → 360 機溢出 108.4、390 溢出 78.4、412 溢出 56.4
   這些溢出量在改動前**全部由品牌區獨自吸收**（實測 .logo-wrap 只拿到
   17.6/47.6/69.6px），內容溢出框外壓在右側元件上＝站長看到的重疊。

   修法分兩層：①上游把保底寬還給 flex item（見 max-width:899px 段的
   .nav .logo-wrap min-width:min-content），讓「擠不下」只會換行不會蓋字；
   ②本段把右側收斂到三個目標寬仍是一排：
     徽章分階降級 129.7 → 74.8（隱藏「體驗・剩」，見 .tier-badge-trial）
     徽章內距 10 → 7（上面那條搬移後才真的生效）
     使用者膠囊 label 內距 12 → 4、下拉箭頭隱藏（整片膠囊仍可點）
     .nav-actions 內部間距 10 → 6、鈴鐺 34 → 30
   收斂後 .nav-actions ≈ 154.8，一排需求 ≈ 20＋126＋10＋154.8＋10＋44
   ＝ 364.8px：412 餘 47、390 餘 25、375 餘 10 都是一排；360 由再下一段
   （max-width:374px）把「183 天」也收掉補上最後 36px。 */
@media (max-width: 480px) {
  #nav-user-email {
    display: none;
  }

  /* 品牌保底寬（.logo-wrap > div min-width:84px）需要的騰挪空間：窄幕把
     右側最肥的使用者膠囊與各層間距各收一階。 */
  .nav {
    gap: 8px 10px;
    padding-left: 10px;
    padding-right: 10px;
  }

  .nav-user-menu {
    margin-left: 0;
  }

  /* 使用者膠囊：本身就是整片可點的下拉觸發區，窄幕把左右內距從 12 收到 4
     （2026-08-19；點擊行為由 nav.js 綁在 .nav-group-label 上，不受影響）。 */
  .nav-user-label {
    gap: 5px;
    padding-left: 4px;
    padding-right: 4px;
  }

  .tier-badge {
    padding: 3px 7px;
    letter-spacing: 0.02em;
  }

  /* 「體驗・剩」是修飾語，藏掉之後「PRO 183 天」語意仍完整（且 title 屬性
     帶完整標籤＋到期時間，帳戶頁權益區塊另有完整說明）。段落切分在
     nav.js renderNavUser() 的 active_trial 分支。 */
  .tier-badge-trial {
    display: none;
  }

  /* 膠囊已經整片可點，窄幕不需要再畫一個 7.7px 的箭頭來暗示。 */
  .nav-user-label .nav-group-caret {
    display: none;
  }

  .nav-actions {
    gap: 8px 6px;
  }

  /* 兩顆圖示鈕的尺寸由 nav.js 自我注入的 <style> 定義（那段在 <head> 的
     app.css 之後，同特異度會贏），所以這裡必須用 (0,2,0) 的後代選擇器
     才蓋得過去——寫成裸 .sv-announce-bell 會靜默無效。 */
  .nav .sv-announce-bell {
    width: 30px;
    height: 30px;
  }
}

/* 窄幕右簇收斂（<=430px，2026-08-21 18:11 站長截圖後新增）：430 這個數字取
   iPhone 14/15 Pro Max 的邏輯寬——從它以下，右簇每多一顆圖示鈕就直接吃掉品牌
   欄的可用寬。上一段（480px）已經收過一輪間距，這一段再收一階，目的是把省下
   來的像素還給品牌字，讓「台股AI解盤」在 375/360 不必被 ellipsis 截尾。

   四項各自省下的量（390px 實測）：圖示鈕 34→30 三顆共 12px、.nav-actions 欄距
   6→4 共 6px、.nav 欄距 10→8 共 4px、使用者膠囊內距與 tier 徽章內距共約 8px。 */
@media (max-width: 430px) {
  .nav {
    gap: 8px 8px;
  }

  .nav-actions {
    gap: 8px 4px;
  }

  /* 三顆圖示鈕的尺寸都由 nav.js 自我注入的 <style> 定義（那段在 <head> 的
     app.css 之後，同特異度會贏），所以這裡必須用 (0,2,0) 的後代選擇器才蓋得
     過去——寫成裸 .sv-announce-bell 會靜默無效（同 480px 段的既有註解）。 */
  .nav .sv-announce-bell,
  .nav .sv-nav-pf-shortcut,
  .nav .sv-theme-toggle {
    width: 30px;
    height: 30px;
  }

  .tier-badge {
    padding: 3px 5px;
  }

  .nav-user-label {
    gap: 4px;
    padding-left: 2px;
    padding-right: 2px;
  }

  /* 品牌字標「AI」的窄機補償**已於 2026-08-22 二輪移除**。
     首版在這裡把中文字級收成 18px、字距歸零，為的是騰出「AI」放大要吃的
     8.7px。二輪實測推翻了那個前提：品牌欄的實得寬在 320–430 全部是 130px
     （由副標「Signova AI・台股智慧選股」撐出來，不是被右簇擠出來的），
     主字放大後只要 116px，餘裕還有 14px——根本不需要縮中文字。
     而縮中文字有代價：字級一變，`--sv-brand-zh-offset`（3.09em）換算出來的
     px 位移就跟改版前對不上，中文字色會在窄機再度偏掉（站長 12:51 明令
     「五個主題全部維持原本標題色」）。所以這一段整個拿掉，窄機的中文字
     逐 px 等於改版前。 */

  /* 徽章天數的降級門檻由 374 → 430：PRO 體驗帳號在 <=480 顯示的是「PRO 183 天」
     （.tier-badge-trial 已隱藏、.tier-badge-days 還在），比 ADMIN 寬約 30px，
     375px 實測就是它把品牌字擠成「台股AI…」。「剩 N 天」在徽章 title、帳戶頁
     權益區塊、到期前的雙段提醒信都拿得到，這裡收掉不損失資訊（理由與下方 374
     段原本寫的完全相同，只是門檻跟著本次的新斷點對齊）。 */
  .tier-badge-days {
    display: none;
  }

  /* 調色盤收進漢堡選單（站長 18:11 的第三階：「若 390px 開快捷＋ADMIN 膠囊
     仍溢出→該寬度下把 🎨 收進漢堡」）。實測 375/360 在只做前兩階時 header 已經
     是單列，但品牌字被截成「台股AI…」（375 得 89/103、360 得 74/103），而站長
     一貫不接受品牌字被截——收掉這顆 34px 的鈕正好把差額補回來。
     搬移由 nav.js `syncThemeTogglePlacement()` 做（真的把同一顆 DOM 搬進
     .nav-links，不是複製一份），這裡只負責「搬進去之後長什麼樣」。 */
  .nav-links .sv-theme-nav-row {
    display: flex;
  }
}

/* 小型手機（<=374px：iPhone SE 一代/mini 之下、360px Android 主流機）：
   上一段收斂後一排仍差約 36px（實測 360 機需求 364.8 > 可用 360），
   把徽章的天數也收掉＝再省 36.3px。留下的「PRO」是這顆徽章真正要傳達的
   狀態；「剩 N 天」在 title、帳戶頁權益區塊、到期前的雙段提醒信都拿得到。 */
@media (max-width: 374px) {
  .tier-badge-days {
    display: none;
  }
}

/* 使用者選單下拉內的登出按鈕：外觀比照選單裡的其他連結（.nav-link），
   維持 id="btn-logout" 供既有各頁 JS 綁定 click 監聽不用改動。 */
.btn-logout {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--nav-sub);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: color 150ms var(--ease), background 150ms var(--ease);
}

.btn-logout:hover {
  color: var(--up);
  background: rgba(var(--up-rgb), 0.1);
}

.pro-locked-box {
  background-color: rgba(var(--surface-tint-rgb), 0.03);
  border: 1px dashed var(--border-strong);
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: 13px;
  margin-top: 8px;
}

.readonly-notice {
  background-color: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-fg);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}

.admin-stats {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.admin-stats .stat-box {
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 20px;
  font-size: 13px;
  color: var(--text-muted);
  box-shadow: var(--shadow-card);
}

.admin-stats .stat-box b {
  display: block;
  font-size: 22px;
  color: var(--text);
  font-weight: 800;
}

.admin-users-table {
  width: 100%;
  border-collapse: collapse;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  font-size: 13px;
  box-shadow: var(--shadow-card);
}

.admin-users-table th, .admin-users-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  text-align: left;
}

.admin-users-table th {
  color: var(--text-muted);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.admin-users-table select {
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: var(--bg-2);
  color: var(--text);
}

/* ---------- 管理台：意見回饋分頁（admin.js，任務新增） ----------
   表格外觀沿用 .admin-users-table（同一頁、同一套視覺語言）；這裡只補
   標題間距／篩選列／展開列的特有樣式。 */
.admin-section-title {
  margin: 24px 0 12px;
}

.admin-feedback-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.admin-feedback-detail-row td {
  background: rgba(var(--surface-tint-rgb), 0.02);
}

.admin-feedback-detail {
  padding: 10px 4px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.admin-feedback-detail-content {
  font-size: 13px;
  line-height: 1.7;
  color: var(--text);
  white-space: pre-wrap;
}

/* ---------- 自選股 ---------- */

.watchlist-add-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  max-width: 480px;
  flex-wrap: wrap;
}

/* 代號/股名輸入框的定位容器（2026-08-22）：建議下拉 .watchlist-suggest 是
   absolute，錨點必須是**輸入框本身**而不是整個 .watchlist-add-bar——這一列
   在手機寬度會換行，錨在 form 上會讓清單飄到備註列底下去。
   `flex: 1 1 200px` + `min-width: 0`：有空間時和備註框一起佔滿一列，空間
   不夠時整格換行（見下方 480px 斷點），永遠不會被壓成一條看不到字的縫。 */
.watchlist-add-field {
  position: relative;
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
}

.watchlist-add-bar input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font-size: 14px;
  background: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text);
}

/* 備註框：比代號框窄一階（`flex: 1 1 140px`），兩者同列時代號框優先拿到
   剩餘空間——使用者打的是股名，那一格才是需要看得見全文的。 */
.watchlist-add-bar > input {
  flex: 1 1 140px;
}

.watchlist-add-bar .btn-primary {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* 手機（≤480px）：代號/股名框獨佔第一列，備註＋按鈕併第二列。
   為什麼要明寫這個斷點而不是靠 flex-wrap 自己跑：320px 寬時三個元件的
   最小寬總和必然超過容器，自動換行的落點會隨「按鈕文字有多寬」浮動
   （字級放大 1.3x 時尤其明顯），實測會出現「代號框和備註框擠在同一列各剩
   一半、按鈕自己一列」這種最難用的排法。固定成兩列是內容驅動的規則，不是
   機型客製。 */
@media (max-width: 480px) {
  .watchlist-add-field {
    flex: 1 1 100%;
  }
  .watchlist-add-bar > input {
    flex: 1 1 120px;
  }
}

.watchlist-add-bar input:focus {
  outline: none;
  border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(var(--brand-blue-rgb), 0.18);
}

/* ---------- 自選股輸入框的「代號或股名」建議下拉（2026-08-22） ----------
   封測者 vicky 回報「打台積電加不進來」。視覺刻意與個股頁查詢框的建議清單
   一致（同樣的卡片底、細框、8px 圓角、hover 高亮），但**用不同的 class 名**
   （.watchlist-suggest vs 個股頁的 .search-suggest）：個股頁那份是就地寫在
   web/templates/stock.html 的頁內 <style>，把同名 class 提升進 app.css 會讓
   個股頁憑空多一份來源不明的全域覆寫、日後改一邊壞另一邊。兩份各自獨立，
   真正共用的是資料層（同一支 /api/v1/search/stocks）。 */
.watchlist-suggest {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  width: 100%;
  max-height: 320px;
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 24px rgba(var(--shadow-rgb), 0.35);
  z-index: 30;
}

.watchlist-suggest-item {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 9px 12px;
  cursor: pointer;
  font-size: 14px;
  border-bottom: 1px solid var(--border);
}

.watchlist-suggest-item:last-child {
  border-bottom: none;
}

.watchlist-suggest-item:hover,
.watchlist-suggest-item.is-active {
  background: var(--accent-bg);
}

.watchlist-suggest-name {
  color: var(--text);
  font-weight: 700;
  /* 極長 ETF 全名（庫內最長「凱基ESG BBB債15+」）寧可斷字也不橫向溢出 */
  overflow-wrap: anywhere;
  min-width: 0;
}

.watchlist-suggest-id {
  color: var(--text-faint);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}

.watchlist-table-wrap {
  overflow-x: auto;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}

table.watchlist-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

table.watchlist-table th,
table.watchlist-table td {
  padding: 11px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

table.watchlist-table th {
  color: var(--text-muted);
  font-weight: 700;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

table.watchlist-table tbody tr:last-child td {
  border-bottom: none;
}

table.watchlist-table tbody tr:hover {
  background-color: rgba(var(--surface-tint-rgb), 0.03);
}

/* ---------- 自選股密集看盤網格（Fugle 風格） ---------- */

.watch-grid {
  display: grid;
  /* auto-fill（非 auto-fit）：格線軌道數固定由容器寬度／230px 決定，即使
     磚數量不足以填滿一整排，多出的軌道會維持空白而不是被僅有的磚均分
     拉滿——這是「只有一檔自選股時磚被拉成全寬」的根本修法（規格 A1）。
     auto-fit 會把空軌道折疊、讓僅有的內容軌道吃下所有剩餘空間；
     auto-fill 保留空軌道，磚寬維持在 minmax 上限附近。 */
  /* 230px → **260px**（2026-08-22 補股名時的版面根治）：230px 的軌道在 1280
     桌面會排成 5 欄、每格只有 232px，扣掉內距與右邊固定 130px 的迷你圖之後
     留給文字的只剩 60px——放不下「2,410.00」這種不可斷開的價格字串，數字會
     溢出去疊在圖上（實測截圖）。260px 讓桌面排成 4 欄、每格約 302px，文字欄
     拿回 130px。auto-fill（非 auto-fit）的既有語意一字未動，見下方原註解。 */
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 12px;
}

.watch-tile {
  position: relative;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  box-shadow: var(--shadow-card);
  cursor: pointer;
  transition: transform 150ms var(--ease), border-color 150ms var(--ease), box-shadow 150ms var(--ease);
  animation: fadeIn 200ms var(--ease);
}

.watch-tile-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.watch-tile-info {
  flex: 1 1 auto;
  /* min-width 從 0 改成 118px（2026-08-22）：這一欄裝的是價格，而價格是一
     串**不可斷開**的字元（「2,410.00」約 110px）。min-width:0 等於告訴
     flexbox「這一欄要多窄都行」，於是欄寬被壓到 60px、數字整串溢出去疊在
     右邊的迷你圖上（實測截圖）。給足最小寬之後，擠壓壓力改由下面那張圖
     吸收（見 .mini-chart-canvas 的 flex 設定），數字永遠有地方站。 */
  min-width: 118px;
}

/* 自選磚的價格列一律直排（2026-08-22）：手機斷點裡早就有一條一模一樣的規則
   （見本檔 @media 內「2026-08-06 跑版根治其之三」），而它的理由**逐字適用於
   自選磚的每一個寬度**——磚的文字欄無論視窗多寬都只有 130px 上下（右邊那張
   迷你圖是固定欄），並排版的價格列寬度需求卻會隨「這檔今天漲多少」浮動
   （實測「2,410.00」＋「+35.00  +1.47%」在桌面 1280 直接溢出去疊在圖上）。
   改直排後這一區的寬度需求＝三行裡最寬的那一行，與字串長度徹底脫鉤，同一
   組磚在任何行情、任何寬度下都是同一個版型。
   特異度 0,2,0 蓋過全域的 .price-head（0,1,0）；手機斷點那條設的是同樣的
   值，兩者不衝突。 */
.watch-tile .price-head {
  grid-template-columns: minmax(0, 1fr);
}

.watch-tile .price-change {
  grid-row: 2;
  grid-column: 1;
}

.watch-tile .price-head .card-quote-time {
  grid-row: 3;
}

.watch-tile:hover,
.watch-tile:focus-visible {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(var(--shadow-rgb), 0.3), 0 14px 32px rgba(var(--shadow-rgb), 0.35);
  outline: none;
}

/* 卡頭獨佔一整列（2026-08-22 補股名時的版面根治，DOM 改動見 app.js
   renderWatchlistTile()）：卡頭原本和右邊那張固定 130px 的迷你圖同在
   .watch-tile-body 這一列裡搶寬度，桌面 grid 一格 232px 扣完只剩 40px 給
   股名，補上股名之後就變成「GOG／OLO／OK」逐字斷行。搬出來之後股名列拿得
   到磚的完整內容寬。
   padding-right:20px 是留給右上角 ✕ 移除鈕的位置（絕對定位，不佔流），
   這一格從卡頭在 body 裡的時候就存在，語意不變。 */
.watch-tile-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  padding-right: 20px;
  margin-bottom: 10px;
  /* 卡頭現在是磚的直接子元素（flex 之外的一般區塊），寬度＝磚的內容寬；
     min-width:0 保留給未來若有人把它放回 flex 容器裡的情況。 */
  min-width: 0;
}

.watch-tile-head > div {
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* min-width:0：讓這一欄在 grid 磚變窄時可以收縮，長股名才折得下去而不是
     把整張磚撐爆（沒有它時 flex item 的最小尺寸是內容寬度 = 溢出來源）。
     align-items:flex-start 讓產業徽章不被 stretch 拉成整列寬。 */
  min-width: 0;
  align-items: flex-start;
}

/* 股名＋代號＋市場徽章同一列（2026-08-22 補股名）。
   排列＝股名（主標）→代號（灰字）→市場徽章，與個股頁頭部 .name-line 同讀法。
   flex-wrap:wrap ＋ overflow-wrap:anywhere 是「不溢出」的兩道保險：放得下就
   同一列，放不下先讓徽章/代號整塊折到次行，真的連股名本身都比磚寬（極長
   ETF 全名 × 320px × 字級 1.3x）才在股名內部斷字。任何情況下都不會有像素
   跑到磚框外面。 */
.watch-tile-stockline {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 6px;
  min-width: 0;
  max-width: 100%;
}

.watch-tile-stock-name {
  font-weight: 800;
  color: var(--text);
  overflow-wrap: anywhere;
  min-width: 0;
}

.watch-tile-stock-id {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  /* tabular-nums：一整片自選磚的代號欄字寬一致，掃視時對得齊 */
  font-variant-numeric: tabular-nums;
  /* flex:0 0 auto ＋ nowrap：代號本身永遠不准被拆成兩行（「33」換行「28」
     是最糟的顯示 bug），放不下就整塊折到下一行。 */
  flex: 0 0 auto;
  white-space: nowrap;
}

/* 查不到股名（剛上市、資料尚未落庫）：代號就是主角，維持原本的主標尺寸，
   不要縮成一個看起來像附註的灰色小字。絕不用代號填進股名槽假冒。 */
.watch-tile-stock-id.is-solo {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}

.watch-tile-note {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.watch-tile .mini-chart-canvas {
  /* 固定尺寸靠右欄（規格 A1）：不再吃 100% 寬度隨磚拉伸——單獨一檔自選股
     時磚被 grid 拉滿版面寬，圖若跟著 100% 會被拉成一條誇張的細長線。
     flex-shrink: 0 確保 .watch-tile-info 文字再長也不會擠壓圖的寬度。 */
  width: 130px;
  height: 56px;
  /* `0 1 auto`（2026-08-22，原本是 `0 0 auto`）：**grow 仍然是 0**，規格 A1
     的「圖不隨磚寬拉伸」一字未變；改的只有 shrink——極窄磚（320px × 字級
     1.3x）擠不下時由這張圖讓步縮一點，總比讓價格數字溢出去疊在圖上好。
     min-width 是讓步的下限，再窄就看不出走勢了。 */
  flex: 0 1 auto;
  min-width: 76px;
}

@media (max-width: 480px) {
  /* 手機單欄寬度有限：磚本身變窄，圖跟著縮小一點但仍固定尺寸，不拉伸。 */
  .watch-tile .mini-chart-canvas {
    width: 100px;
    height: 48px;
  }
}

.watch-tile-remove {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background-color: rgba(var(--up-rgb), 0.1);
  color: var(--up);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 150ms var(--ease), background-color 150ms var(--ease);
}

.watch-tile:hover .watch-tile-remove,
.watch-tile:focus-within .watch-tile-remove {
  opacity: 1;
}

.watch-tile-remove:hover {
  background-color: rgba(var(--up-rgb), 0.22);
}

.skeleton-tile {
  height: 152px;
  border-radius: var(--radius);
}

/* ---------- 自選股拖曳排序（任務新增） ---------- */

.watch-tile-drag-handle {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: 13px;
  line-height: 1;
  cursor: grab;
  opacity: 0;
  transition: opacity 150ms var(--ease), color 150ms var(--ease);
}

.watch-tile[draggable="true"]:hover .watch-tile-drag-handle,
.watch-tile:focus-within .watch-tile-drag-handle {
  opacity: 1;
}

.watch-tile-drag-handle:hover {
  color: var(--text-muted);
}

.watch-tile.dragging {
  opacity: 0.4;
}

.watch-tile.drag-over {
  border-color: var(--brand-blue);
  box-shadow: 0 0 0 2px rgba(var(--brand-blue-rgb), 0.35);
}

/* ---------- 自選股條件式警示 ---------- */

.watch-tile-alert-btn {
  position: absolute;
  top: 10px;
  right: 38px;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  border-radius: 11px;
  border: 1px solid var(--border);
  background-color: rgba(var(--surface-tint-rgb), 0.04);
  color: var(--text-muted);
  font-size: 11px;
  line-height: 20px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 150ms var(--ease), background-color 150ms var(--ease), color 150ms var(--ease);
}

.watch-tile:hover .watch-tile-alert-btn,
.watch-tile:focus-within .watch-tile-alert-btn,
.watch-tile-alert-btn.has-alerts {
  opacity: 1;
}

.watch-tile-alert-btn.has-alerts {
  color: var(--brand-blue);
  border-color: var(--brand-blue);
  background-color: rgba(var(--brand-blue-rgb), 0.12);
}

.watch-tile-alert-btn:hover {
  background-color: rgba(var(--brand-blue-rgb), 0.2);
}

.alert-panel {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  cursor: default;
}

.alert-panel-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 8px;
}

.alert-panel-empty {
  font-size: 12px;
  color: var(--text-muted);
}

.alert-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text);
}

.alert-row-disabled {
  opacity: 0.5;
}

.alert-row-detail {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alert-row-triggered {
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
}

.alert-row-toggle,
.alert-row-delete {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background-color: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text-muted);
  font-size: 10px;
  cursor: pointer;
  flex-shrink: 0;
}

.alert-row-toggle:hover,
.alert-row-delete:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.alert-form-bar {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.alert-form-type {
  flex: 1;
  min-width: 110px;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 12px;
  background: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text);
}

.alert-form-threshold {
  width: 72px;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 12px;
  background: rgba(var(--surface-tint-rgb), 0.03);
  color: var(--text);
}

.alert-form-add {
  padding: 6px 10px;
  border: 1px solid var(--brand-blue);
  border-radius: 6px;
  font-size: 12px;
  background: rgba(var(--brand-blue-rgb), 0.12);
  color: var(--brand-blue);
  cursor: pointer;
  white-space: nowrap;
}

.alert-form-add:hover {
  background: rgba(var(--brand-blue-rgb), 0.22);
}

.alert-form-status {
  margin-top: 4px;
  font-size: 11px;
  color: var(--down);
}

/* ---------- 績效（任務#158 重設計） ---------- */

.perf-overview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.perf-stat-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow-card);
}

.perf-stat-card .perf-horizon-label {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 700;
  margin-bottom: 8px;
}

.perf-stat-card .perf-avg-return {
  font-size: 26px;
  font-weight: 800;
}

.perf-stat-card .perf-sub-row {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.perf-section-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin: 24px 0 12px;
}

table.perf-rule-table th,
table.perf-rule-table td {
  white-space: nowrap;
}

table.perf-rule-table .rule-name {
  font-weight: 700;
  color: var(--text);
  cursor: help;
}

/* ---------- 績效：空狀態／敘事卡（規格 P6-lite ＋ 任務#158 擴充） ---------- */

.perf-explain-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 18px;
  margin-bottom: 16px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

.perf-disclaimer {
  margin-top: 20px;
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.6;
}

/* 結算前總覽三卡的敘事態變體：不擺死「—」，改「驗證迴路運作中」文案
   （訊號池累積數／最近訊號日／首批結算倒數，三卡各佔一面）。 */
.perf-stat-card-narrative {
  background: linear-gradient(160deg, var(--card-bg), var(--card-bg-hover));
  border-color: var(--border-strong);
}

.perf-narrative-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.perf-narrative-icon {
  font-size: 22px;
  line-height: 1;
  flex-shrink: 0;
}

.perf-narrative-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
}

.perf-narrative-text {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* 部分空狀態（其它期間已有資料，這期間還沒滿足門檻）：輕量提示，不是整
   套敘事，避免部分已結算後仍大篇幅重複「運作中」文案。 */
.perf-stat-card-pending .perf-pending-note {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-faint);
}

/* ---------- 績效：驗證倒數卡（取代舊版黑話「D-1」小數字卡） ---------- */

.perf-countdown-card {
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-card);
}

.perf-countdown-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.perf-countdown-icon {
  font-size: 16px;
}

.perf-countdown-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.02em;
}

.perf-countdown-body {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}

.perf-countdown-value {
  font-size: 30px;
  font-weight: 800;
  color: var(--brand-cyan-text);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.perf-countdown-desc {
  font-size: 13px;
  color: var(--text-muted);
}

.perf-countdown-explain {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-faint);
}

/* ---------- 績效：規則卡片牆／視圖切換 ---------- */

.perf-rules-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin: 24px 0 12px;
}

.perf-section-title-inline {
  margin: 0;
}

.perf-view-toggle {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.perf-view-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 700;
  padding: 6px 14px;
  border-radius: calc(var(--radius-sm) - 3px);
  cursor: pointer;
  transition: background 120ms var(--ease), color 120ms var(--ease);
  white-space: nowrap;
}

.perf-view-btn:hover {
  color: var(--text);
}

.perf-view-btn.active {
  background: var(--accent-bg);
  color: var(--text);
}

.perf-rules-grid {
  margin-bottom: 8px;
}

.perf-rule-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.perf-rule-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.perf-rule-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}

.perf-rule-desc {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* 類別籤：五分類配色沿用全站品牌色板（見 .chip-theme 既有慣例），只是
   每個類別分配不同色相方便一眼辨識，非新創的色彩系統。 */
.perf-cat-chip {
  display: inline-block;
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid transparent;
}

.perf-cat-chip-sm {
  font-size: 10.5px;
  padding: 2px 8px;
}

.perf-cat-technical {
  background: rgba(var(--brand-blue-rgb), 0.12);
  border-color: rgba(var(--brand-blue-rgb), 0.3);
  color: var(--brand-blue);
}

.perf-cat-chips {
  background: rgba(var(--watch-rgb), 0.14);
  border-color: rgba(var(--watch-rgb), 0.3);
  color: var(--watch-fg);
}

.perf-cat-fundamental {
  background: rgba(var(--score-high-rgb), 0.12);
  border-color: rgba(var(--score-high-rgb), 0.3);
  color: var(--score-high);
}

.perf-cat-sentiment {
  background: rgba(var(--brand-violet-rgb), 0.16);
  border-color: rgba(var(--brand-violet-rgb), 0.35);
  color: var(--perf-sentiment-fg);  /* 舉一反三修復 20260728：代幣化（深色值 #a67dff 零變化；淺色=--tag-violet） */
}

.perf-cat-ai {
  background: rgba(var(--brand-cyan-rgb), 0.12);
  border-color: rgba(var(--brand-cyan-rgb), 0.3);
  color: var(--brand-cyan-text);
}

/* ---------- 績效：5/10/20 日勝率環 ---------- */

.perf-horizons-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.perf-horizon-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 1 1 0;
}

.perf-ring {
  --pct: 0;
  --ring-color: var(--text-faint);
  position: relative;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: conic-gradient(var(--ring-color) calc(var(--pct) * 3.6deg), rgba(var(--surface-tint-rgb), 0.08) 0);
  display: flex;
  align-items: center;
  justify-content: center;
}

.perf-ring::before {
  content: "";
  position: absolute;
  inset: 5px;
  border-radius: 50%;
  background: var(--card-bg);
}

.perf-ring-value {
  position: relative;
  z-index: 1;
  font-size: 11.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.perf-ring-high { --ring-color: var(--score-high); }
.perf-ring-mid { --ring-color: var(--score-mid); }
.perf-ring-low { --ring-color: var(--score-low); }
.perf-ring-empty { --ring-color: var(--text-faint); opacity: 0.5; }

.perf-horizon-name {
  font-size: 10.5px;
  color: var(--text-muted);
  font-weight: 600;
}

.perf-horizon-return {
  font-size: 12px;
  font-weight: 700;
}

.perf-sample-chip {
  align-self: flex-start;
  background-color: rgba(var(--score-high-rgb), 0.1);
  border: 1px solid rgba(var(--score-high-rgb), 0.28);
  color: var(--score-high);
  border-radius: 8px;
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 600;
}

.perf-sample-chip-pending {
  background-color: rgba(var(--text-muted-rgb), 0.1);
  border-color: var(--border);
  color: var(--text-faint);
}

/* ---------- 績效：近期訊號結算進度條 ---------- */

.perf-progress-cell {
  min-width: 84px;
}

.perf-progress-track {
  width: 72px;
  height: 6px;
  border-radius: 999px;
  background: rgba(var(--surface-tint-rgb), 0.08);
  overflow: hidden;
}

.perf-progress-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--brand-blue);
  transition: width 200ms var(--ease);
}

.perf-progress-label {
  margin-top: 3px;
  font-size: 10.5px;
  color: var(--text-faint);
  white-space: nowrap;
}

.perf-recent-stock-link {
  color: var(--brand-cyan-text);
  font-weight: 700;
  text-decoration: none;
}

.perf-recent-stock-link:hover {
  text-decoration: underline;
}

/* ---------- TOAST ---------- */

.toast-stack {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  pointer-events: none;
  width: 100%;
  padding: 0 16px;
}

.toast {
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--shadow-pop);
  animation: toastIn 200ms var(--ease);
  max-width: 90vw;
}

.toast.toast-ok { border-color: rgba(var(--down-rgb), 0.4); color: var(--down); }
.toast.toast-err { border-color: rgba(var(--up-rgb), 0.4); color: var(--up); }

@keyframes toastIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- 意見回饋浮動按鈕 + 提交 modal（feedback_widget.js，任務新增；
   案⑥ 2026-07-12 改版：icon-only 圓形浮鈕） ----------
   浮動按鈕固定右下角、全站出現（登入才顯示，由 JS 判斷）；modal 外框沿用既有
   .info-modal-overlay / .info-modal-card（個股 AI 深度體檢彈窗同款），這裡只
   補浮動按鈕本體與表單內特有樣式，避免重複定義一份幾乎一樣的 modal 外框。

   病灶（案⑥ 使用者實測回報）：舊版一律展開成「💬 意見回饋」文字藥丸，
   固定佔用 right:20/bottom:20 一大塊區域，疊住設定分頁 sticky 儲存列
   （.settings-actionbar）的存檔鈕點不到。改版：預設收合成 48px 純
   icon 圓鈕（對照 Intercom/Zendesk 等成熟產品 FAB 慣例），只有
   hover／focus 時才展開出文字標籤，遮擋足跡從一大塊藥丸縮到一個小圓點。
   標籤展開用 max-width/opacity 轉場（不是 width:auto，CSS 無法對 auto
   轉場），按鈕本身靠 flex content 自然撐開寬度，不需要額外設定 width。 */
.feedback-fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 90;
  display: flex;
  align-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow-pop);
  overflow: hidden;
  transition: transform 150ms var(--ease), box-shadow 150ms var(--ease),
    opacity 180ms var(--ease);
}

.feedback-fab:hover,
.feedback-fab:focus-visible {
  width: auto;
  transform: translateY(-2px);
}

.feedback-fab-icon {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
}

.feedback-fab-label {
  display: inline-block;
  max-width: 0;
  opacity: 0;
  white-space: nowrap;
  overflow: hidden;
  transition: max-width 220ms var(--ease), opacity 160ms var(--ease), padding-right 220ms var(--ease);
}

.feedback-fab:hover .feedback-fab-label,
.feedback-fab:focus-visible .feedback-fab-label {
  max-width: 120px;
  opacity: 1;
  padding-right: 16px;
}

/* 滿意度調查卡片顯示時讓位（案⑥ 全域規則④：feedback-fab／survey_widget／
   頁面操作列三者不互疊）：survey_widget.js 顯示 CSAT/NPS 卡片時會 dispatch
   `signova:survey-shown`／關閉時 `signova:survey-hidden`，feedback_widget.js
   監聽後切換這個 class，讓浮鈕淡出＋不可點擊，避免兩個右下角浮動元件同時
   搶占同一塊視覺與互動空間；調查卡片關閉後浮鈕自動淡入恢復。 */
.feedback-fab-yield {
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
}

@media (max-width: 767px) {
  .feedback-fab {
    right: 14px;
    bottom: 14px;
    width: 44px;
    height: 44px;
  }
  .feedback-fab-icon {
    width: 44px;
    height: 44px;
  }
}

.feedback-modal-card {
  max-width: 480px;
}

.feedback-form .field-group {
  margin-bottom: 14px;
}

.feedback-form select.text-input,
.feedback-form .feedback-textarea {
  width: 100%;
  box-sizing: border-box;
}

.feedback-form .feedback-textarea {
  resize: vertical;
  font-family: inherit;
  line-height: 1.6;
  padding: 10px 12px;
}

.feedback-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 6px;
}

/* 帳戶頁「我的回報」清單（account.js loadMyFeedback）＋管理台回饋分頁
   （admin.js）共用同一套 .status-badge 狀態色。 */
.status-badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}

.status-badge.status-new {
  background: rgba(var(--brand-blue-rgb), 0.16);
  color: var(--status-new);
}

.status-badge.status-progress {
  background: rgba(var(--status-progress-rgb), 0.16);
  color: var(--status-progress);
}

.status-badge.status-resolved {
  background: rgba(var(--status-resolved-rgb), 0.16);
  color: var(--status-resolved);
}

.status-badge.status-wontfix {
  background: rgba(var(--surface-tint-rgb), 0.08);
  color: var(--text-muted);
}

.my-feedback-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.my-feedback-item {
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: rgba(var(--surface-tint-rgb), 0.02);
}

.my-feedback-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.my-feedback-title {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
}

.my-feedback-meta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
}

.my-feedback-reply {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border-strong);
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.6;
}

/* ---------- 帳號停權全頁遮罩（nav.js renderSuspendedOverlay，會員停權功能，
   任務新增） ----------
   z-index 999999：刻意高於全站所有既有浮動元素（.info-modal-overlay=200／
   .feedback-fab=90／各頁彈窗），且不可透過點擊背景或 Esc 關閉（沒有掛
   對應的 close 事件），確保停權帳號不管原本在哪個頁面、開著哪個既有 modal，
   一律被這層完全蓋住、任何底層功能都摸不到。 */
.suspended-overlay {
  position: fixed;
  inset: 0;
  z-index: 999999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(var(--scrim-rgb), 0.92);
  animation: fadeIn 150ms var(--ease);
}

.suspended-overlay-card {
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(var(--shadow-rgb), 0.6);
  padding: 28px 26px;
  max-width: 480px;
  width: 100%;
  max-height: 86vh;
  overflow-y: auto;
  text-align: center;
}

.suspended-overlay-icon {
  font-size: 34px;
  line-height: 1;
  margin-bottom: 10px;
}

.suspended-overlay-card h2 {
  margin: 0 0 10px;
  font-size: 19px;
  color: #ff6b6b;  /* theme-exempt: #ff6b6b 與 --up(#ff5d5d) 不等值 */
}

.suspended-overlay-card p {
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--text-muted);
  margin: 0 0 10px;
  text-align: left;
}

.suspended-overlay-reason {
  background: rgba(var(--up-rgb), 0.1);
  border: 1px solid rgba(var(--up-rgb), 0.3);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  color: var(--text);
  text-align: left;
  margin: 0 0 14px;
}

.suspended-overlay-actions {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 16px 0 6px;
  flex-wrap: wrap;
}

.suspended-overlay-mine {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border-strong);
  text-align: left;
}

.suspended-overlay-mine h3 {
  margin: 0 0 10px;
  font-size: 13.5px;
  color: var(--brand-cyan-text);
}

/* ---------- SKELETON LOADING ---------- */

.skeleton {
  background: linear-gradient(
    100deg,
    rgba(var(--surface-tint-rgb), 0.04) 30%,
    rgba(var(--surface-tint-rgb), 0.09) 50%,
    rgba(var(--surface-tint-rgb), 0.04) 70%
  );
  background-size: 200% 100%;
  animation: skeletonShimmer 1.3s ease-in-out infinite;
  border-radius: 8px;
}

@keyframes skeletonShimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.skeleton-card {
  height: 140px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}

.skeleton-line {
  height: 14px;
  margin-bottom: 8px;
}

/* ---------- 設定頁：多組命名選股策略（任務新增） ---------- */

.strategy-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 12px;
}

.strategy-row {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 13px;
  background: rgba(var(--surface-tint-rgb), 0.02);
  transition: border-color 150ms var(--ease);
}

.strategy-row.is-active {
  border-color: var(--accent);
}

.strategy-row-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.strategy-active-badge {
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-text);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}

.strategy-row-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.strategy-row-actions button {
  font-size: 12px;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition: border-color 150ms var(--ease);
}

.strategy-row-actions button:hover:not(:disabled) {
  border-color: var(--accent);
}

.strategy-row-actions button:disabled {
  opacity: 0.45;
  cursor: default;
}

.strategy-new-form {
  border-top: 1px solid var(--border);
  padding-top: 12px;
  margin-top: 4px;
}

.strategy-new-form .field-group-hint {
  margin-bottom: 8px;
}

/* ---------- RESPONSIVE ---------- */

@media (max-width: 767px) {
  main { padding: 14px 12px 32px; }
  /* `.nav { padding: 10px 14px; }` 已於 2026-08-19 搬到 NAV 區段基底規則正
     下方——它排在這裡會（因來源順序）蓋掉 `@media (max-width:480px)` 的窄幕
     內距收窄，見該處註解。此處不留同名規則，避免又把它蓋回去。 */
  /* 大盤指數卡（#200 起是 grid）：手機收成單欄——主數字區在上、兩塊
     sub-stat 磚在下並排（磚本身仍是兩欄，390px 各約 150px 綽綽有餘）。 */
  .market-card {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    padding: 16px 16px 14px;
    gap: 13px;
  }
  .mini-chart-canvas { width: 110px; height: 44px; }

  /* 2026-08-06 跑版根治其之二：上面那條手機縮圖規則（特異度 0,1,0）一直
     被 `.signal-card-side .mini-chart-canvas`（0,2,0）蓋掉，訊號卡的迷你
     K 線在手機上其實還是 130px——「手機縮圖」這個既有意圖從來沒生效過。
     補一條同特異度的規則讓它真的縮到 110px，卡頭左欄因此多拿回 20px。 */
  .signal-card-side .mini-chart-canvas { width: 110px; }

  /* 跑版根治其之三：手機的價格列改直排（大字價格／漲跌／更新時間各佔
     一行，順序固定）。
     幾何：卡頭左欄在 390px 只剩 180px（298 −8 gap −110 右欄）。並排版的
     價格列 max-content 實測 145.8px（26.15）～191.9px（1234.50 +123.50
     +9.99%）——**會不會爆版取決於這檔股票今天漲多少**，正是站長看到同一
     組卡片兩種版型的直接原因。改直排後這一區的寬度需求 ＝ 三行裡最寬的
     那一行（約 99px），與字串長度徹底脫鉤，180px 留有 81px 餘裕，四張卡
     在任何行情下都是同一個版型。
     代價是手機卡片高約 +15px，換來版型不再隨盤中報價跳動。
     .watch-tile 的自選股磚共用 .price-head，同步受惠（磚更窄、更擠）。 */
  .price-head {
    grid-template-columns: minmax(0, 1fr);
  }
  .price-change {
    grid-row: 2;
    grid-column: 1;
  }
  .price-head .card-quote-time {
    grid-row: 3;
  }
}

/* ---------- 連線狀態守護橫幅（connstatus.js 注入，2026-07 新增） ----------
   固定於 nav 正下方（有 nav 的頁面）或頁面最頂（login/verify 無 nav）；
   DOM 完全由 JS 建立，這裡只定義樣式。紅＝失聯，綠＝恢復。 */
.connstatus-banner {
  position: sticky;
  top: 0;
  z-index: 19;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  border-bottom: 1px solid var(--border-strong);
  animation: fadeIn 200ms var(--ease);
}

.connstatus-banner[data-state="down"] {
  background: rgba(var(--conn-down-rgb), 0.16);
  color: var(--conn-down);
}

.connstatus-banner[data-state="up"] {
  background: rgba(var(--conn-up-rgb), 0.16);
  color: var(--conn-up);
}

.connstatus-banner .connstatus-msg {
  white-space: normal;
}

.connstatus-banner .connstatus-btn {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 700;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  cursor: pointer;
  transition: background 150ms var(--ease);
}

.connstatus-banner .connstatus-btn:hover {
  background: rgba(var(--surface-tint-rgb), 0.12);
}

.connstatus-banner .connstatus-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ==========================================================================
   設計系統共用元件層（#30 精煉，2026-07-10 Fable）
   --------------------------------------------------------------------------
   背景：app.css 之外 12 個獨立頁 CSS 共 ~6,300 行，各自重複定義表格
   （9~30 處）/卡片（3~40 處）/徽章，風格逐頁漂移。本層把全站既有最佳
   模式制度化成 .sv-* 共用元件（全部只用上方既有 tokens，精煉≠重設計、
   純 additive 零破壞）。**新頁面一律優先用 .sv-*，禁止再自定義同構元件**；
   既有頁面按 docs/design_system.md 的遷移清單逐頁收斂。
   ========================================================================== */

/* ---- 區塊卡：頁面主要內容單元（標題列＋內容） ---- */
.sv-section {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  margin-bottom: 18px;
  box-shadow: var(--shadow-card);
}

.sv-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.sv-section-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.02em;
}

/* 標題列右側的動作/篩選容器 */
.sv-section-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* ---- 資料表：專業資訊密度（緊湊、數字右對齊、hover 列） ---- */
.sv-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.sv-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.sv-table th {
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}

.sv-table td {
  padding: 9px 10px;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  white-space: nowrap;
}

.sv-table tbody tr:hover {
  background: var(--card-bg-hover);
}

.sv-table th.num,
.sv-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ---- 徽章：語意色系（漲跌沿台股慣例；分類標籤用中性色——法律審查：
   分類標籤不得用紅綠傳遞多空暗示，見 docs/legal/99 審查意見書） ---- */
.sv-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  background: var(--skip-bg);
  color: var(--text-muted);
}

.sv-badge-up { background: var(--up-bg); color: var(--up); }
.sv-badge-down { background: var(--down-bg); color: var(--down); }
.sv-badge-warn { background: var(--warn-bg); color: var(--warn-fg); }
.sv-badge-accent { background: var(--accent-bg); color: var(--accent-text); }
/* 中性分類色（策略/狀態標籤專用，無多空聯想） */
.sv-badge-blue { background: rgba(var(--brand-blue-rgb), 0.14); color: var(--tag-blue); }
.sv-badge-violet { background: rgba(var(--badge-violet-rgb), 0.16); color: var(--tag-violet); }  /* 舉一反三修復 20260728：底色代幣化（深色值 150,110,255 零變化；淺色=--tag-violet-rgb 色相歸隊） */
.sv-badge-slate { background: rgba(var(--text-muted-rgb), 0.14); color: var(--tag-slate); }

/* ---- 懸浮備註框（hover popover）全域元件（任務#84，2026-07-10 從
   stock.css 升格為全域層——UI 元件級 bug 修法一律進全域，見專案
   CLAUDE.md 血訓）：一顆觸發元素（badge/info 圖示）＋一個懸浮說明框，
   互動邏輯（hover 200ms 寬限收合／點擊釘選／Esc/點外部關閉）交給
   web/static/popover_util.js 的 SvPopover.bind()，這裡只管樣式與顯示
   condition。原個股頁指標白話備註（#64）、K線型態卡可靠度/多空不明
   info 彈窗（#66）都吃這組共用類名，見 stock.js。 ---- */
.sv-metric-chip-wrap {
  position: relative;
  display: inline-flex;
}

.sv-metric-chip {
  cursor: pointer;
  user-select: none;
}

.sv-metric-chip:focus-visible {
  outline: 2px solid var(--brand-cyan);
  outline-offset: 2px;
}

.sv-metric-pop {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  width: 230px;
  max-width: min(230px, 78vw);
  background: rgba(var(--surface-scrim-rgb), 0.97);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--text);
  box-shadow: var(--shadow-pop);
  text-align: left;
  white-space: normal;
}

/* 死區橋接（同 .nav-dropdown::before 手法，見上方 nav 區塊注解）：chip
   底部到 pop 頂部之間留的 6px 視覺間距，滑鼠路徑上原本沒有任何元素接
   住游標，會被誤判「離開 wrap」導致 pop 瞬間收合、點不到框內連結
   （2026-07-10 使用者實測病灶）。這裡補一個透明熱區蓋住整段間距，讓
   hover hit-box 連續；pop 顯示時才會渲染（display:none 時 ::before 不
   存在），觸發顯示本身靠滑鼠先進入 chip/icon 本體，不受影響。 */
.sv-metric-pop::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -6px;
  height: 6px;
}

/* 顯示三條件：滑鼠原生 hover（JS 掛不上時的退化路徑）／JS 管理的
   .sv-pop-hover（mouseenter 立即加、mouseleave 200ms 寬限才移除，見
   popover_util.js）／.sv-metric-chip-open（點擊釘選，不受 hover 影響，
   同一時間全站只會有一個）。 */
.sv-metric-chip-wrap:hover .sv-metric-pop,
.sv-metric-chip-wrap.sv-pop-hover .sv-metric-pop,
.sv-metric-chip-wrap.sv-metric-chip-open .sv-metric-pop {
  display: block;
}

.sv-metric-pop p {
  margin: 0 0 6px;
}

.sv-metric-pop a {
  color: var(--brand-cyan-text);
  text-decoration: none;
  font-size: 11px;
}

.sv-metric-pop a:hover {
  text-decoration: underline;
}

/* 加寬修飾類（任務#157 案3新增）：預設 230px 對純文字備註夠用，但漏斗頁
   「熱度」說明要塞四權重子項拆解（每項一個 label+分數+一句白話），230px
   會擠成三行文字疊在一起難讀。這裡加一個共用的加寬變體，之後任何需要
   放表格/多行拆解的 popover 都可以直接加這個 class，不必各自重開一份
   寬度樣式。 */
.sv-metric-pop.sv-metric-pop-wide {
  width: 300px;
  max-width: min(300px, 88vw);
}

/* ---- KPI 統計磚：頁頂關鍵數字帶 ---- */
.sv-stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.sv-stat {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
}

.sv-stat-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.sv-stat-value {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.sv-stat-sub {
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 4px;
}

/* ---- 洞察卡網格：規則式/AI 短評卡片並列（#101，2026-07-11 新增）
   用於「分類籤＋粗體結論句＋淡色補充句＋深入學習連結」這種洞察卡清單
   （法人排行/期貨籌碼/產業資金流/ETF 資金流的「盤後重點解讀」）——原本
   單欄直列在寬螢幕下拉出一大段瀑布，改用 auto-fill 讓版面夠寬時自動並列
   多欄。minmax(min(340px,100%),1fr) 而不是裸 minmax(340px,1fr)：容器比
   340px 窄時（手機/窄欄）用 100% 頂替最小寬度，避免 grid track 撐爆容器
   造成橫向捲軸，同 .pf-overview-cards／.dv-kpi-cards 既有慣例。見
   docs/design_system.md §10。 ---- */
.sv-insight-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
  /* #216 質感升級後卡片本身有柔影（--sv-card-shadow），12px 間距會讓相鄰兩張
     的陰影互相壓到，改 14px 讓每張卡各自落地。 */
  gap: 14px;
}

/* ---- 篩選列 ---- */
.sv-filter-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--text-muted);
}

.sv-filter-bar select,
.sv-filter-bar input[type="text"] {
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  font-size: 13px;
}

/* ---- 空狀態 / 資料日標註（誠實揭露慣例） ---- */
.sv-empty {
  padding: 28px 12px;
  text-align: center;
  color: var(--text-faint);
  font-size: 13px;
}

.sv-data-date {
  font-size: 11px;
  color: var(--text-faint);
  font-weight: 400;
}

/* ---- 更新時刻註記：區塊標題列下方的 muted 小字 ----
   #239 升格（2026-08-19）。原本 institutional.css / industry.css 各留一份
   同名同義的宣告，兩處註解都寫著「之後若有第三頁要用，再升格進 app.css 並
   一次 bump `?v=`」——#239 把註記鋪到 /etf、/futures、/market、/dividend、
   /big-holders、/conference，第三個使用者到齊，條件成立，宣告收攏到這裡，
   那兩份本地宣告同時刪除（重複宣告會讓「改一處以為全站生效」變成靜默的
   假動作）。

   用法契約：貼在區塊標題列之後、內容容器之前的一行 `<p>`，內容三原則
   ——給區間不給死點、歸因寫「依公開資訊發布時程」（集保／公開資訊觀測站
   的資料寫對應機構名）、時刻字串一律寫死字面**不得** import scheduler 常數
   （排程改了文案沒跟著改時，要讓測試變紅燈提醒人去改文案，而不是跟著一起
   漂移、讓站上掛著錯的時段沒人知道）。

   顏色吃 --text-muted 主題代幣，不宣告色票。 */
.sv-update-note {
  margin: 4px 0 0;
  font-size: 12px;
  line-height: 1.6;
  font-weight: 400;
  color: var(--text-muted);
}

/* ==========================================================================
   選股執行狀態列：進度卡／失敗橫幅／設定已變更 chip（規格 P0，任務新增）
   --------------------------------------------------------------------------
   三者共用 #today-status-banner 容器，時間軸互斥（見 app.js
   renderProgressCard() / renderRunStatusBanner() 的取捨說明）。
   ========================================================================== */

.run-progress-card {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--accent-bg);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.35);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: 13px;
  color: var(--text);
}

.run-progress-card .spinner {
  border-color: rgba(var(--brand-blue-rgb), 0.35);
  border-top-color: var(--brand-blue);
}

.run-progress-stage {
  font-weight: 700;
}

.run-progress-elapsed {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.run-fail-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-fg);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: 13px;
}

.btn-run-retry {
  background: transparent;
  color: var(--warn-fg);
  border: 1px solid var(--warn-border);
  border-radius: 8px;
  padding: 5px 14px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms var(--ease);
}

.btn-run-retry:hover {
  background: rgba(var(--watch-rgb), 0.16);
}

.settings-newer-chip {
  display: inline-block;
  background: var(--accent-bg);
  color: var(--brand-blue);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.3);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  margin-bottom: 12px;
  font-size: 12.5px;
  font-weight: 600;
}

/* 非交易日手動選股資料基準日標註（任務#93），比照 .settings-newer-chip
   的中性提示樣式、換一個不搶眼的灰階調性（不是警告，是誠實揭露）。 */
.data-as-of-chip {
  display: inline-block;
  background: var(--bg-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  margin-bottom: 12px;
  font-size: 12.5px;
  font-weight: 600;
}

/* toast 行動鈕（規格 P0：儲存設定成功→立即選股） */
.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: auto;
}

.toast-action-btn {
  background: var(--brand-gradient);
  color: var(--on-accent);
  border: none;
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}

/* ==========================================================================
   PV 視覺語言四件套（AI 智選重構首發棒 M2，任務新增）
   --------------------------------------------------------------------------
   sv-hero-stat（大數字卡）／sv-sparkline-canvas（app.js drawSparkline() 畫）
   ／sv-ring（app.js renderScoreRing() 畫）／sv-empty-viz（空狀態插畫）。
   全部沿用上方既有 tokens，不新增顏色體系；分數環刻意用 slate/blue/violet
   三階（不用紅綠——分數是數據完整度不是漲跌方向，紅綠只准用於行情事實，
   見本文件開頭「語意色」規則與 docs/design_system.md）。
   ========================================================================== */

/* ---- 大數字卡：頁頂關鍵指標，比 .sv-stat 更醒目（44px+ 等寬數字）
   任務#157 案4「首屏預算整治」：桌機 1920×1080 免捲動要看到第一排訊號
   卡評分圈，KPI 三卡是要壓縮的三個目標之一（硬驗收 ≤110px／卡）。padding
   16→8、數字 clamp 上限 44→28、label margin-top 6→2、字級略縮。第一輪
   （padding 10/clamp 30）量測時全頁仍差 28px 未達標——今日
   `today-funnel-row`／`today-intraday-feed` 兩塊即時內容比#154量測當時
   多撐出不少高度，不在本案裁剪授權範圍內——於是把授權範圍內三個目標
   （KPI卡／首頁橫幅／市場脈搏條）再壓緊一階，不動範圍外元件，實測見
   任務#157 完工回報的高度量測表。 ---- */
.sv-hero-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin-bottom: 8px;
}

.sv-hero-stat {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 14px;
  box-shadow: var(--shadow-card);
}

.sv-hero-stat-value {
  font-size: clamp(20px, 1.2vw + 15px, 28px);
  font-weight: 800;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.sv-hero-stat-value-text {
  font-size: clamp(14px, 0.7vw + 11px, 17px);
  font-weight: 700;
}

/* 趨勢箭頭槽：呼叫端視需要塞 ▲/▼ span 並加 .up/.down class（沿用全站
   紅漲綠跌語意），本身不預設內容——沒有趨勢資料就留空，不硬畫。 */
.sv-hero-stat-trend {
  font-size: 14px;
  font-weight: 700;
}

.sv-hero-stat-trend.up { color: var(--up); }
.sv-hero-stat-trend.down { color: var(--down); }

.sv-hero-stat-label {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-muted);
}

/* ---- 入選產業分佈 chips（任務#157 案1，取代舊版單一「最強產業」文字）
   ----
   第三張 KPI 卡改顯示全部入選產業（非只有最高檔數那一個），chips 換行
   排列；卡高交給 CSS Grid 同列自動撐齊（.sv-hero-row 是 grid，三個
   .sv-hero-stat 同一列，最高的那個自然決定整列高度，不必額外對齊）。
   案4「首屏預算整治」硬驗收 KPI 三卡 ≤110px／卡，若某天入選產業數很多
   （例如 15+ 產業）chips 換行可能撐爆這個高度預算，因此 chips 容器本身
   設 max-height + overflow-y:auto——優先滿足「chips 換行、看得到多少算
   多少」，超出的用捲動兜底，不強制縮字級到不可讀，也不讓單一卡片無限
   撐高拖垮全站首屏預算。 */
.sv-hero-stat-industries {
  display: flex;
  flex-direction: column;
}

.sv-industry-chip-row {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 4px;
  max-height: 50px;
  overflow-y: auto;
  padding-right: 2px;
}

.sv-industry-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(var(--text-muted-rgb), 0.08);
  color: var(--text-muted);
  font-size: 10.5px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color 120ms var(--ease), background-color 120ms var(--ease), color 120ms var(--ease);
}

.sv-industry-chip:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.sv-industry-chip:focus-visible {
  outline: 2px solid var(--brand-cyan);
  outline-offset: 1px;
}

.sv-industry-chip-count {
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}

/* 最多檔數的產業：品牌外框＋⭐＋加粗（規格明文三件套）。 */
.sv-industry-chip-top {
  border-color: var(--brand-cyan);
  background: rgba(var(--brand-cyan-rgb), 0.14);
  color: var(--brand-cyan-text);
  font-weight: 800;
}

.sv-industry-chip-star {
  font-size: 9.5px;
}

/* 目前正被套用為快速篩選條件的 chip（點擊後與 #quick-filter-industry
   下拉同步狀態，見 app.js applyIndustryChipFilter()）。 */
.sv-industry-chip-active {
  outline: 2px solid var(--brand-cyan);
  outline-offset: 1px;
}

/* ---- 迷你走勢線：app.js drawSparkline(canvas, values, opts) 畫 ---- */
.sv-sparkline-canvas {
  width: 64px;
  height: 24px;
  display: block;
  flex-shrink: 0;
}

/* ---- 分數環：app.js renderScoreRing(el, score, max) 畫 ---- */
.sv-ring {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
}

.sv-ring-svg {
  width: 100%;
  height: 100%;
}

.sv-ring-track {
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 4;
}

.sv-ring-fg {
  fill: none;
  stroke-width: 4;
  stroke-linecap: round;
  transition: stroke-dasharray 300ms var(--ease);
}

.sv-ring-label {
  font-size: 15px;
  font-weight: 800;
  fill: var(--text);
}

/* 分數三階（低→中→高）：slate/blue/violet，刻意不用紅綠——分數代表數據
   完整度，不是漲跌方向，紅綠語意只保留給行情事實（見上方語意色規則）。 */
.sv-ring-low .sv-ring-fg { stroke: var(--text-muted); }
.sv-ring-mid .sv-ring-fg { stroke: var(--brand-blue); }
.sv-ring-high .sv-ring-fg { stroke: var(--tag-violet); }

.sv-ring-empty {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px dashed var(--border-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--text-faint);
}

/* ---- 空狀態插畫：中性線條風 SVG（chart/search 兩款）＋白話文案＋行動鈕 ---- */
.sv-empty-viz {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 40px 20px;
  color: var(--text-faint);
}

.sv-empty-viz-icon {
  width: 72px;
  height: 72px;
  color: var(--text-muted);
  opacity: 0.7;
  margin-bottom: 14px;
}

.sv-empty-viz-icon svg {
  width: 100%;
  height: 100%;
}

.sv-empty-viz-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 6px;
}

.sv-empty-viz-hint {
  font-size: 13px;
  color: var(--text-muted);
  max-width: 360px;
  line-height: 1.6;
}

.sv-empty-viz-action {
  margin-top: 16px;
  background: var(--brand-gradient);
  color: var(--on-accent);
  border: none;
  border-radius: 10px;
  padding: 9px 20px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

/* ==========================================================================
   透明漏斗色帶條＋設定回顯 chips（AI 智選重構 P1，任務#69新增）
   --------------------------------------------------------------------------
   sv-funnel-*：今日訊號頁「本次選股漏斗」四段色帶條（全市場->命中規則->
   產業/主題過濾->入選），藍→紫漸層深淺呼應品牌色但刻意不用紅綠（漏斗是
   流程事實，不是漲跌，同 sv-ring 的既有語意色規則）。
   sv-recap-*：設定回顯 chips 列。
   run-funnel-*：選股紀錄表格的迷你漏斗欄。
   funnel-dropped-*：點漏斗某一段彈出的被刷樣本清單（殼複用既有
   .info-modal-overlay / .info-modal-card，同 admin-delete-* 的既有模式）。
   ========================================================================== */

.sv-funnel-row {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}

.sv-funnel-stage {
  flex: 1 1 110px;
  min-width: 90px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  padding: 10px 12px;
  text-align: center;
}

.sv-funnel-stage-value {
  font-size: clamp(20px, 1.2vw + 16px, 26px);
  font-weight: 800;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.sv-funnel-stage-label {
  margin-top: 3px;
  font-size: 11.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 四段藍→紫漸層深淺：universe 最淺（起點，全市場基準）、final 最深/最
   飽和（終點，最重要的結果），中間兩段線性過渡。 */
.sv-funnel-stage-universe {
  background: rgba(var(--brand-cyan-rgb), 0.07);
  border-color: rgba(var(--brand-cyan-rgb), 0.22);
}
.sv-funnel-stage-rules {
  background: rgba(var(--brand-blue-rgb), 0.12);
  border-color: rgba(var(--brand-blue-rgb), 0.32);
}
.sv-funnel-stage-industry {
  background: rgba(var(--funnel-ramp-2-rgb), 0.15);
  border-color: rgba(var(--funnel-ramp-2-rgb), 0.38);
}
.sv-funnel-stage-final {
  background: rgba(var(--brand-violet-rgb), 0.18);
  border-color: rgba(var(--brand-violet-rgb), 0.45);
}
.sv-funnel-stage-final .sv-funnel-stage-value {
  color: var(--tag-violet); /* 同 sv-ring-high，分數/漏斗結果統一用這階紫 */
}

/* 環境守門段（任務#154 追加科目）：五段漏斗裡插在 rules 與 industry
   之間，舊版沒有專屬顏色、會落回 .sv-funnel-stage 的預設灰邊，讓藍→紫
   漸層在這裡斷一截——這裡補上介於兩者之間的藍紫色銜接漸層，並多給一點
   flex-basis（放得下下面補的動態狀態句，見 .sv-funnel-stage-note）。
   實際觸發收緊時額外疊 .sv-funnel-stage-env-triggered 轉為警示紅，讓
   使用者一眼看出「今天有沒有真的動作」。 */
.sv-funnel-stage-env_guard {
  flex: 1.6 1 150px;
  background: rgba(var(--funnel-ramp-1-rgb), 0.13);
  border-color: rgba(var(--funnel-ramp-1-rgb), 0.34);
}

.sv-funnel-stage-env-triggered {
  background: var(--danger-bg);
  border-color: rgba(var(--up-rgb), 0.45);
}

.sv-funnel-stage-env-triggered .sv-funnel-stage-value {
  color: var(--danger);
}

.sv-funnel-stage-note {
  margin-top: 4px;
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--text-faint);
  white-space: normal;
}

.sv-funnel-stage-note-triggered {
  color: var(--danger);
  font-weight: 600;
}

.sv-funnel-stage-clickable {
  cursor: pointer;
  transition: transform 120ms var(--ease), border-color 120ms var(--ease);
}

.sv-funnel-stage-clickable:hover,
.sv-funnel-stage-clickable:focus-visible {
  border-color: var(--brand-cyan);
  transform: translateY(-1px);
  outline: none;
}

.sv-funnel-arrow {
  display: flex;
  align-items: center;
  color: var(--text-faint);
  font-size: 14px;
  flex: 0 0 auto;
  padding: 0 2px;
}

.sv-funnel-missing {
  font-size: 12.5px;
  color: var(--text-faint);
  padding: 8px 2px;
  margin-bottom: 6px;
}

/* ==========================================================================
   週選漏斗視覺 sv-wfunnel-*（FT-52 M3-9，2026-08-06）
   --------------------------------------------------------------------------
   沿革：四塊素白框（站長 19:58 打槍「顯舊」）→ CSS clip-path 梯形（站長
   20:35 再打槍「很沒質感，又很醜」：實心淡色塊、生硬斜邊、前三層幾乎同色、
   末層突然轉紫）→ **本版整條漏斗是一張 SVG**（結構與幾何見 app.js
   weeklyFunnelSVG()／welcome.js 同名段落，兩處同構，改一邊要同步另一邊）。

   為什麼是 SVG：clip-path 做不出 defs 漸層、非水平邊的 1px 高光、以及跟著
   斜邊走的濾鏡——那正是 treemap／環境儀表／法人拔河條那套質感的來源。

   色彩故事（站長 20:35 指示）：四層**同一色相**（--accent）由淺到深漸進，
   深度寫在 .sv-wfunnel-l0..l3 的 --wf-c，用 color-mix() 從主題代幣現算；
   顏色本身就讀得出 28→28→17→5 的收斂感，不再是「前三層粉、末層突然紫」。
   每層再疊：縱向漸層（頂亮底暗＝立體）＋頂緣 1px 高光＋柔投影，層間留
   6 個 viewBox 單位的細縫讓輪廓呼吸。

   深/淺兩套強度旋鈕分開（深底吃得住光暈、白底要極輕否則髒）。零寫死色。
   ========================================================================== */

.sv-wfunnel {
  /* 尺寸＝站長 2026-08-07 兩次定調：桌機「縮小到跟左邊黃框差不多大」（340px
     靠左與時間戳膠囊對齊）、手機「也要修正小一點」（272px 置中——手機上小
     元素靠左會右側大片空）。SVG 等比縮放，兩端都不會變形。 */
  max-width: 272px;
  margin: 2px auto 16px;

  /* 四層深度：同一色相由淺到深。深色主題刻意不往「更亮」走——深色 UI 裡
     「更深」＝更飽和但仍壓得住，往亮處走會讓末層的字掉對比。 */
  --wf-d0: 14%;
  --wf-d1: 24%;
  --wf-d2: 36%;
  --wf-d3: 52%;
  --wf-top: 86%;      /* 縱向漸層頂端：--wf-c 保留多少（其餘混白）＝受光面 */
  --wf-bot: 88%;      /* 底端：--wf-c 保留多少（其餘混黑）＝背光面 */
  --wf-gloss: 34%;    /* 環口 catch light 的白度 */
  --wf-shadow-a: 0.34;
  --wf-final-glow: 30%;
  /* ---- 3D 碗（M3-10）三種材質的強度旋鈕，全部從同一顆 --wf-c 現算 ---- */
  --wf-rim-lit: 62%;   /* 環口受光側：--wf-c 保留多少（其餘混白） */
  --wf-rim-shade: 78%; /* 環口背光側：保留多少（其餘混黑） */
  --wf-in-back: 46%;   /* 碗內後緣（最深處）：保留多少（其餘混黑） */
  --wf-in-front: 68%;  /* 碗內前緣（碗底反光）：保留多少 */
  --wf-icon-a: 78%;    /* 層側 icon 線條的 accent 濃度 */
  --wf-underglow-a: 34%; /* 末層底光中心的 accent 濃度 */
}

:root[data-theme="light-a"] .sv-wfunnel,
:root[data-theme="light-b"] .sv-wfunnel,
:root[data-theme="light-c"] .sv-wfunnel,
:root[data-theme="champagne"] .sv-wfunnel {
  /* 淺色主題：底是白的，「更深」就是真的更深，可以拉大級距讓收斂感更明顯；
     光暈與高光一律壓輕，否則白底會髒。 */
  --wf-d0: 16%;
  --wf-d1: 30%;
  --wf-d2: 46%;
  --wf-d3: 66%;
  --wf-top: 90%;
  --wf-bot: 92%;
  --wf-gloss: 62%;
  --wf-shadow-a: 0.16;
  --wf-final-glow: 16%;
  /* 白底：碗內暗面不能太深（前三層的 --wf-c 本來就淺，混太多黑會變髒灰），
     環口的金屬對比也收一階。 */
  --wf-rim-lit: 74%;
  --wf-rim-shade: 86%;
  --wf-in-back: 66%;
  --wf-in-front: 82%;
  --wf-icon-a: 86%;
  --wf-underglow-a: 22%;
}

.sv-wfunnel-svg {
  display: block;
  width: 100%;
  height: auto;
}

@media (min-width: 768px) {
  .sv-wfunnel {
    max-width: 340px;
    margin-left: 0;
    margin-right: 0;
  }
}

/* 四層的基色：同一色相（--accent）越往下越深。 */
.sv-wfunnel-l0 { --wf-c: color-mix(in srgb, var(--accent) var(--wf-d0), var(--card-bg)); }
.sv-wfunnel-l1 { --wf-c: color-mix(in srgb, var(--accent) var(--wf-d1), var(--card-bg)); }
.sv-wfunnel-l2 { --wf-c: color-mix(in srgb, var(--accent) var(--wf-d2), var(--card-bg)); }
.sv-wfunnel-l3 { --wf-c: color-mix(in srgb, var(--accent) var(--wf-d3), var(--card-bg)); }

/* 碗身縱向漸層三端（<stop> 繼承所屬 <g> 的 --wf-c，所以每層各自算各自的）。 */
.wf-stop-top { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-top), white); }
.wf-stop-mid { stop-color: var(--wf-c); }
.wf-stop-bot { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-bot), black); }

/* 環口金屬（橫向：左受光 → 主色 → 右背光）。 */
.wf-stop-rim-0 { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-rim-lit), white); }
.wf-stop-rim-1 { stop-color: var(--wf-c); }
.wf-stop-rim-2 { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-rim-shade), black); }

/* 碗內暗面（縱向：後緣最深 → 前緣略亮＝碗底反光）＝整個 3D 感的來源。 */
.wf-stop-in-0 { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-in-back), black); }
.wf-stop-in-1 { stop-color: color-mix(in srgb, var(--wf-c) var(--wf-in-front), black); }

/* 末層底光（放射漸層：中心暖光 → 邊緣全透明）。 */
.wf-stop-glow-0 { stop-color: color-mix(in srgb, var(--accent) var(--wf-underglow-a), transparent); }
.wf-stop-glow-1 { stop-color: color-mix(in srgb, var(--accent) 0%, transparent); }

.sv-wfunnel-body {
  filter: drop-shadow(0 2px 4px rgba(var(--shadow-rgb), var(--wf-shadow-a)));
}

/* 末層（本週精選）＝漏斗出口：同色相最深，再加一圈 accent 光暈收尾。 */
.sv-wfunnel-final .sv-wfunnel-body {
  filter:
    drop-shadow(0 2px 4px rgba(var(--shadow-rgb), var(--wf-shadow-a)))
    drop-shadow(0 0 9px color-mix(in srgb, var(--accent) var(--wf-final-glow), transparent));
}

/* 底光本身沒有邊界，靠放射漸層自己淡出（不加濾鏡，否則兩層柔化會糊成一片）。 */
.sv-wfunnel-underglow { pointer-events: none; }

/* 環口左上的 catch light（沿環口外橢圓的一小段弧，見 app.js bowlGlossPath()）。
   vector-effect 讓它不隨 viewBox 縮放變粗變細。 */
.sv-wfunnel-gloss {
  stroke: color-mix(in srgb, white var(--wf-gloss), transparent);
  stroke-width: 1.4;
  fill: none;
  stroke-linecap: round;
}

/* ---- 層側 icon 徽章（M3-10）：小巧線條風，描邊走 --accent，零填色 ----
   第二層齒輪＝過濾、第三層禁止圓章＝否決、末層星星＝精選（星星填色以示
   終點）。與碗身同一組 stagger 進場（掛在 .sv-wfunnel-layer 上）。 */
.sv-wfunnel-icon circle,
.sv-wfunnel-icon line,
.sv-wfunnel-icon path {
  fill: none;
  stroke: color-mix(in srgb, var(--accent) var(--wf-icon-a), transparent);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* 星星是終點徽章：填淺色底＋描邊，比另外兩顆再亮一階。 */
.sv-wfunnel-icon-star path {
  fill: color-mix(in srgb, var(--accent) 26%, transparent);
}

.sv-wfunnel-icon-link {
  stroke: color-mix(in srgb, var(--accent) 42%, transparent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* 同層兩級字階：檔數大字粗體、標籤與單位小字（站長 20:35：「現在一行等
   權重太平」）。字級是 viewBox 單位，等比縮放後桌機約 ×1.3、手機約 ×0.83。 */
/* 字級（viewBox 單位）：M3-12 第三輪迷你化（碗壁 38→19、rxMax 180→150）
   同步縮兩階 30/15/13 → 18/11/9，否則數字會頂出壓扁後的碗身。
   **同層兩級字階的關係不變**——數字仍然明顯大於層名（18 vs 11）且 800
   粗體，站長要的「層名與數字單行、數字仍粗體但不搶」成立。 */
.sv-wfunnel-text {
  font-size: 18px;
  font-weight: 800;
  fill: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

.sv-wfunnel-label {
  font-size: 11px;
  font-weight: 600;
  fill: var(--text-muted);
}

.sv-wfunnel-value {
  font-size: 18px;
  font-weight: 800;
  fill: var(--text-strong);
}

.sv-wfunnel-unit {
  font-size: 9px;
  font-weight: 600;
  fill: var(--text-muted);
}

/* 自頂向下 stagger 淡入＋輕微下落定位（比照卡片進場）。
   fill-mode 用 backwards 不用 both：`both` 會讓終格在動畫結束後繼續生效，
   而動畫層優先權高於一般宣告與 :hover（同一個坑已在 funnel.css
   .fn-signal-row 上實際踩到）。終值＝基礎樣式，視覺結果一模一樣。
   prefers-reduced-motion 由本檔全站規則壓成 0.01ms＝直接定格。 */
.sv-wfunnel-layer {
  animation: sv-wfunnel-in 0.5s var(--ease) backwards;
  animation-delay: calc(var(--wf-i, 0) * 90ms);
}

@keyframes sv-wfunnel-in {
  from { opacity: 0; transform: translateY(-7px); }
  to { opacity: 1; transform: none; }
}

/* ==========================================================================
   週選漏斗融入卡片流 wpk-*（FT-52 M3-12 第二輪，2026-08-07）
   --------------------------------------------------------------------------
   沿革（兩輪都被站長打槍過，把理由留著免得第三次再繞）：
   - M3-10 把漏斗縮成桌機 340px 靠左 → 右側空出一條大帶。
   - 第一輪補「本週精選迷你清單」在右欄 → 站長打槍：「好像多此一舉」。他是
     對的——清單的代號/名稱/適配分與下方股票卡**完全重複**，只隔一個滾動
     距離，是冗餘資訊，不是補位。整段已乾淨移除（無死碼）。
   - 本輪不新增任何內容：**讓漏斗自己變成卡片 grid 的一格**。空白消失的原因
     不是「填了東西」，而是「漏斗不再獨佔一整條 row」——它跟卡片排在同一個
     格線系統裡，剩餘欄位由卡片自動回填（grid-auto-flow: dense）。

   ---- 為什麼 span 不是寫死的 2（交辦假設「卡高 ~150px」只在一種模式成立）----
   - 第二輪（漏斗跨兩行 `grid-row: span N`）也已作廢：跨行的前提是漏斗比卡片
     高，而第三輪站長給了定稿 mockup——**卡片一律緊湊卡、六格等高**，漏斗
     縮扁到與卡片同高，跨行反而破壞等高，故整組 span 邏輯移除。

   實測（1280、正式 payload、harness 同一組量測，緊湊化之後）：
     漏斗 388×170.11px（撐滿 index 卡欄）／ 260×113.72px（撐滿 welcome 卡欄）
     六格（漏斗＋五卡）逐像素同高，高度＝下方 --wpk-cell-h。

   手機（<768px）：單欄直排、卡片同款緊湊版式，漏斗維持 272px 置中。
   等高相關的覆寫全部關在 768 斷點裡（單欄時等高沒有意義）。
   ========================================================================== */

/* 掛在卡片 grid 上：dense 讓比漏斗晚出場的卡片回填漏斗右側與後續空格，
   不會因為第一格被佔走就整批往後推。 */
.wpk-cardflow {
  grid-auto-flow: dense;
}

/* ---- 等高格線（第三輪，站長 mockup 定稿）----
   站長要的是「2 行 × 3 欄、6 格全部同高」的乾淨格線，所以第二輪那套
   `grid-row: span N`（漏斗跨兩行）整個拿掉——跨行的前提是漏斗比卡片高，
   而緊湊卡上線後兩者本來就該一樣高，跨行反而破壞等高。

   等高**不靠 grid 的 stretch**，靠一顆共用的 `--wpk-cell-h`：
   - 為什麼不用 stretch：stretch 會讓「某張卡展開後同列全部跟著長高」，
     直接違反站長的「展開時其他卡不動」。
   - 改用 `align-items: start`（自然高度）＋ 兩者同一個 `min-height`：
     未展開時每一格都剛好等於 --wpk-cell-h（六格逐像素同高），某張卡展開
     時只有它自己超過 min-height 往下長，同列其他格維持 --wpk-cell-h 不動。
   要調整整體高度只需要改這一顆變數。 */
.wpk-cardflow {
  align-items: start;
}

/* 漏斗的格位。align-self:start 仍是**防跑版的那顆螺絲**：任何一列因為卡片
   展開而長高時，漏斗格只會維持自己的高度，不會被 grid 拉長變形。 */
/* flex-direction:column 是刻意的：主軸轉成縱向後 `justify-content:center`
   負責**垂直置中**，而交叉軸（寬）預設 stretch 會讓漏斗撐滿格寬。
   用 row + align-items:center 會踩到「SVG 內建尺寸 300×150」這個經典坑——
   flex 主軸走 max-content，漏斗會停在 300px 不肯填滿 388px 的格子
   （harness 實測到 funnelW=300 vs cellW=388）。 */
.wpk-funnel-cell {
  align-self: start;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

@media (min-width: 768px) {
  /* 等高只在多欄時才有意義，所以整組關在 768 內；手機是單欄直排，
     每格自然高度即可（站長規格：手機單欄直排、卡片同款緊湊版式）。 */

  /* ---- 格高＝內容自然高＋呼吸感（第四輪，站長 08-07 追加令）----
     第三輪的 236px 是「先訂一個看起來夠的數字」，結果卡片中段空出一大塊
     （會員態卡片自然高 163px，等於憑空多 73px 白）。第四輪改成**由量測
     決定**：格高必須 ≥ 每一格的自然高（否則 min-height 撐不住，等高失效），
     所以取「全站最高一格的自然高 + 呼吸感」。

     1280 實測自然高（harness `assert_cell_height_hugs_content()` 每次跑都
     重量一次，這裡的數字不是寫死的信仰）：
       index   漏斗 170.11 ／ 會員卡 163（含 AI 判讀徽章）／ 訪客卡 131
               ／ 鎖卡 157.8
       welcome 卡 182（最高的一格，本變數就是被它決定的）／ 漏斗 113.72
               ／ 鎖卡 99.19
     取值還要蓋得住漏斗的**高度上限**（見下方 max-width: 420px 那段）：
     420 × 184.06/420 ＝ 184.06px。兩個下界取大再加呼吸感 ⇒ 186px。
     餘裕：1280 welcome 卡 4px、1280 index 漏斗 15.89px、1720 index 漏斗
     1.94px、index 會員卡 23px。

     ⚠️ 「把格高調小，漏斗佔比會跟著縮」是錯的直覺：漏斗是 SVG，高度由
     **欄寬 × viewBox 比例**決定（388 × 184.06/420 ＝ 170.11），與格高無關。
     所以第三輪那條「漏斗佔卡高 70-75%」的斷言在格高縮小後必然失守——它
     量的其實是「格高比漏斗高多少」，不是漏斗本身。第四輪已把它換成兩條
     真正的不變量：①漏斗高 === 欄寬推出來的幾何值（本體零位移）
     ②格高 − 最高自然高 ≤ 呼吸感上限（零大片留白）。 */
  .wpk-cardflow {
    --wpk-cell-h: 186px;
  }

  .wpk-cardflow > .signal-card,
  .wpk-cardflow > .w-weekly-card,
  .wpk-cardflow > .w-weekly-locked,
  .wpk-cardflow > .weekly-locked-card,
  .wpk-funnel-cell {
    min-height: var(--wpk-cell-h);
  }

  /* 卡內縱向分佈：卡頭在上、卡底列被 margin-top:auto 壓到底，中間留白由
     min-height 撐出來——展開時 .sv-card-body 插在卡底列之後往下長。 */
  .wpk-cardflow > .signal-card {
    display: flex;
    flex-direction: column;
  }

  .wpk-cardflow > .signal-card > .sv-card-foot {
    margin-top: auto;
  }

  /* 進了格子就當個正常格子住戶：撐滿欄寬（不再是 340px 的窄條配兩側留白），
     SVG 等比長高。margin 歸零由 grid gap 統一管間距。
     **這條關在 768 內**，手機維持 272px 置中的原樣。

     ---- 上限 420px＝漏斗的原生 viewBox 寬（第四輪補的那顆螺絲）----
     第三輪寫 `max-width: none`，等於讓漏斗高度 = 欄寬 × 0.4384 無上限成長。
     格高 236px 時剛好蓋得住（1720 欄寬 494px → 漏斗 216px < 236），所以這個
     缺陷一直沒被看見；第四輪把格高縮到內容高，它立刻現形：1720 六格變成
     [216, 184×5]，等高當場破掉（harness [S2c] 實測抓到）。
     根因是「一格的內容高由欄寬決定、卻要跟固定格高對齊」，所以修在源頭——
     漏斗不放大超過原生尺寸（viewBox 420×184.06）。推論出來的硬上限：
       漏斗高上限 = 420 × 184.06/420 = 184.06px < --wpk-cell-h
     1280（欄寬 388）與 welcome（欄寬 260）都在上限之下，畫面逐像素不變；
     只有 1720 這種超寬視窗漏斗停在 420px 置中（原本會被拉成 494px）。
     順帶把 768-900px 單欄那段也一起治好（欄寬 700px 時漏斗原本會長到
     307px，同樣撐破等高）。

     `width: 100%` 不是贅字，是**必要的**：交叉軸 auto margin 一旦生效，
     flex 的 stretch 就退場，漏斗會掉回 SVG 內建的 300px 寬（本輪實測 300 vs
     388，與第三輪註解裡記的同一個坑）。給了明確寬度之後 auto margin 才是
     單純的置中，max-width 也才咬得住。三行缺一不可。 */
  .wpk-funnel-cell > .sv-wfunnel {
    width: 100%;
    max-width: 420px;
    margin: 0 auto;
  }
}

/* ---------- 配置駕駛模式（2026-07-16）：橫幅＋鎖罩 ----------
   設定頁第一眼回答「現在誰在開車」：AI/策略駕駛（藍紫）vs 手動配置
   （中性）。鎖罩蓋在「選股規則」「股價範圍」兩卡上（值存 screen_params
   、策略生效時被整組蓋掉的那兩張），半透明＋模糊、點擊由中央按鈕引導
   切回手動，見 app.js renderDriveModeBanner()/applyDriveModeLocks()。 */
.drive-mode-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: var(--radius-md, 10px);
  margin-bottom: 14px;
  border: 1px solid var(--border);
}

.drive-mode-ai {
  background: linear-gradient(90deg, rgba(var(--brand-cyan-rgb), 0.10), rgba(148, 88, 255, 0.10));  /* theme-exempt: 148,88,255 為青→紫漸層中段色，無對應代幣 */
  border-color: rgba(var(--brand-cyan-rgb), 0.35);
}

.drive-mode-manual {
  background: rgba(var(--text-muted-rgb), 0.07);
}

.drive-mode-icon {
  font-size: 22px;
  flex: 0 0 auto;
}

.drive-mode-text {
  flex: 1 1 auto;
  min-width: 0;
}

.drive-mode-title {
  font-size: 14px;
  font-weight: 800;
  color: var(--text);
}

.drive-mode-sub {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* W5 M2（施工正本 docs/w5w6_spec_20260722.md）：站長設置透明標示——
   「站長設置＝AI 智選每日自動對齊（今日依據：X，日期）」／「站長手動
   配置中」，見 app.js renderDriveModeBanner()。獨立小徽章觀感（非純
   文字說明），故字級/字重與 .drive-mode-sub 區分。 */
.drive-mode-align-status {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--brand-cyan-text);
  margin-top: 4px;
}

.drive-mode-actions {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
  flex-wrap: wrap;
}

.drive-mode-btn {
  font-size: 12.5px;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: none;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}

.drive-mode-btn:hover {
  border-color: var(--text-muted);
}

.drive-mode-btn-primary {
  border-color: rgba(var(--brand-cyan-rgb), 0.55);
  color: var(--brand-blue);
  font-weight: 700;
}

.settings-card.drive-mode-locked {
  position: relative;
}

.drive-mode-lock-overlay {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(var(--scrim-rgb), 0.55);
  backdrop-filter: blur(1.5px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
}

.drive-mode-lock-msg {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
  font-size: 13px;
  color: var(--text);
  max-width: 320px;
  padding: 14px;
  background: rgba(var(--surface-scrim-rgb), 0.85);
  border: 1px solid rgba(var(--brand-cyan-rgb), 0.35);
  border-radius: var(--radius-md, 10px);
  /* sticky 置中：卡片很高時訊息盒跟著視窗，不會捲到看不到 */
  position: sticky;
  top: 20vh;
  bottom: 20vh;
}

.drive-mode-lock-icon {
  font-size: 20px;
}

@media (max-width: 640px) {
  .drive-mode-banner {
    flex-wrap: wrap;
  }
  .drive-mode-actions {
    width: 100%;
    justify-content: flex-end;
  }
}

/* 精選研究卡的漏斗標籤比今日訊號漏斗長（「候選池（外資買超Top30）」），
   容器又只有半寬，共用的 nowrap+ellipsis 會把字剪掉——精選卡允許換行
   完整顯示（見 app.js renderFeaturedFunnelRow()）。 */
.sv-funnel-row-featured .sv-funnel-stage-label {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.35;
}

.sv-recap-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}

.sv-recap-chip {
  display: inline-block;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 12px;
  line-height: 1.5;
}

.sv-recap-chip-strategy {
  color: var(--brand-blue);
  border-color: rgba(var(--brand-blue-rgb), 0.35);
  background: var(--accent-bg);
  font-weight: 600;
}

.sv-recap-changed {
  font-size: 11.5px;
  color: var(--warn-fg);
}

/* ==========================================================================
   盤中快訊直播流（規格 M2，任務#78「鷹眼」新增；版式追加規格 2026-07-10）
   --------------------------------------------------------------------------
   首頁今日訊號 tab 漏斗條之下的事件時間軸，見 app.js
   renderIntradayFeed()/loadIntradayFeed()。**單列網格制**（見
   docs/design_system.md §7「時間軸流列版式」正本）：每列固定
   時間/chip/股名/數值/說明五欄，同寬同高、禁止說明句換行獨立成段——
   grid-template-columns 定寬，超長內容一律截斷+title，不擠版面。
   ========================================================================== */

.sv-intraday-feed {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: 14px;
  background: var(--bg-2);
}

.sv-intraday-feed-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}

.sv-intraday-feed-title {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
}

.sv-intraday-feed-status {
  font-size: 11.5px;
  color: var(--text-faint);
}

.sv-intraday-list {
  display: flex;
  flex-direction: column;
  max-height: 280px;
  overflow-y: auto;
}

/* 五欄定寬網格：時間｜事件chip｜股名代號｜數值｜說明。所有列同一組欄寬，
   逐列對齊——這是版式追加規格的核心要求，禁止改回 flex-wrap 自由排列。 */
.sv-intraday-item {
  display: grid;
  /* 股名欄 108→176px（2026-07-16 使用者回饋）：「元大台灣50正2(00631L)」
     這種長名 ETF 在 108px 被剪成「元大台灣50正2(…」，右側說明欄（1fr）
     空間充裕，讓給股名完整顯示。行動版（480px 斷點）股名本來就是 1fr，
     不受影響。 */
  grid-template-columns: 42px 132px minmax(0, 176px) 76px minmax(0, 1fr);
  align-items: center;
  column-gap: 10px;
  font-size: 12.5px;
  padding: 7px 4px;
  min-height: 32px;
  border-bottom: 1px solid var(--border-faint, var(--border));
}

.sv-intraday-item:last-child {
  border-bottom: none;
}

/* 大盤級事件（index_move）整列淡底區隔，欄位對齊維持不變。 */
.sv-intraday-item-index {
  background: rgba(var(--brand-cyan-rgb), 0.05);
  border-radius: 6px;
}

/* 嚴重度分級（規格 M3，任務#94新增；見 intraday_signals.EVENT_SEVERITY）：
   警報醒目／提示低調。刻意避開紅綠——紅綠只保留給 .sv-intraday-value 表達
   漲跌方向，分級一律用琥珀（警報）／藍（注意）／降低透明度（提示，不畫線）
   表達「這則多值得馬上看」，不與「這支股票漲了還是跌了」的語意混淆。
   在 .sv-intraday-item-index 之後宣告：index_move 本身也是 alert 級，同時
   套用兩個 class 時琥珀色左框線優先，維持「警報」視覺一致性。 */
.sv-intraday-item-sev-alert {
  border-left: 3px solid var(--warn-fg);
  background: rgba(var(--watch-rgb), 0.07);
  padding-left: 7px;
}

.sv-intraday-item-sev-watch {
  border-left: 3px solid var(--brand-blue);
  padding-left: 7px;
}

.sv-intraday-item-sev-info {
  opacity: 0.78;
}

.sv-intraday-time {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  font-family: "SF Mono", "Consolas", "Menlo", monospace;
  white-space: nowrap;
}

.sv-intraday-chip {
  display: block;
  width: 100%;
  box-sizing: border-box;
  background: rgba(var(--brand-blue-rgb), 0.12);
  border: 1px solid rgba(var(--brand-blue-rgb), 0.32);
  color: var(--brand-blue);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 11px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sv-intraday-chip-limit_touch {
  background: rgba(var(--watch-rgb), 0.14);
  border-color: rgba(var(--watch-rgb), 0.4);
  color: var(--warn-fg);
}

.sv-intraday-chip-strategy_hit {
  background: rgba(var(--brand-violet-rgb), 0.16);
  border-color: rgba(var(--brand-violet-rgb), 0.42);
  color: var(--tag-violet);
}

.sv-intraday-chip-index_move {
  background: rgba(var(--brand-cyan-rgb), 0.1);
  border-color: rgba(var(--brand-cyan-rgb), 0.3);
  color: var(--brand-cyan-text);
}

.sv-intraday-chip-trump_news {
  background: rgba(var(--up-rgb), 0.12);
  border-color: rgba(var(--up-rgb), 0.32);
  color: var(--up);
}

.sv-intraday-stock {
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sv-intraday-stock:hover {
  color: var(--brand-cyan-text);
}

.sv-intraday-stock-empty::before {
  content: "—";
  color: var(--text-faint);
}

.sv-intraday-value {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  text-align: right;
  white-space: nowrap;
}

.sv-intraday-headline {
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-decoration: none;
}

a.sv-intraday-headline:hover {
  color: var(--brand-cyan-text);
  text-decoration: underline;
}

.sv-intraday-empty {
  padding: 10px 2px;
}

.sv-intraday-disclaimer {
  margin-top: 8px;
  font-size: 10.5px;
  color: var(--text-faint);
}

/* ---------- 盤中鷹眼精簡橫條（任務#154 第三追加科目，取代原任務#130
   落點1 的三張 16:10 大卡）----------
   起因：原版每卡一張大圖＋標題＋文案，整條高達 400px+，這是「非開盤
   空檔的行銷填充」而非核心內容，卻把訊號卡列表擠到 1080p 首屏摺線下，
   本末倒置（2026-07-12 使用者截圖回饋）。改為單列三欄 compact 卡：左側
   72px 方形縮圖（沿用 ill_24~26 素材，object-fit:cover 裁切成方形不
   變形）＋右側標題一行/文案最多兩行（line-clamp:2；卡高由 72px 縮圖
   主導，兩行文案 50px 內不增高——2026-07-12 使用者回饋單行截斷吃掉
   重點資訊後改制，title tooltip 保留當極窄寬度後備），整條壓到 ~140px
   （見 .sv-hawkeye-bar 內距估算）。右上角「收合」把整條再壓成一行，
   狀態存 localStorage（見 app.js isHawkeyeCollapsed()/
   setHawkeyeCollapsed()）跨次造訪記住。渲染時機（非開盤 或 快訊流為空
   才顯示，開盤有事件時讓位給真正的快訊流）沿用 app.js
   renderIntradayFeed() 既有邏輯，未改動。 */
.sv-hawkeye-bar {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  margin-bottom: 14px;
  background: var(--bg-2);
}

.sv-hawkeye-header-full {
  margin-bottom: 8px;
}

.sv-hawkeye-toggle {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-muted);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 150ms var(--ease), color 150ms var(--ease);
}

.sv-hawkeye-toggle:hover {
  border-color: var(--brand-cyan);
  color: var(--brand-cyan-text);
}

.sv-hawkeye-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.sv-hawkeye-card {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px;
}

.sv-hawkeye-thumb-wrap {
  flex: 0 0 auto;
  width: 72px;
  height: 72px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--bg-1);
}

.sv-hawkeye-thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sv-hawkeye-text {
  min-width: 0; /* 讓子層 ellipsis 生效，flex item 預設 min-width:auto 會撐爆 */
  flex: 1 1 auto;
}

.sv-hawkeye-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sv-hawkeye-desc {
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  cursor: default;
}

/* 收合行：預設隱藏，只有 .sv-hawkeye-bar.sv-hawkeye-collapsed 時顯示，
   取代 header-full／row 整條縮成一行文字按鈕，點擊展開。 */
.sv-hawkeye-collapsed-line {
  display: none;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  padding: 0;
  color: var(--text-muted);
  font-size: 12.5px;
  cursor: pointer;
}

.sv-hawkeye-collapsed-line:hover {
  color: var(--brand-cyan-text);
}

.sv-hawkeye-bar.sv-hawkeye-collapsed {
  padding: 8px 14px;
}

.sv-hawkeye-bar.sv-hawkeye-collapsed .sv-hawkeye-header-full,
.sv-hawkeye-bar.sv-hawkeye-collapsed .sv-hawkeye-row {
  display: none;
}

.sv-hawkeye-bar.sv-hawkeye-collapsed .sv-hawkeye-collapsed-line {
  display: block;
}

/* 375px：維持 compact 高度，三欄改橫向滑動（不堆疊——堆疊會讓高度隨欄
   數線性增加，違背「壓縮到摺線上」的初衷），每卡露出下一張卡片一角當
   「還可以滑」的提示。 */
@media (max-width: 480px) {
  .sv-hawkeye-row {
    display: flex;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    gap: 8px;
  }
  .sv-hawkeye-card {
    flex: 0 0 82%;
    scroll-snap-align: start;
  }
}

/* 行動版降為兩行制：上排 時間/chip/股名/數值 四欄，下排說明獨占一整行
   （淡色，可換行）——欄仍對齊，只是說明改到第二行而非硬擠在同一行。 */
@media (max-width: 480px) {
  .sv-intraday-item {
    grid-template-columns: 38px 104px minmax(0, 1fr) 64px;
    grid-template-areas:
      "time chip stock value"
      "headline headline headline headline";
    row-gap: 2px;
    padding: 8px 4px;
  }
  .sv-intraday-time { grid-area: time; }
  .sv-intraday-chip { grid-area: chip; font-size: 10.5px; }
  .sv-intraday-stock { grid-area: stock; }
  .sv-intraday-value { grid-area: value; }
  .sv-intraday-headline {
    grid-area: headline;
    white-space: normal;
    font-size: 11px;
    line-height: 1.4;
  }
}

/* ---- 選股紀錄表格：迷你漏斗欄 ---- */
.run-funnel-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
}

.run-funnel-chain {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  white-space: nowrap;
}

.run-funnel-strategy-chip {
  display: inline-block;
  background: var(--accent-bg);
  color: var(--brand-blue);
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 10.5px;
  font-weight: 600;
}

.run-funnel-missing {
  font-size: 11.5px;
  color: var(--text-faint);
}

/* ---- 漏斗被刷樣本彈窗：殼複用 .info-modal-overlay / .info-modal-card ---- */
.funnel-dropped-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
  max-height: 50vh;
  overflow-y: auto;
}

.funnel-dropped-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  text-decoration: none;
  transition: border-color 120ms var(--ease);
}

.funnel-dropped-row:hover {
  border-color: var(--brand-blue);
}

.funnel-dropped-stock {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

.funnel-dropped-reason {
  font-size: 12px;
  color: var(--text-muted);
  text-align: right;
}

/* ---------- 管理台：帳戶刪除防呆彈窗（admin.js，任務新增） ----------
   殼複用既有 .info-modal-overlay / .info-modal-card（見該 class 定義處
   docstring：「個股 AI 深度體檢彈窗同款」的既有共用模式），這裡只補內容
   專屬樣式。 */

.admin-delete-summary {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin: 12px 0;
  font-size: 13px;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.admin-delete-summary b {
  color: var(--text);
}

.admin-delete-warn {
  color: var(--danger);
  font-size: 12.5px;
  margin: 10px 0 4px;
}

.admin-delete-confirm-label {
  font-size: 12.5px;
  color: var(--text-muted);
  display: block;
  margin: 10px 0 4px;
}

.admin-delete-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

.admin-delete-danger-btn {
  background: var(--danger);
  color: var(--on-accent);
  border: none;
  border-radius: var(--radius-sm);
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.admin-delete-danger-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.admin-delete-cancel-btn {
  background: var(--bg-2);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 8px 16px;
  font-size: 13px;
  cursor: pointer;
}

.admin-user-deleted-row {
  opacity: 0.55;
}

.admin-user-row-actions {
  display: flex;
  gap: 6px;
  align-items: center;
}

/* 列內操作鈕四款統一同尺寸（2026-07-15 使用者回饋：降級/贈送PRO 誤用
   .btn-save 主 CTA 樣式，比同列刪除鈕大顆突兀）——語意只靠 hover 色區分。 */
.admin-user-delete-btn,
.admin-user-restore-btn,
.admin-user-demote-btn,
.admin-user-grant-btn {
  border: 1px solid var(--border-strong);
  background: var(--bg-2);
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}

.admin-user-delete-btn:hover {
  color: var(--danger);
  border-color: var(--danger);
}

.admin-user-restore-btn:hover,
.admin-user-grant-btn:hover {
  color: var(--brand-cyan-text);
  border-color: var(--brand-cyan);
}

.admin-user-demote-btn:hover {
  color: var(--warn-fg);
  border-color: var(--warn-fg);
}

/* ---------- 管理台：AI 配額樹（總量→頁→功能，admin.js，任務新增） ---------- */

.admin-quota-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-end;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 14px 16px;
  margin-bottom: 14px;
}

.admin-quota-total-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.admin-quota-total-field label {
  font-size: 12px;
  color: var(--text-muted);
}

.admin-quota-tree {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 14px;
}

.admin-quota-page {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.admin-quota-page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  cursor: pointer;
  user-select: none;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
}

.admin-quota-page-head:hover {
  background: var(--card-bg-hover);
}

.admin-quota-page-caret {
  color: var(--text-faint);
  transition: transform 150ms var(--ease);
  font-size: 11px;
}

.admin-quota-page.collapsed .admin-quota-page-caret {
  transform: rotate(-90deg);
}

.admin-quota-page-body {
  border-top: 1px solid var(--border);
}

.admin-quota-page.collapsed .admin-quota-page-body {
  display: none;
}

.admin-quota-feature-row {
  display: grid;
  grid-template-columns: 1fr 90px 90px 140px;
  gap: 10px;
  align-items: center;
  padding: 8px 14px;
  font-size: 12.5px;
  border-top: 1px solid var(--border);
}

.admin-quota-feature-row:first-child {
  border-top: none;
}

.admin-quota-feature-label {
  color: var(--text);
}

.admin-quota-feature-limit-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.admin-quota-feature-limit-wrap span {
  font-size: 10.5px;
  color: var(--text-faint);
}

.admin-quota-limit-input {
  width: 100%;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 4px 6px;
  font-size: 12.5px;
}

.admin-quota-limit-input::placeholder {
  color: var(--text-faint);
}

.admin-quota-used-today {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.admin-quota-used-bar {
  height: 6px;
  border-radius: 4px;
  background: var(--bg-2);
  overflow: hidden;
}

.admin-quota-used-bar-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--brand-gradient);
}

/* ==========================================================================
   插畫二批佈線（任務#123，2026-07-11）：以下三個共用元件供多頁重用，見各
   引用處註解。命名沿用既有 `sv-` 前綴慣例（同 ai_progress_modal.css 的
   `.sv-ai-progress-*`），與各頁專屬 class（`bt-*`/`w-*`/`pf-*`…）分開的
   全域設計系統層級元件。
   ========================================================================== */

/* ---------- Pro 付費牆解鎖卡（.sv-paywall-card，任務#123 新增） ----------
   全域可重用元件：圖 16:10 裁切滿版置頂＋內文區塊，本批只接
   backtest.html 策略實驗室付費牆一處，未來其他頁的付費牆/fog 卡可直接
   套用同一組 class，不必重新設計版型。 */
.sv-paywall-card {
  max-width: 560px;
  margin: 56px auto;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  text-align: center;
}

.sv-paywall-img-wrap {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--bg-2);
}

.sv-paywall-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sv-paywall-body {
  padding: 26px 30px 32px;
}

.sv-paywall-body h2 {
  margin: 0 0 12px;
  font-size: 20px;
  color: var(--text);
}

.sv-paywall-body p {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.7;
  margin: 0 0 8px;
}

.sv-paywall-hint {
  display: inline-block;
  margin-top: 6px;
  color: var(--brand-cyan-text);
  font-weight: 700;
  font-size: 13.5px;
}

/* ---------- 頁首品牌插畫橫幅（.sv-page-hero，任務#123 新增；任務#129
   改版為「左文右圖分欄」版型，修正主體被裁問題） ----------
   任務#129 根因：素材原生比例（ill_15 900x559≈1.61:1／ill_14 1400x593≈
   2.36:1）與本容器在寬螢幕下的「有效比例」（寬度隨版心可達 1500+px、
   高度卻鎖死 220~240px，有效比例常跑到 5~7:1）差距遠超過設計系統插畫節
   訂的 35% 容忍值，原本 object-fit:cover 硬裁必然把主體（機器人頭部）
   裁出畫面。

   **版型演進**：第一版改用「模糊延伸」（背景 blur+前景 contain），但
   指揮官實看 live 站後打回——超寬容器下模糊背景變成兩塊無意義糊色塊、
   原圖被 contain 縮成中央小方塊，比例觀感依然怪；改採 hero 類**首選
   分欄（手法 B）**，模糊延伸降為受限手法（見
   docs/design_system.md 插畫節）。

   分欄版型：`.sv-page-hero` 本身是 flex row，兩個子元素：
   - `.sv-page-hero-text`（flex:1，佔剩餘空間）：品牌深藍漸層底＋標題／
     副標，一般文字排版，不再是疊在圖片上的半透明 overlay。
   - `.sv-page-hero-visual`（flex:none，寬度＝`height * aspect-ratio`）：
     `aspect-ratio` 由模板內聯樣式設成該頁插畫的**精確原生比例**（例：
     kline_guide.html 設 `900/559`、arena.html 設 `1400/593`），使
     `object-fit:cover` 幾乎零裁切——高度落在 200~240px 時，寬度自然落在
     350~570px 區間（非固定 % 寬，用 aspect-ratio 反推寬度，跟容器整體
     寬度無關，因此不會被寬螢幕拉爆比例）。左緣疊一層水平漸層
     `.sv-page-hero-visual::before`（品牌深藍→透明），讓圖與左側文字區
     的漸層底無縫融合，不出現硬接縫。
   `.sv-page-hero-sm` 修飾類＝較矮版本（kline_guide.html 用，220px；
   預設 240px 供 arena.html 用）。480px 以下改「上文下圖」堆疊（見下方
   media query），圖框維持原生比例、高度收到 150/130px，不強制填滿寬度
   （避免又走回固定寬高比例失配的老路）。 */
.sv-page-hero {
  position: relative;
  width: 100%;
  height: 240px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin: 0 0 22px;
  display: flex;
  align-items: stretch;
  background: linear-gradient(120deg, #0a1830 0%, #0e2248 55%, #123268 100%);  /* theme-exempt-permanent: 品牌插畫接縫——底色須與深藍插畫素材同色，四主題一律深藍 */
}

.sv-page-hero.sv-page-hero-sm {
  height: 220px;
}

.sv-page-hero-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 20px 10px 20px 28px;
}

.sv-page-hero-visual {
  position: relative;
  flex: 0 0 auto;
  height: 100%;
  max-width: 60%;
  overflow: hidden;
  /* aspect-ratio 由模板內聯樣式指定為該頁素材原生比例，見上方註解 */
}

.sv-page-hero-visual::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(90deg, #0e2248 0%, rgba(14, 34, 72, 0) 24%);  /* theme-exempt-permanent: 品牌插畫接縫——同 .sv-page-hero 底色 */
  pointer-events: none;
}

.sv-page-hero-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 38%;
}

.sv-page-hero-title {
  /* theme-exempt-permanent（2026-07-29 站長抓包「字被吃掉」修類）：橫幅底是
     永久豁免的品牌深藍（#0e2248 系），文字若吃主題 token 在淺色主題會變
     深字疊深底。豁免底＝豁免字——釘回深色版原亮字，四主題一律亮字。 */
  color: #e8eefb;
  font-size: clamp(19px, 1.6vw + 12px, 28px);
  font-weight: 800;
  margin: 0 0 6px;
}

.sv-page-hero-sub {
  color: #8fa3c8; /* theme-exempt-permanent: 同上，豁免底＝豁免字 */
  font-size: 13px;
  line-height: 1.5;
  max-width: 46ch;
}

@media (max-width: 480px) {
  .sv-page-hero {
    flex-direction: column;
    align-items: center;
    height: auto;
    padding-bottom: 4px;
  }
  .sv-page-hero-text {
    width: 100%;
    max-width: 100%;
    padding: 14px 16px 10px;
  }
  .sv-page-hero-visual {
    width: auto;
    max-width: 92%;
    height: 150px;
    flex: none;
    margin: 0 0 14px;
    border-radius: var(--radius);
  }
  .sv-page-hero.sv-page-hero-sm .sv-page-hero-visual {
    height: 130px;
  }
  .sv-page-hero-visual::before {
    background: linear-gradient(90deg, #0e2248 0%, rgba(14, 34, 72, 0) 16%);  /* theme-exempt-permanent: 品牌插畫接縫 */
  }
}

/* ---------- 窄橫幅修飾類（.sv-page-hero-xs，任務#157 案4新增） ----------
   首頁「透明漏斗理念卡」原本吃 240px 高的完整 `.sv-page-hero`（標題＋
   副標＋大圖），在「今日訊號」首屏預算整治裡是最大的裁剪對象——這裡加
   一個獨立修飾類，只影響加了 `.sv-page-hero-xs` 的實例（目前只有
   index.html 一處），kline_guide/backtest/arena 三頁仍用原本
   `.sv-page-hero`/`.sv-page-hero-sm`，不受影響。壓成 ≤120px 的單行窄
   橫幅：小縮圖（用原圖 aspect-ratio 反推寬度，同一張素材、只是整體更
   小）＋一行標語（超長時用 ellipsis 收尾，不擠爆高度）＋「了解透明漏斗
   →」連結，維持可點擊、不完全犧牲導流。480px 以下沿用同一顆橫向版型
   （刻意不落回基礎 `.sv-page-hero` 的「上文下圖」直排 media query，直排
   會讓 xs 版變得比原本還高，違背「窄橫幅」的設計意圖），只再縮小字級與
   間距。

   高度 52px（與行動版原本用的高度一致，桌機/手機統一）＋margin-bottom
   8px：任務#157 案4 首屏預算硬驗收（1920×1080 免捲動見第一排訊號卡評分
   圈）實測時，僅靠原本 60px/12px 仍差約 28px（今日 `today-funnel-row`／
   `today-intraday-feed` 兩塊即時內容比#154量測當時多撐出不少高度，不在
   本案裁剪授權範圍內，故不動），於是把授權範圍內三個目標（本橫幅／KPI
   卡／市場脈搏條）再壓緊一階，不動範圍外元件。 */
.sv-page-hero.sv-page-hero-xs {
  height: 52px;
  align-items: center;
  margin-bottom: 8px;
}

.sv-page-hero-xs .sv-page-hero-visual {
  height: 100%;
  max-width: none;
  flex: 0 0 auto;
}

.sv-page-hero-xs .sv-page-hero-visual::before {
  background: linear-gradient(90deg, #0e2248 0%, rgba(14, 34, 72, 0) 55%);  /* theme-exempt-permanent: 品牌插畫接縫 */
}

.sv-page-hero-xs .sv-page-hero-text {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 16px;
  min-width: 0;
}

.sv-page-hero-xs .sv-page-hero-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.sv-page-hero-xs-link {
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 700;
  color: #00d4ff; /* theme-exempt-permanent: 豁免深底＝豁免亮字（=深色版 --brand-cyan） */
  white-space: nowrap;
  text-decoration: none;
}

.sv-page-hero-xs-link:hover {
  text-decoration: underline;
}

@media (max-width: 480px) {
  .sv-page-hero.sv-page-hero-xs {
    flex-direction: row;
    align-items: center;
    height: 52px;
    padding-bottom: 0;
  }
  .sv-page-hero-xs .sv-page-hero-visual {
    width: auto;
    max-width: none;
    height: 100%;
    margin: 0;
    border-radius: 0;
  }
  .sv-page-hero-xs .sv-page-hero-text {
    width: auto;
    max-width: none;
    padding: 0 10px;
  }
  .sv-page-hero-xs .sv-page-hero-title {
    font-size: 11.5px;
  }
  .sv-page-hero-xs-link {
    font-size: 11px;
  }
}

/* ---------- 通用空狀態插畫（.sv-empty-illus-img，任務#123 新增） ----------
   包在既有 `.empty-state` 容器內：圖 160~200px 寬置中＋原空狀態文字在下，
   跨頁共用（portfolio 尚無持股／my_dividends 尚無持股皆套同一顆 class），
   語氣延續原本溫和的空狀態文案，插畫只是加值不是取代文字。 */
.sv-empty-illus-img {
  display: block;
  width: 180px;
  max-width: 60%;
  height: auto;
  margin: 0 auto 14px;
  border-radius: var(--radius-sm);
}

/* ---------- 審核中全頁遮罩插畫（.suspended-overlay-illus，任務#123 新增，
   nav.js renderApprovalOverlay 待審核狀態用） ----------
   沿用既有 `.suspended-overlay-icon`（帳號停權/審核遮罩共用殼）同一個
   位置，僅待審核（pending）狀態換成插畫；婉拒（rejected）狀態維持原本
   ✖ 文字圖示，不套插畫（情緒不同，插畫語氣是溫和等待，不適合婉拒場景）。 */
.suspended-overlay-illus-wrap {
  width: 100%;
  max-width: 240px;
  aspect-ratio: 16 / 10;
  margin: 0 auto 12px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg-2);
}

.suspended-overlay-illus {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.admin-quota-save-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
}

/* ---------- 選股日分組手風琴＋刪除/還原（需求A，2026-07-15） ----------
   首頁「今日訊號」近 30 個選股日按日收折、績效 tab「近期訊號結算進度」
   共用同一組 class（收折卡概念抄 admin_data_status.css .ds-page-card：
   .collapsed 時 caret 轉 -90deg、body 隱藏）。 */
.signal-date-group {
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 12px;
  overflow: hidden;
  background: var(--card-bg);
}

.signal-date-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  cursor: pointer;
  user-select: none;
}

.signal-date-header:hover {
  background: rgba(var(--surface-tint-rgb), 0.03);
}

.signal-date-caret {
  flex: none;
  font-size: 11px;
  color: var(--text-faint);
  transition: transform 150ms ease;
}

.signal-date-group.collapsed .signal-date-caret {
  transform: rotate(-90deg);
}

.signal-date-title {
  font-weight: 700;
  font-size: 14px;
  color: var(--text);
  /* 2026-07-18 使用者回報手機「擠壓 排版不好看」：分組頭單行塞五個元素
     （caret+日期+示範chip+檔數+基準日長註記），375px 下日期被 flex 壓縮
     斷行成三行豆腐乾直排。日期是錨點資訊，永不斷行。 */
  white-space: nowrap;
}

.signal-date-count {
  font-size: 12px;
  color: var(--text-faint);
  white-space: nowrap;
}

/* 手機分組頭擠壓根治（同上 2026-07-18 回報）：幾何上 375px 內容寬 ~347px
   放不下五元素單行（基準日註記文案就 200px+），改允許換行——第一行=
   caret+日期+示範chip+檔數（合計 ~280px 站得下），基準日註記/還原鈕自動
   折到第二行整行顯示，資訊完整不擠壓。桌機（>640px）維持原單行。 */
@media (max-width: 640px) {
  .signal-date-header {
    flex-wrap: wrap;
    row-gap: 6px;
  }
  .signal-date-header .data-as-of-chip {
    flex-basis: 100%;
    order: 10;
    white-space: normal;
    line-height: 1.5;
  }
  .signal-date-header .signal-restore-btn {
    margin-left: 0;
    order: 11;
  }
}

.signal-date-body {
  padding: 10px 14px 14px;
}

.signal-date-group.collapsed .signal-date-body {
  display: none;
}

/* 組 header 右側「還原本次選股」鈕：ghost 樣式，靠右推開 */
.signal-restore-btn {
  margin-left: auto;
  flex: none;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--accent-text);
  border-radius: 6px;
  padding: 3px 10px;
  font-size: 12px;
  cursor: pointer;
}

.signal-restore-btn:hover {
  background: var(--accent-bg);
}

/* 卡片操作列「刪除」小按鈕：與 .btn-ai-review/.btn-add-watchlist 並列
   （同 padding/字級，margin-left 比照 .btn-add-watchlist 的 8px——不能用
   auto，flex-end 容器裡 auto margin 會把左鄰按鈕整排推去左緣）；預設低調
   ghost，二段確認態轉紅提醒。 */
.signal-del-btn {
  margin-left: 8px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-faint);
  border-radius: var(--radius-sm);
  padding: 5px 11px;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}

.signal-del-btn:hover {
  color: var(--danger);
  border-color: var(--danger);
}

.signal-del-btn.confirming {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--danger-bg);
  font-weight: 700;
}

/* 績效 tab 分組容器：與統計區塊間距一致 */
.perf-recent-groups {
  margin-top: 4px;
}

/* ==========================================================================
   本週 AI 精選研究首頁卡（Signova F3 前端，計畫正本
   docs/featured_report_plan_20260715.md §4）：唯讀展示 GET /api/v1/
   featured/weekly（api/featured.py），渲染邏輯見 app.js
   loadFeaturedReportCard()/renderFeaturedReportCard()。卡片本體與內層每檔
   卡都借用既有 `.settings-card` 基礎視覺（背景/邊框/圓角/陰影，見該
   class 定義），漏斗展開沿用 `.sv-funnel-row`/`.sv-funnel-stage` 與
   `.settings-flow-toggle`/`.settings-flow-body` 既有摺疊機制、is_fallback
   徽章沿用 `.advisor-summary-chip.is-fallback`——本節只補版面排列，不重複
   定義視覺基礎，維持全站「透明漏斗」版式一致。
   ========================================================================== */

.featured-card {
  margin-bottom: 20px;
}

.featured-card-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 4px;
}

.featured-card-header .settings-card-title {
  margin: 0;
}

.featured-report-intro {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 10px 0 16px;
}

.featured-pick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}

.featured-pick-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.featured-pick-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.featured-pick-stock {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}

.featured-pick-reason {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

.featured-pick-btn {
  align-self: flex-start;
  text-decoration: none;
}

/* ==========================================================================
   手機首屏重排＋點擊目標（2026-07-18 QA a13：訊號卡埋 3 螢幕深、按鈕過小）
   --------------------------------------------------------------------------
   #app 本來就是 flex column（見頂部 #app 定義），手機下用 order 把三塊
   「市場氛圍」內容（市場脈搏板/透明漏斗橫幅/本週精選卡）沉到主內容
   （tabs＋訊號卡）之後、footer 之前——核心產出（今日訊號）進首屏。
   桌機版順序不動。
   ========================================================================== */
@media (max-width: 640px) {
  /* #home-pulse-board 自 #204（2026-08-17）起首頁已不再掛載（速覽列與加權指數
     大卡重複，見 index.html 三處註解包裝），這個選擇器目前不匹配任何節點——
     刻意留著：速覽列是「藏不刪」，掛載點放回來時這條排序規則要跟著回來。
     #featured-report-card 同理（#176d 已下架）。 */
  #home-pulse-board,
  #app > .sv-page-hero-xs,
  #featured-report-card {
    order: 1;
  }
  #app > footer {
    order: 2;
  }

  /* 主要互動元件 44px 點擊目標（Apple HIG / WCAG 2.5.8）：只挑導覽/
     分頁/表單控制這類獨立控件，卡片內小 chip 不動避免破版。 */
  .tab-btn,
  .btn-run,
  .quick-filter-bar select,
  #tab-settings select,
  #tab-settings input[type="text"],
  #tab-settings input[type="number"],
  .toggle-row {
    min-height: 44px;
  }
  /* 44px 補漏（QA R3 P2-8，2026-07-18）：上一批只做了「外框控件」（分頁/
     選單/設定表單），漏掉**手機使用者最常按的**訊號卡動作鈕（實測僅
     24-28px）、篩選 checkbox（~20px）與漢堡鈕（38×34）——QA 棒17 抓到，
     且比前輪評審更嚴格。這三處才是首頁的主要互動點。 */
  .btn-ai-review,
  .btn-add-watchlist,
  .signal-del-btn,
  .signal-restore-btn {
    min-height: 44px;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  /* 並排動作鈕加大間距，防手指誤觸相鄰鈕（44px 目標的配套）。 */
  .signal-card .card-actions,
  .signal-card .row-actions {
    gap: 10px;
  }
  .checkbox-group label {
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .nav-toggle-label {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .toggle-row {
    align-items: center;
    cursor: pointer;
  }
}

/* ==========================================================================
   統計卡＋資料表＋膠囊「質感層」共用代幣與共用皮膚（#193，2026-08-17）

   為什麼在 app.css：/market 的統計卡、/institutional 的排行表、/etf 的日報
   表、/futures 的散戶多空比表…各頁本來就各有一套 class（`.stat-card`、
   `.inst-ranking-table`、`.etf-overview-table`、`.ind-ranking-table`、
   `.tbs-table`、共用的 `.sv-table`），沒有一顆共用 class 可以一次改完。硬
   把頁面 class 搬進 app.css 會反過來被各頁 css（載入順序在後、specificity
   相同）蓋掉，改了等於沒改。所以這裡採**代幣層共用、套用層各自呼叫**：質
   感的「配方」（漸層／高光／柔影／格線／斑馬／膠囊底）集中在這一段定義一
   次，各頁 css 只寫 `background: var(--sv-card-sheen), var(--card-bg)` 這種
   一行呼叫——日後要調整全站質感只動這一段，不必再逐頁翻。

   四主題規則：深色底吃「白色高光」（rgba(255,255,255,α)）；淺色底的卡面本
   身就是白的、再疊白光等於沒有，所以淺色版一律翻成「上白下微深」——底部壓
   一層 --surface-tint-rgb（淺色主題是 15,23,42）造出落地感。這是本專案既有
   慣例（見 portfolio.css `--cal-gloss-rgb`、market.css `.index-hero` 的強度
   旋鈕），不是本段自創。
   ========================================================================== */

:root {
  /* ---- (1) 卡面：漸層 + 內緣高光 + 柔影 ---- */
  --sv-card-sheen: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.10),
    rgba(255, 255, 255, 0.028) 44%,
    rgba(255, 255, 255, 0) 76%
  );
  --sv-card-inset: inset 0 1px 0 rgba(255, 255, 255, 0.16);
  --sv-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 10px 28px rgba(0, 0, 0, 0.26);
  --sv-card-shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.34), 0 18px 44px rgba(0, 0, 0, 0.40);
  --sv-card-border-hover: rgba(255, 255, 255, 0.20);
  /* hover 微上浮的位移量；prefers-reduced-motion 由下方媒體查詢歸零。 */
  --sv-lift: -2px;

  /* ---- (2) 資料表：表頭底／分隔線／斑馬／列高亮／橫捲暗示 ---- */
  --sv-thead-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
  --sv-thead-rule: rgba(255, 255, 255, 0.16);
  --sv-row-line: rgba(255, 255, 255, 0.055);
  --sv-row-zebra: rgba(255, 255, 255, 0.018);
  --sv-row-hover: rgba(255, 255, 255, 0.06);
  /* 手機橫向捲動時左右緣的漸層暗示（background-attachment: local 老招，
     零 JS、零 scroll 監聽）。 */
  --sv-scroll-shade: rgba(0, 0, 0, 0.30);
  /* 紅綠語意大數字（買賣超那類）的極淡語意底暈強度。 */
  --sv-net-tint: 0.085;

  /* ---- (3) 膠囊（檢視切換／區間／篩選 pills、下拉） ---- */
  --sv-pill-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.015));
  --sv-pill-inset: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  --sv-pill-hover-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.03));
  --sv-pill-active-bg: linear-gradient(
    180deg,
    rgba(var(--brand-cyan-rgb), 0.26),
    rgba(var(--brand-cyan-rgb), 0.09)
  );
  --sv-pill-active-ring: 0 0 0 1px rgba(var(--brand-cyan-rgb), 0.34),
    0 4px 14px rgba(var(--brand-cyan-rgb), 0.20), inset 0 1px 0 rgba(255, 255, 255, 0.16);
  /* 買／賣方向 pill 的選中態（語意色版，同一組配方換色源） */
  --sv-pill-up-bg: linear-gradient(180deg, rgba(var(--up-rgb), 0.28), rgba(var(--up-rgb), 0.10));
  --sv-pill-up-ring: 0 0 0 1px rgba(var(--up-rgb), 0.38), 0 4px 14px rgba(var(--up-rgb), 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.16);
  --sv-pill-down-bg: linear-gradient(180deg, rgba(var(--down-rgb), 0.28), rgba(var(--down-rgb), 0.10));
  --sv-pill-down-ring: 0 0 0 1px rgba(var(--down-rgb), 0.38), 0 4px 14px rgba(var(--down-rgb), 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

:root[data-theme="light-a"],
:root[data-theme="light-b"],
:root[data-theme="light-c"],
:root[data-theme="champagne"] {
  --sv-card-sheen: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.95),
    rgba(var(--surface-tint-rgb), 0.022) 50%,
    rgba(var(--surface-tint-rgb), 0.07)
  );
  --sv-card-inset: inset 0 1px 0 rgba(255, 255, 255, 0.92);
  --sv-card-shadow: 0 1px 2px rgba(var(--surface-tint-rgb), 0.07), 0 6px 18px rgba(var(--surface-tint-rgb), 0.09);
  --sv-card-shadow-hover: 0 2px 6px rgba(var(--surface-tint-rgb), 0.11),
    0 14px 32px rgba(var(--surface-tint-rgb), 0.17);
  --sv-card-border-hover: var(--border-strong);

  --sv-thead-bg: linear-gradient(180deg, rgba(var(--surface-tint-rgb), 0.05), rgba(var(--surface-tint-rgb), 0.014));
  --sv-thead-rule: var(--border-strong);
  --sv-row-line: rgba(var(--surface-tint-rgb), 0.06);
  --sv-row-zebra: rgba(var(--surface-tint-rgb), 0.022);
  --sv-row-hover: rgba(var(--surface-tint-rgb), 0.05);
  --sv-scroll-shade: rgba(var(--surface-tint-rgb), 0.16);
  --sv-net-tint: 0.10;

  --sv-pill-bg: linear-gradient(180deg, #fff, rgba(var(--surface-tint-rgb), 0.035));
  --sv-pill-inset: inset 0 1px 0 rgba(255, 255, 255, 0.92);
  --sv-pill-hover-bg: linear-gradient(180deg, #fff, rgba(var(--surface-tint-rgb), 0.07));
  --sv-pill-active-bg: linear-gradient(
    180deg,
    rgba(var(--brand-cyan-rgb), 0.18),
    rgba(var(--brand-cyan-rgb), 0.07)
  );
  --sv-pill-active-ring: 0 0 0 1px rgba(var(--brand-cyan-rgb), 0.34),
    0 3px 10px rgba(var(--brand-cyan-rgb), 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.75);
  --sv-pill-up-bg: linear-gradient(180deg, rgba(var(--up-rgb), 0.18), rgba(var(--up-rgb), 0.07));
  --sv-pill-up-ring: 0 0 0 1px rgba(var(--up-rgb), 0.34), 0 3px 10px rgba(var(--up-rgb), 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.75);
  --sv-pill-down-bg: linear-gradient(180deg, rgba(var(--down-rgb), 0.18), rgba(var(--down-rgb), 0.07));
  --sv-pill-down-ring: 0 0 0 1px rgba(var(--down-rgb), 0.34), 0 3px 10px rgba(var(--down-rgb), 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.75);
}

/* ==========================================================================
   香檳金屬質感層（任務 #225，2026-08-18）—— 只在 data-theme="champagne" 生效

   【設計契約｜哪裡上金屬、哪裡不上】站長要「有質感」，但可讀性優先：
     上金屬（斜掃光＋角落打光＋明暗階）：頁面殼（body）、導覽列（.nav）、
       卡片**外殼**（--sv-card-sheen）、膠囊（--sv-pill-*）。
     ✗ 不上金屬（一律維持素面淺底）：資料表格內部（--sv-row-* / --sv-thead-bg
       沿用上一塊的淺色家族值）、長文區域。金屬漸層只走外框與頁面殼，
       表格列上有密集小字，底一花就毀了可讀性。

   【幅度】站長對視覺改動的感知門檻高（記憶：visual-tweak-must-be-2x），
   所以斜掃光的白階直接給到 .62（品牌卡正本 `_shell()` 的同一個量級），
   不是設計師慣用的 .06 克制版。每一層的**最暗停**都實算過對比，
   見下方各條標註。

   【色票】全部來自 social/tools/make_brand_cards.py:43-51 與其 `_shell()`；
   雙描邊語彙（#B67A45 外／#F2D8B4 內）取自 web/static/icon.svg。
   ========================================================================== */

:root[data-theme="champagne"] {
  /* 卡殼：頂端亮白高光 → 中段金屬本色 → 底部沉一層金褐（落地感）。
     疊在 --card-bg #FFFDF4 上，最暗停實測 #F3E7CD：--text 9.35／
     --text-muted 5.99／--text-faint 5.72，正文全數過 AA。 */
  --sv-card-sheen: linear-gradient(
    168deg,
    rgba(255, 255, 255, 0.98) 0%,
    rgba(242, 223, 172, 0.42) 26%,
    rgba(255, 255, 255, 0.55) 46%,
    rgba(201, 169, 97, 0.16) 74%,
    rgba(122, 90, 30, 0.11) 100%
  );
  /* 雙描邊：內圈亮金高光（#F2D8B4 語彙）＋底緣深金收邊，卡看起來像一塊有厚度的金屬板 */
  --sv-card-inset: inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 0 0 1px rgba(242, 216, 180, 0.55), inset 0 -1px 0 rgba(122, 90, 30, 0.13);
  --sv-card-shadow: 0 1px 2px rgba(122, 90, 30, 0.12), 0 6px 18px rgba(122, 90, 30, 0.14),
    0 1px 0 rgba(255, 255, 255, 0.7);
  --sv-card-shadow-hover: 0 2px 6px rgba(122, 90, 30, 0.18), 0 14px 34px rgba(122, 90, 30, 0.22),
    0 1px 0 rgba(255, 255, 255, 0.8);
  --sv-card-border-hover: var(--brand-cyan); /* GOLD #C9A961 金線 */

  /* 膠囊：小塊金屬牌（上亮下暗＋亮金內描邊），與品牌卡 `.chip` 同語彙 */
  --sv-pill-bg: linear-gradient(180deg, #fffdf4 0%, #f4e6c9 100%);
  --sv-pill-inset: inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 0 0 1px rgba(242, 223, 172, 0.6);
  --sv-pill-hover-bg: linear-gradient(180deg, #fffef9 0%, #f7ecd6 100%);
  --sv-pill-active-bg: linear-gradient(180deg, rgba(201, 169, 97, 0.34), rgba(201, 169, 97, 0.14));
  --sv-pill-active-ring: 0 0 0 1px rgba(201, 169, 97, 0.62),
    0 3px 10px rgba(122, 90, 30, 0.20), inset 0 1px 0 rgba(255, 255, 255, 0.88);
}

/* ---- 頁面殼：香檳金屬板 ----
   四層＝斜掃光 / 右上打光 / 左下沉影 / 底層明暗階，語彙逐層對應品牌卡
   `_shell()` 的 background。`background-attachment: fixed` 是必要的：不加的話
   漸層會被拉伸到整份文件高度（長頁面上等於看不見金屬感），加了才是「一塊
   固定在視口的金屬板，內容在上面捲動」。
   最暗停 #E9D9B0 實測：--text 8.20／--text-muted 5.25／--text-faint 5.02，
   全數過 AA——頁面殼上直接放字（區塊標題、頁尾）也讀得到。 */
:root[data-theme="champagne"] body {
  background:
    linear-gradient(
      105deg,
      rgba(255, 255, 255, 0) 16%,
      rgba(255, 255, 255, 0.62) 26%,
      rgba(255, 255, 255, 0.14) 33%,
      rgba(255, 255, 255, 0) 43%,
      rgba(255, 255, 255, 0) 68%,
      rgba(255, 255, 255, 0.34) 77%,
      rgba(255, 255, 255, 0) 85%
    ),
    radial-gradient(58% 42% at 88% -8%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 62%),
    radial-gradient(70% 48% at 0% 104%, rgba(122, 90, 30, 0.18), rgba(122, 90, 30, 0) 58%),
    linear-gradient(102deg, #fdf7ea 0%, #f2e5c8 17%, #fffcf2 32%, #efe1be 48%,
      #fbf4e4 63%, #eddfba 80%, #fbf6e8 100%);
  background-attachment: fixed;
}

/* ---- 導覽列：同一塊金屬板的橫向切片 ----
   nav 高度小、寬度滿版，所以掃光角度放平（96deg）才看得出金屬轉折。
   最暗停 #EFE1BE 實測：--nav-fg #4A3618 8.83／--nav-sub #6B5225 5.66，過 AA。
   底緣金線用 GOLD #C9A961，與卡框同一條金。 */
:root[data-theme="champagne"] .nav {
  background:
    linear-gradient(
      96deg,
      rgba(255, 255, 255, 0) 10%,
      rgba(255, 255, 255, 0.72) 22%,
      rgba(255, 255, 255, 0.18) 30%,
      rgba(255, 255, 255, 0) 40%,
      rgba(255, 255, 255, 0) 70%,
      rgba(255, 255, 255, 0.42) 80%,
      rgba(255, 255, 255, 0) 90%
    ),
    linear-gradient(180deg, #fffaef 0%, #faf1dc 62%, #efe1be 100%);
  border-bottom: 1px solid var(--brand-cyan);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.75), 0 2px 12px rgba(122, 90, 30, 0.13);
}

/* ---- 卡片外框改吃金線 ----
   只動**外框**，不動卡內任何底色（資料表格與長文維持素面，見本節設計契約）。
   `--border` 在香檳金是 #E6D5AE（淡金），這裡把**卡層級**的框再上一階到
   GOLD #C9A961，讓卡的邊界在金屬板上分得出來。 */
:root[data-theme="champagne"] .sv-card,
:root[data-theme="champagne"] .card,
:root[data-theme="champagne"] .panel,
:root[data-theme="champagne"] .market-card,
:root[data-theme="champagne"] .notice-banner {
  border-color: rgba(201, 169, 97, 0.72);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --sv-lift: 0px;
  }
}

/* --------------------------------------------------------------------------
   共用皮膚 ①：`.sv-table`（app.css 自己的共用表格元件）
   使用面：/market 融資融券數字表、/futures 散戶多空比數字表、/stock 多張
   表、/conference、/admin、/arena、/dividend、/my_dividends。這一支是真正
   的共用 class，直接在這裡升級一次，全部受益。
   -------------------------------------------------------------------------- */

.sv-table th {
  /* 表頭：淡底＋字距拉開＋上下細線，讓表頭與資料列一眼分層 */
  background: var(--sv-thead-bg);
  letter-spacing: 0.06em;
  font-weight: 700;
  border-top: 1px solid var(--sv-row-line);
  border-bottom: 1px solid var(--sv-thead-rule);
  padding: 9px 10px;
}

.sv-table td {
  /* 列分隔柔化：原本吃 --border（實色），改吃比它更淡一階的專用線色 */
  border-bottom: 1px solid var(--sv-row-line);
}

.sv-table tbody tr:last-child td {
  border-bottom: none;
}

/* 斑馬：極淡，只負責讓長表不跑行，不搶語意色 */
.sv-table tbody tr:nth-child(even) {
  background: var(--sv-row-zebra);
}

.sv-table tbody tr {
  transition: background 120ms var(--ease);
}

/* hover／觸控高亮：原本吃 --card-bg-hover（實色，深淺主題落差大），改吃半
   透明疊色，任何底色上都是「亮一階」而不是換成另一個顏色。 */
.sv-table tbody tr:hover,
.sv-table tbody tr:active {
  background: var(--sv-row-hover);
}

.sv-table th.num,
.sv-table td.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* 紅綠語意數值：只加一階字重，字色維持既有 --up/--down。
   **刻意不在這裡上語意底暈**：`.sv-table` 是共用元件，/futures 的散戶多空
   比表每一列的兩個數字欄都掛 .up/.down，整表一上底暈就變成一片紅綠花海
   （2026-08-17 首版實測，130 列全糊）。底暈只給「一張表裡唯一的主角數字
   欄」用，那是各頁自己的事——見 institutional.css `td.inst-net.up/.down`
   （買賣超欄，一列只有一欄）。 */
.sv-table td.num.up,
.sv-table td.num.down {
  font-weight: 700;
}

/* 手機橫捲左右緣漸層暗示（background-attachment: local 老招）**刻意不放在
   這支共用 class 上**。
   那個技法要靠兩層「與容器表面同色」的遮罩把邊緣陰影蓋住，捲動時遮罩跟著
   內容移開、陰影才浮出來——換句話說它必須知道容器背後是什麼顏色。
   `.sv-table-wrap` 沒有自己的背景：在 /futures、/dividend、/my_dividends 它
   疊在頁面卡片上，在 /market、/stock 它直接坐在頁面底色上。統一寫
   var(--card-bg) 當遮罩色的結果是後者兩頁在表格左右各多出一條 34px 的亮帶
   （2026-08-17 首版實測，/market 融資融券數字表量到 #182235 vs 頁底
   #0e1424，肉眼可見）。
   所以這個技法一律寫在「自己有 background-color 的那層」：
     institutional.css `.inst-ranking-table-wrap`／`.amounts-*-wrap`
     etf.css          `.etf-overview-table-wrap`
     industry.css     `.ind-ranking-table-wrap`
     market.css       `#margin-table-wrap`
   四處配方逐字相同，改的時候一起改。 */

/* --------------------------------------------------------------------------
   共用皮膚 ②：圖表 hover 卡片（`.sv-chart-tooltip`）
   樣式本體由 chart_tooltip.js 在 runtime 注入 <style> 到 <head>（見該檔
   ensureStyle()），注入節點排在 app.css 之後、specificity 又相同 → 同名選
   擇器蓋不過它。這裡刻意用 `body .sv-chart-tooltip`（多一層 element）把
   specificity 抬高一階來覆寫，**不改 chart_tooltip.js**：那支是 /market、
   /stock、/futures、/etf 等多頁共用的行為層，改它牽連面遠大於換皮。
   只換皮不換結構：底／字／圓角／陰影升級，position、pointer-events、
   z-index、display 這些行為相關宣告一個都不碰。
   -------------------------------------------------------------------------- */

body .sv-chart-tooltip {
  padding: 9px 13px;
  border-radius: 11px;
  font-size: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)),
    var(--overlay-surface);
  box-shadow: var(--shadow-pop), inset 0 1px 0 rgba(255, 255, 255, 0.10);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

body .sv-chart-tooltip b {
  letter-spacing: 0.04em;
  font-size: 11px;
  margin-right: 8px;
}

/* --------------------------------------------------------------------------
   共用皮膚 ③：代號連結（`a.sv-stock-id-link`）
   全站表格裡「代號欄 → /stock/{代號}」的共用徽章，由 stock_link.js 產生。
   **那支把樣式寫成 inline `style` 屬性**（color:inherit + 點線底線），inline
   宣告贏過任何 CSS 規則，所以這裡只能用 `!important` 覆寫那三個屬性；其餘
   （hover 轉場、圓角、聚焦環）是新增屬性，正常權重即可。
   為什麼不改 stock_link.js：那支是 /institutional、/etf、/industry、/market
   共用的產生器，本波是視覺波，不動任何 JS 產生器的輸出結構。
   -------------------------------------------------------------------------- */

a.sv-stock-id-link {
  text-decoration-color: rgba(var(--text-muted-rgb), 0.5) !important;
  text-underline-offset: 3px !important;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: 600;
  border-radius: 4px;
  transition: color 140ms var(--ease), text-decoration-color 140ms var(--ease);
}

a.sv-stock-id-link:hover {
  color: var(--accent-text) !important;
  text-decoration-color: var(--accent) !important;
}

a.sv-stock-id-link:focus-visible {
  outline: 2px solid rgba(var(--brand-cyan-rgb), 0.55);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   共用皮膚 ④：「盤後重點解讀」洞察卡家族（`.insights-list .insight-item`）
   #216，2026-08-17（站長問「盤後重點解讀的區塊有改了嗎」——#193 質感風暴
   掃過統計卡/資料表/膠囊、#198 掃過 canvas 圖，唯獨漏了這組卡）

   【使用面】/industry-flow、/institutional、/futures、/etf 四頁的「盤後重點
   解讀」區塊，HTML 結構一模一樣（`.insights-list.sv-insight-grid` >
   `.insight-item` > `.insight-item-head > .sv-badge` ＋ `.insight-fact` ＋
   `.insight-note` ＋ `a.insight-learn-link`），由各頁 *.js 的
   buildInsightItem() 產生。

   【為什麼寫在 app.css 而不是四份頁面 css】
   原本這組樣式在 industry.css / institutional.css / futures.css / etf.css
   各存一份**逐字相同**的副本（四檔檔頭都自述「同一套規格，各自維護一份」），
   結果就是任何一次質感升級都要改四遍、漏一頁就發散。本波改成「共用層一份、
   頁面層零份」：四份副本刪掉只留指向本段的註解。
   選擇器刻意寫成 `.insights-list .insight-item`（0,2,0）而不是裸
   `.insight-item`（0,1,0）——頁面 css 的載入順序在 app.css 之後，同權重會被
   蓋掉（#193 檔頭已記過這個坑）；多一層祖先就穩定贏，日後就算哪頁又長回一
   份副本也不會把共用層打回去。四頁容器都掛 `.insights-list`（實查四份
   template），沒有落單的 `.insight-item`。

   【語意色】每張卡吃一顆 `--ins-hue`，由 `.insight-item[data-tone]` 決定
   （各頁 *.js 的 INSIGHT_TAG_META 多帶一個 tone 欄位，見那四支）：
     amber  金 → 集中/佔比/水位類（集中度、成交比重、產業傾斜、情緒指標）
     violet 紫 → 背離/反向類（熱度背離、籌碼分歧、指數背離、散戶反指標…）
     blue   藍 → 方向/流向類（法人連續同向、外資三軌、淨流向、期現貨價差）
     slate  灰 → 廣度/對比/預設（廣度、週對比、未知 tag）
   **刻意沒有綠色**：docs/design_system.md「法律紅線」寫死分類/策略標籤禁用
   紅綠（紅綠帶多空暗示＝實質推介），交辦單提的「廣度綠」因此換成石板灰，
   靠質感（漸層底＋同色環＋柔光暈）而不是靠綠色去做出區別。
   四顆 hue 全部是既有代幣（--tag-blue/--tag-violet/--tag-slate/--usage-amber，
   四主題都已有各自的值），本段零寫死色。

   【配方】卡面＝#193 統計卡同一支（--sv-card-sheen/-inset/-shadow）＋左上語意
   角落暈＋左緣 3px 語意細軌；徽章＝market.css `.index-hero-chip` 同一組
   color-mix 旋鈕（同色漸層底→同色環→柔光暈→內緣細高光）。深色吃白高光、
   淺色三主題把暈與光收斂（本檔既有慣例）。
   -------------------------------------------------------------------------- */

.insights-list .insight-item {
  /* ---- 強度旋鈕（深色主題基準；淺色三主題在下一條收斂）---- */
  --ins-hue: var(--tag-slate); /* 未掛 data-tone / 未知 tag 一律落回石板灰 */
  --ins-wash: 10%; /* 左上語意角落暈 */
  --ins-rail: 58%; /* 左緣語意細軌 */
  /* 徽章底漸層兩端。**上限由對比決定，不是由好看決定**：徽章字色就是這顆
     hue 本身，底色越濃＝字與底越接近，漸層最濃的那一端（a1，膠囊上緣）就是
     整顆膠囊對比最差的一點。逐像素實測（_verify_task216_pixels.py）：a1=30%
     時 blue 只剩 4.20:1、破 4.5 底線，24% 時 violet 仍只有 4.44，收在 20%
     後最差的 dark/violet 是 4.94，其餘 ≥5.2。膠囊感改由「環＋柔光暈＋內緣
     高光」撐，不是靠把底色加濃。 */
  --ins-chip-a1: 20%;
  --ins-chip-a2: 8%;
  --ins-chip-fg: var(--ins-hue); /* 深色不壓深，見淺色區塊說明 */
  --ins-chip-ring: 42%; /* 徽章環 */
  --ins-chip-glow: 26%; /* 徽章柔光暈 */
  --ins-chip-gloss: 26%; /* 徽章內緣細高光（與白混，數字越小越接近純白） */
  --ins-hover-border: 46%;
  --ins-link-ring: 44%;
  --ins-link-glow: 22%;

  position: relative;
  /* 三層：左上語意角落暈 → 質感層 sheen（上緣高光）→ 卡底色。
     底色從舊版的 --bg-2（比所在的 .sv-section 更暗＝內凹）改成 --card-bg＋
     sheen＋柔影，讓卡片變成「浮在面板上的磚」而不是「挖進面板的洞」。 */
  background:
    radial-gradient(
      120% 150% at 0% 0%,
      color-mix(in srgb, var(--ins-hue) var(--ins-wash), transparent),
      transparent 60%
    ),
    var(--sv-card-sheen), var(--card-bg);
  border: 1px solid var(--border);
  /* 圓角回歸設計憲法的「卡片一律 --radius」（舊版 --radius-sm 是條列尺寸） */
  border-radius: var(--radius);
  padding: 15px 17px 13px;
  /* 語意細軌用 inset box-shadow 而不是 ::before 實體元素：自動跟著 border-radius
     收邊，也不必為了裁切而 overflow:hidden（那會連帶剪掉連結的 focus 外框）。 */
  box-shadow: var(--sv-card-shadow), var(--sv-card-inset),
    inset 3px 0 0 color-mix(in srgb, var(--ins-hue) var(--ins-rail), transparent);
  transition: transform 160ms var(--ease), box-shadow 160ms var(--ease),
    border-color 160ms var(--ease);
}

:root[data-theme="light-a"] .insights-list .insight-item,
:root[data-theme="light-b"] .insights-list .insight-item,
:root[data-theme="light-c"] .insights-list .insight-item,
:root[data-theme="champagne"] .insights-list .insight-item {
  /* 淺色三主題的 hue 代幣本身就是深色（--tag-* / --usage-amber 各主題都有
     對比校正過的深色值），所以暈要收、環與軌反而可以更實；內緣高光改成幾乎
     純白（gloss 數字降低＝混更多白）。 */
  --ins-wash: 7%;
  --ins-rail: 66%;
  /* 淺色這邊的瓶頸更緊：--tag-blue 淺色版（#2a72b8）在純白上本來就只有
     5.03:1、--tag-violet（#7a5fb0）5.1:1，底一上 tint 就掉到 4.4 上下。
     解法不是把底調淡到看不見（試過 a1=7%，light-c 仍只有 4.49），而是**把字
     壓深一階**——見下面 --ins-chip-fg。字深了之後底反而吃得住 14%，份量與
     對比兩邊都拿到（實測淺色三主題最差 5.21）。 */
  --ins-chip-a1: 14%;
  --ins-chip-a2: 5%;
  --ins-chip-ring: 46%;
  /* 淺色專用：徽章字壓深 14%（與黑混，等同把代幣色再暗一階；同一支
     color-mix 技法本檔既有使用處是把色與白混做內緣高光）。深色主題不做這件
     事——那邊是亮字疊暗底，壓深只會更糊。 */
  --ins-chip-fg: color-mix(in srgb, var(--ins-hue) 86%, black);
  --ins-chip-glow: 14%;
  --ins-chip-gloss: 12%;
  --ins-hover-border: 40%;
  --ins-link-ring: 36%;
  --ins-link-glow: 12%;
}

.insights-list .insight-item[data-tone="amber"] {
  --ins-hue: var(--usage-amber);
}
.insights-list .insight-item[data-tone="violet"] {
  --ins-hue: var(--tag-violet);
}
.insights-list .insight-item[data-tone="blue"] {
  --ins-hue: var(--tag-blue);
}
.insights-list .insight-item[data-tone="slate"] {
  --ins-hue: var(--tag-slate);
}

/* hover 微上浮：位移量走 --sv-lift（prefers-reduced-motion 時全站歸零），
   同時把語意軌與邊框加實一階，滑過去才知道這張卡是哪一類。 */
.insights-list .insight-item:hover {
  transform: translateY(var(--sv-lift));
  box-shadow: var(--sv-card-shadow-hover), var(--sv-card-inset),
    inset 3px 0 0 color-mix(in srgb, var(--ins-hue) 82%, transparent);
  border-color: color-mix(in srgb, var(--ins-hue) var(--ins-hover-border), transparent);
}

.insights-list .insight-item-head {
  margin-bottom: 9px;
}

/* 類別徽章 → 質感膠囊。顏色一律由 --ins-hue 現算，所以 JS 掛的
   `.sv-badge-blue/violet/slate` 在洞察卡裡只是「CSS 沒載到時的保底底色」，
   真正的色源是 data-tone（單一真相）。 */
.insights-list .insight-item .sv-badge {
  padding: 3px 11px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.045em;
  color: var(--ins-chip-fg);
  /* 最後那層 --card-bg 是**必要的不透明底**，不是多餘的：沒有它，徽章底的
     半透明漸層會跟卡片左上那圈語意角落暈疊在一起（徽章正好坐在角落暈最濃
     處），字與底同色相再相加＝對比被吃掉。逐像素實測：不加這層時淺色主題的
     blue 徽章只有 3.95:1（破 4.5），加了之後徽章底只跟 --card-bg 合成，對比
     變成可預測的定值。 */
  background: linear-gradient(
      180deg,
      color-mix(in srgb, var(--ins-hue) var(--ins-chip-a1), transparent),
      color-mix(in srgb, var(--ins-hue) var(--ins-chip-a2), transparent)
    ),
    var(--card-bg);
  border: 1px solid color-mix(in srgb, var(--ins-hue) var(--ins-chip-ring), transparent);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--ins-hue) var(--ins-chip-glow), transparent),
    inset 0 1px 0 color-mix(in srgb, var(--ins-hue) var(--ins-chip-gloss), white);
}

/* 主句：升為卡片主角（13.5px/600/--text 兩級 → 15px/700/--text-strong），
   與降灰的說明句拉開一整階，掃視時先讀到結論。 */
.insights-list .insight-fact {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: -0.005em;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* 主句裡的漲跌語意字（行情事實，非分類標籤，紅綠合法） */
.insights-list .insight-fact .up {
  color: var(--up);
  font-weight: 800;
}
.insights-list .insight-fact .down {
  color: var(--down);
  font-weight: 800;
}

/* 說明句：降到 --text-faint（三級制最弱，淺色三主題該顆已做過 5.1+ 對比校正，
   深色 #7e8ea5 疊 --card-bg 約 4.8:1，仍在 4.5 門檻之上），行距放寬。 */
.insights-list .insight-note {
  margin-top: 7px;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--text-faint);
}

/* 「深入學習 →」：素連結 → 低調膠囊（底走全站 pill 代幣），hover 才點亮成
   該卡的語意色。頁面 css 的 `.sv-learn-link:hover{text-decoration:underline}`
   是 0,2,0，這裡用 0,3,0 蓋掉（膠囊上再加底線會髒）。 */
.insights-list .insight-learn-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 11px;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-faint);
  text-decoration: none;
  background: var(--sv-pill-bg), var(--bg-2);
  border: 1px solid var(--border);
  box-shadow: var(--sv-pill-inset);
  transition: color 140ms var(--ease), background 140ms var(--ease),
    border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}

.insights-list .insight-learn-link:hover,
.insights-list .insight-learn-link:focus-visible {
  color: var(--ins-hue);
  text-decoration: none;
  background: var(--sv-pill-hover-bg), var(--bg-2);
  border-color: color-mix(in srgb, var(--ins-hue) var(--ins-link-ring), transparent);
  box-shadow: 0 3px 12px color-mix(in srgb, var(--ins-hue) var(--ins-link-glow), transparent),
    var(--sv-pill-inset);
}

.insights-list .insight-learn-link:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--ins-hue) 62%, transparent);
  outline-offset: 2px;
}

/* [hidden] 全域保證（2026-08-20，B15 修類）：`.empty-state` 等帶 display:flex 的
   class 會蓋過 UA 的 [hidden]{display:none}，症狀＝後台「你沒有權限瀏覽」提示
   對管理員永遠顯示（站長 08-19 影片與截圖都拍到）。hidden 屬性的語意是「就是
   不該顯示」，!important 合理。 */
[hidden] {
  display: none !important;
}

/* =====================================================================
   持股頁卡片式改版＋券商篩選（持股多券商，2026-08-20）
   ---------------------------------------------------------------------
   放 app.css 檔尾自成段落（本棒檔案邊界：portfolio.css 由並行棒維護，
   不動）。三個元件家族：

   ① `.pf-broker-bar`／`.pf-broker-chip`：券商膠囊篩選列。選中態走
      accent 實底（比照全站 pill 語彙）；「＋管理券商」是虛線邊的
      幽靈膠囊，跟資料膠囊在視覺上分開——它是入口不是篩選值。
   ② `.pf-cards`／`.pf-card`：卡片式持股。手機單欄、≥768px 兩欄
      （斷點沿用 app.css 既有 min-width:768px 慣例，見 7958 行一帶）。
      卡面質感對齊 portfolio.css v12 總覽卡語彙：珍珠高光＋柔影＋
      hover 浮起。損益值元素沿用 .pf-today-pnl 等舊 class（SSE
      applyLiveQuote 會整顆蓋 className），卡片語境的樣式全走
      `.pf-card-pnl-item .pf-today-pnl` 後代選擇器，蓋掉也不掉妝。
      券商名一律金色（--chart-line-amber 這顆四主題都校過對比的琥珀
      金代幣）；「點此設定券商」淡黃小字走 --warn-fg/--watch-rgb
      （與「估」小標同族——同樣是「提醒但不緊急」的語意）。
   ③ `.sv-tour-*`：FeatureTour 通用導覽（feature_tour.js）。聚光燈
      用單一元素＋巨大 box-shadow 挖洞壓暗；卡片 fixed 定位由 JS 算。

   顏色一律走代幣，零寫死色票（遮罩壓暗層例外——它語意上就是「黑紗」，
   四主題都用同一片黑，寫 rgba(10,14,22,…) 不隨主題翻是刻意的）。
   ===================================================================== */

/* ---------- ① 券商膠囊篩選列 ---------- */

.pf-broker-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
}

.pf-broker-chip {
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: color 140ms var(--ease), border-color 140ms var(--ease),
    background 140ms var(--ease), box-shadow 140ms var(--ease),
    transform 140ms var(--ease);
}

.pf-broker-chip:hover {
  color: var(--accent-text);
  border-color: var(--accent);
  transform: translateY(-1px);
}

.pf-broker-chip.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 3px 12px rgba(var(--brand-blue-rgb), 0.3);
}

.pf-broker-chip.is-active:hover {
  color: var(--on-accent);
  transform: none;
}

/* 「＋管理券商」：入口不是篩選值，虛線邊幽靈膠囊在視覺上分家 */
.pf-broker-chip-manage {
  border-style: dashed;
  background: transparent;
  color: var(--text-faint);
}

/* ---------- ① 管理券商面板 ---------- */

.pf-broker-manage {
  margin-bottom: 14px;
  padding: 14px 16px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}

.pf-broker-manage-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.pf-broker-manage-title {
  font-size: 13.5px;
  font-weight: 800;
  color: var(--text);
}

.pf-broker-manage-close {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.pf-broker-manage-close:hover {
  color: var(--down);
  border-color: var(--down);
}

.pf-broker-manage-hint {
  font-size: 12px;
  color: var(--text-faint);
  margin-bottom: 10px;
}

.pf-broker-manage-list {
  display: grid;
  gap: 8px;
}

.pf-broker-manage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(var(--surface-tint-rgb), 0.03);
}

.pf-broker-manage-stock {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pf-broker-manage-shares {
  margin-left: 8px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.pf-broker-select {
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 12.5px;
  max-width: 46%;
}

/* ---------- ② 卡片式持股 ---------- */

.pf-cards {
  display: grid;
  grid-template-columns: 1fr; /* 手機單欄 */
  gap: 12px;
}

/* 電腦兩欄（斷點沿用 app.css 既有 min-width:768px 慣例） */
@media (min-width: 768px) {
  .pf-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }
}

.pf-card {
  position: relative;
  overflow: hidden;
  --pf-card-gloss-rgb: var(--surface-tint-rgb);
  padding: 15px 17px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 90% at 8% -12%, rgba(var(--brand-blue-rgb), 0.06), transparent 58%),
    radial-gradient(110% 90% at 104% -8%, rgba(var(--brand-violet-rgb), 0.05), transparent 60%),
    linear-gradient(180deg, rgba(var(--pf-card-gloss-rgb), 0.08), transparent 52%),
    var(--card-bg);
  box-shadow: var(--shadow-card), inset 0 1px 0 rgba(var(--pf-card-gloss-rgb), 0.12);
  transition: transform 160ms var(--ease), box-shadow 160ms var(--ease),
    border-color 160ms var(--ease);
}

/* 珍珠高光在淺色四主題必須覆寫回白（--surface-tint-rgb 是壓暗用的深藍，
   拿來當高光會變髒污）——同 portfolio.css .pf-stat-card 的既有結論。 */
:root[data-theme="light-a"] .pf-card,
:root[data-theme="light-b"] .pf-card,
:root[data-theme="light-c"] .pf-card,
:root[data-theme="champagne"] .pf-card {
  --pf-card-gloss-rgb: 255, 255, 255;
}

/* hover 浮起只給有滑鼠的裝置（#173 慣例：觸控裝置的 hover 是黏住的假態） */
@media (hover: hover) {
  .pf-card:hover {
    transform: translateY(-2px);
    border-color: rgba(var(--brand-blue-rgb), 0.35);
    box-shadow: var(--shadow-card), inset 0 1px 0 rgba(var(--pf-card-gloss-rgb), 0.12),
      0 10px 28px rgba(var(--shadow-rgb), 0.16);
  }
}

/* 集中度 >30%：左緣琥珀色條（與 ⚠ 徽章、表格時代 .pf-row-heavy 同族） */
.pf-card.is-heavy::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, rgba(var(--watch-rgb), 0.9), rgba(var(--watch-rgb), 0.25));
}

.pf-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.pf-card-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
  min-width: 0;
  font-size: 15px;
}

.pf-card-sid {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.pf-card-industry {
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(var(--surface-tint-rgb), 0.05);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}

.pf-card-price {
  text-align: right;
  flex-shrink: 0;
}

/* 卡片語境的現價字級升一級（表格 13.5px 是欄寬妥協，卡上是主角） */
.pf-card-price .pf-price-main {
  font-size: 17px;
}

.pf-card-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 11px;
}

.pf-card-stat-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  margin-bottom: 3px;
}

.pf-card-stat-value {
  font-size: 13px;
  font-weight: 800;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 「N 券商」小徽章：金色語彙（多券商是本次改版的主角資訊） */
.pf-card-multi {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  border: 1px solid rgba(var(--amber-alt-rgb), 0.45);
  background: rgba(var(--amber-alt-rgb), 0.12);
  color: var(--chart-line-amber);
  font-size: 10px;
  font-weight: 800;
  line-height: 16px;
  letter-spacing: 0.02em;
  vertical-align: 1px;
  cursor: help;
}

/* 損益列：淡色底一條，把「錢的事」與上面的部位數據分層 */
.pf-card-pnl {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  padding: 9px 12px;
  margin-bottom: 11px;
  border-radius: 12px;
  background: rgba(var(--surface-tint-rgb), 0.045);
  border: 1px solid rgba(var(--surface-tint-rgb), 0.07);
}

.pf-card-pnl-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  margin-bottom: 2px;
}

/* 值元素的 className 會被 applyLiveQuote 整顆蓋掉（"num pf-today-pnl up"），
   樣式全部走後代選擇器不掛額外 class。 */
.pf-card-pnl-item .pf-today-pnl,
.pf-card-pnl-item .pf-total-pnl {
  font-size: 15.5px;
  font-weight: 900;
  letter-spacing: -0.3px;
  font-variant-numeric: tabular-nums;
}

.pf-card-pnl-item .up { color: var(--up); }
.pf-card-pnl-item .down { color: var(--down); }
.pf-card-pnl-item .flat { color: var(--text-muted); }

.pf-card-pnl-total-wrap {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
}

.pf-card-pnl-item .pf-total-pnl-pct {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  border: 1px solid rgba(var(--pnl-pct-rgb, var(--text-muted-rgb)), 0.32);
  background: rgba(var(--pnl-pct-rgb, var(--text-muted-rgb)), 0.12);
}

.pf-card-pnl-item .pf-total-pnl-pct.up { --pnl-pct-rgb: var(--up-rgb); }
.pf-card-pnl-item .pf-total-pnl-pct.down { --pnl-pct-rgb: var(--down-rgb); }

/* ---- 卡片底列：券商標籤（左）＋操作鈕（右） ---- */

.pf-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}

.pf-card-broker-line {
  display: flex;
  align-items: center;
  min-width: 0;
}

/* 券商標籤：金色（--chart-line-amber，四主題都校過對比的琥珀金代幣） */
.pf-card-broker {
  padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid rgba(var(--amber-alt-rgb), 0.45);
  background: rgba(var(--amber-alt-rgb), 0.1);
  color: var(--chart-line-amber);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease);
}

.pf-card-broker:hover {
  background: rgba(var(--amber-alt-rgb), 0.18);
  border-color: rgba(var(--amber-alt-rgb), 0.7);
}

/* 未指定券商的淡黃提示（畫面規格 ⑤）：提醒但不緊急，--warn-fg 同族 */
.pf-card-broker-hint {
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px dashed var(--warn-border);
  background: rgba(var(--watch-rgb), 0.08);
  color: var(--warn-fg);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  transition: background 140ms var(--ease);
}

.pf-card-broker-hint:hover {
  background: rgba(var(--watch-rgb), 0.16);
}

/* 行內指定/改派券商列（點標籤或提示後展開） */
.pf-card-assign {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 9px;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px dashed var(--border);
  background: rgba(var(--surface-tint-rgb), 0.03);
}

.pf-card-assign-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
}

.pf-card-assign .pf-broker-select {
  max-width: none;
  flex: 1;
  min-width: 130px;
}

.pf-card-assign-cancel {
  padding: 5px 11px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.pf-card-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

/* 展開各券商明細的小三角鈕 */
.pf-card-expand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  transition: color 140ms var(--ease), border-color 140ms var(--ease);
}

.pf-card-expand:hover {
  color: var(--accent-text);
  border-color: var(--accent);
}

.pf-card-expand-caret {
  display: inline-block;
  font-size: 11px;
  line-height: 1;
  transition: transform 200ms var(--ease);
}

.pf-card-expand.is-open .pf-card-expand-caret {
  transform: rotate(90deg);
}

/* ---- 各券商明細（展開動畫走 grid-rows 0fr→1fr，收合時高度歸零） ---- */

.pf-positions {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 260ms var(--ease), margin-top 260ms var(--ease);
  margin-top: 0;
}

.pf-positions.is-open {
  grid-template-rows: 1fr;
  margin-top: 10px;
}

.pf-positions-inner {
  overflow: hidden;
  min-height: 0;
  display: grid;
  gap: 6px;
}

.pf-pos-row {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: 10px;
  border: 1px solid rgba(var(--surface-tint-rgb), 0.07);
  background: rgba(var(--surface-tint-rgb), 0.04);
}

/* 子列券商名：金色（畫面規格 ③） */
.pf-pos-broker {
  font-size: 12px;
  font-weight: 800;
  color: var(--chart-line-amber);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.pf-pos-broker.is-unassigned {
  color: var(--text-faint);
  font-weight: 700;
}

.pf-pos-info {
  font-size: 11.5px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pf-pos-pnl {
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.pf-pos-total {
  font-size: 12.5px;
  font-weight: 800;
}

.pf-pos-total-pct {
  font-size: 10.5px;
  font-weight: 700;
}

.pf-pos-total.up, .pf-pos-total-pct.up { color: var(--up); }
.pf-pos-total.down, .pf-pos-total-pct.down { color: var(--down); }
.pf-pos-total.flat, .pf-pos-total-pct.flat { color: var(--text-muted); }

.pf-pos-actions {
  display: flex;
  gap: 5px;
}

/* 手機：明細列塌成兩行（券商+損益一行、部位+操作一行），4 欄擠不下 */
@media (max-width: 640px) {
  .pf-pos-row {
    grid-template-columns: 1fr auto;
    row-gap: 4px;
  }
  .pf-pos-info {
    grid-column: 1;
  }
  .pf-pos-actions {
    grid-column: 2;
    justify-self: end;
  }
  /* 手機卡片內距收一階 */
  .pf-card {
    padding: 13px 14px 12px;
  }
  .pf-card-stats {
    gap: 6px;
  }
}

/* ---------- ③ FeatureTour 通用導覽（feature_tour.js） ---------- */

.sv-tour-root {
  position: fixed;
  inset: 0;
  z-index: 1600; /* 高於 toast(--z?) 與 modal 常用層；導覽期間全頁凍結 */
}

/* 聚光燈：元素本身罩住目標，巨大 box-shadow 把其餘畫面壓暗。
   壓暗層刻意不走代幣（語意就是黑紗，四主題同一片黑）。 */
.sv-tour-spot {
  position: fixed;
  border-radius: 14px;
  box-shadow: 0 0 0 200vmax rgba(10, 14, 22, 0.6);
  border: 2px solid var(--chart-line-amber);
  outline: 1px solid rgba(var(--amber-alt-rgb), 0.35);
  outline-offset: 3px;
  transition: top 240ms var(--ease), left 240ms var(--ease),
    width 240ms var(--ease), height 240ms var(--ease);
  pointer-events: none;
}

/* 降級態的聚光燈：尺寸歸零、框線拿掉、擺到畫面正中央。
   **仍然保留這顆元素**——整片黑紗就是它的 box-shadow（見上一條規則），藏掉
   它等於連遮罩一起收掉。0×0 的元素照樣把 200vmax 的陰影鋪滿整個畫面，於是
   畫面依舊變暗，只是沒有任何指向性的框。
   （2026-08-21 封測回報：導覽說明卡浮在亮著的內容上＝就是遮罩不見了。） */
.sv-tour-spot-blank {
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border: none;
  outline: none;
}

/* 降級態的說明卡：置中。`!important` 是必要的——正常路徑走的是 inline
   top/left，降級路徑雖已清空那兩個值，這條規則仍要能贏過任何殘留。 */
.sv-tour-card-centered {
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%);
}

.sv-tour-card {
  position: fixed;
  padding: 15px 16px 13px;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: var(--card-bg);
  box-shadow: 0 18px 48px rgba(var(--shadow-rgb), 0.4);
  transition: top 240ms var(--ease), left 240ms var(--ease);
}

.sv-tour-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}

.sv-tour-icon {
  font-size: 19px;
  line-height: 1;
}

.sv-tour-title {
  flex: 1;
  font-size: 14.5px;
  font-weight: 800;
  color: var(--text);
}

.sv-tour-counter {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.sv-tour-text {
  font-size: 13px;
  line-height: 1.65;
  color: var(--text-muted);
  margin-bottom: 10px;
}

.sv-tour-dots {
  display: flex;
  gap: 5px;
  margin-bottom: 11px;
}

.sv-tour-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(var(--surface-tint-rgb), 0.18);
  transition: background 140ms var(--ease), width 140ms var(--ease);
}

.sv-tour-dot.is-active {
  width: 16px;
  border-radius: 999px;
  background: var(--chart-line-amber);
}

.sv-tour-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sv-tour-actions-spacer {
  flex: 1;
}

.sv-tour-btn {
  padding: 7px 14px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  transition: color 140ms var(--ease), border-color 140ms var(--ease),
    background 140ms var(--ease), filter 140ms var(--ease);
}

.sv-tour-btn-skip {
  border-color: transparent;
  color: var(--text-faint);
  padding-left: 6px;
  padding-right: 6px;
}

.sv-tour-btn-skip:hover {
  color: var(--text-muted);
}

.sv-tour-btn-prev:hover {
  color: var(--accent-text);
  border-color: var(--accent);
}

.sv-tour-btn-next {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.sv-tour-btn-next:hover {
  filter: brightness(1.08);
}

/* 動效敏感使用者：聚光燈/卡片瞬移、展開動畫關閉（全站既有慣例） */
@media (prefers-reduced-motion: reduce) {
  .sv-tour-spot,
  .sv-tour-card,
  .pf-positions,
  .pf-card,
  .pf-card-expand-caret {
    transition: none;
  }
}

/* ===== 訪客 nav 窄機分階降級（2026-08-22 站長實機：/welcome 390px 品牌字標被截）=====
   原則：品牌字標是 nav 主字（站長 08-20 明令），永不收縮、永不裁切；空間不夠
   由右側動作自行降級（內容／狀態驅動，禁機型客製）：
   ≤430px：註冊／申請加入 CTA 換短標（兩個 span 切換）＋按鈕內距收斂；
   ≤400px：訪客態（.nav.sv-nav-guest，由 nav.js 訪客分支掛上）藏調色盤；
   ≤340px：訪客態再藏鈴鐺。會員態不受影響（會員動作已在漢堡面板分階）。 */
.nav .logo-wrap { flex-shrink: 0; }
.nav .logo-wrap + div { flex-shrink: 0; }
.sv-cta-short { display: none; }
@media (max-width: 430px) {
  .sv-cta-full { display: none; }
  .sv-cta-short { display: inline; }
  .nav .sv-guest-btn,
  .nav .nav-actions .btn-ghost,
  .nav .nav-actions .btn-save { padding-left: 9px; padding-right: 9px; }
}
@media (max-width: 400px) {
  .nav.sv-nav-guest .sv-theme-toggle-wrap { display: none; }
}
@media (max-width: 340px) {
  .nav.sv-nav-guest .sv-announce-bell { display: none; }
}
@media (max-width: 340px) {
  /* 320 級極窄：字標降到 18px（仍是 nav 主字）、訪客雙鈕內距與間距再收，
     幾何：24 padding＋44 logo＋~104 字標＋(登入 ~42＋註冊 ~48＋漢堡 36＋間距 8) ≈ 306 ≤ 320。 */
  .nav .title { font-size: 18px; }
  .nav .sv-guest-btn,
  .nav .nav-actions .btn-ghost,
  .nav .nav-actions .btn-save { padding-left: 7px; padding-right: 7px; font-size: 12px; }
  .nav .nav-actions, .nav .sv-guest-auth { gap: 4px; }
}

/* #184 四輪（2026-08-22）：漢堡選單展開期間，固定定位的浮層不得攔截點擊——
   實測 .toast-stack（z-index:100）與 .feedback-fab 蓋在展開中的選單上，
   a.nav-link 命中測試落到 div.toast。body.sv-nav-open 由 nav.js fit() 同步。 */
body.sv-nav-open .toast-stack,
body.sv-nav-open .feedback-fab { pointer-events: none; opacity: 0.35; }

/* ===== 一眼版體檢分數卡（2026-08-23，正本 docs/health_score_spec_20260823.md §4）
   兩個掛載點共用同一組 class，樣式只寫一份：
     - SSR 摘要頁 `/stock/{id}`：`.hs-ssr` 片段（四條橫條＋膠囊，零 JS、無圓環）
     - 互動頁 `/stock?id=`：`#ai-l2-glance` 裡的 `.hs-glance`（圓環＋橫條＋膠囊）
   stock_seo.html 與 stock.html 吃的是同一支 app.css，所以這一組定義在全域層
   而不是各自的 <style>——一份定義、兩頁同步，改色階不會只改到一邊。

   **一個 hex 都不寫**：色階全部走五主題既有代幣（--up / --watch-fg / --down /
   --text / --card-bg / --border），四個亮色主題不需要另外覆寫這一區——需要覆寫
   的只有「疊色比例」那一類，比照本檔 .env-mini-gauge / .env-score-light-chip
   的既有寫法（見下方 .hs-chip 那一段）。

   ---- 二版「立體感改版」（站長 2026-08-23 15:21：「太平淡無奇，要重新設計有
   質感一點，並且帶有一些立體感」）----
   三個層次一起加厚，一版的扁平面全部換成有受光方向的體積：
     (1) 圓環：粗度 10→16、值弧走 SVG 金屬漸層（亮階→本色→暗階）、底環做成
         內凹軌道（上暗下亮的漸層＋內緣亮線／外緣暗線）、弧末端加儀表指針頭
         （亮點＋外光暈）、環外 36 根低對比刻度、圓心數字 900 字重＋漸層填色。
     (2) 橫條：6→10 高、軌道內凹（inset 陰影）、填色左深右亮＋頂部 1px 高光線
         ＋末端圓亮點、右側數字改成同色階的小膠囊、標籤前加 4px 色柱。
     (3) 卡片：近距＋遠距雙層陰影＋頂緣 1px 亮邊＋上亮下暗的表面漸層；桌機
         hover 微抬升。膠囊全面玻璃化（半透明底＋內緣高光），風險點發光。

   **白與黑只當「打亮／壓暗」的疊色成分用**（`color-mix(… white x%, transparent)`
   之類），不是主題色——同一條規則在五個主題上都是「往亮的方向加一點」或
   「往暗的方向加一點」，所以不必為亮色主題再寫一份覆寫；深色主題吃到的是
   更明顯的內光暈，四個亮色主題吃到的是更明顯的下緣壓暗，各自都立體。 ===== */

/* SSR 片段：一版刻意做成「沒有卡殼的裸片段」（活在既有的 .ss-card 裡）。二版
   把它升成一塊**浮起的內嵌面板**——理由是立體感這件事在 SEO 頁沒有圓環可以
   承擔，只剩橫條與膠囊，若連底板都沒有就只是「四條彩色線躺在卡上」。面板本身
   的顏色仍然是 var(--card-bg)（與外層 .ss-card 同底），差異全靠邊框、上亮下暗
   的表面漸層與雙層陰影做出來，所以在四個亮色主題上不會出現「白底疊白底」的
   髒塊。 */
.hs-ssr {
  margin: 0 0 14px;
  padding: 13px 13px 11px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background:
    linear-gradient(180deg, color-mix(in srgb, white 8%, transparent), transparent 46%),
    linear-gradient(0deg, color-mix(in srgb, black 6%, transparent), transparent 42%),
    var(--card-bg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.18),
    0 16px 34px -26px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 color-mix(in srgb, white 14%, transparent);
}

/* 互動頁的分數卡：同一套配方但更厚（它是 AI 分析中心裡自成一塊的主角）。
   雙層陰影＝近距 1px 的「接觸陰影」（讓卡緣咬住底面）＋遠距大範圍的
   「投射陰影」（讓整張卡離開底面）；頂緣 inset 1px 亮邊是受光面。 */
.hs-glance {
  margin: 10px 0 12px;
  padding: 16px 15px 13px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background:
    linear-gradient(180deg, color-mix(in srgb, white 9%, transparent), transparent 48%),
    linear-gradient(0deg, color-mix(in srgb, black 7%, transparent), transparent 44%),
    var(--card-bg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.22),
    0 18px 40px -24px rgba(0, 0, 0, 0.62),
    inset 0 1px 0 color-mix(in srgb, white 16%, transparent);
}

/* 桌機 hover 微抬升：只在有真滑鼠的裝置上開（`hover: hover` ＋ `pointer: fine`），
   手機不會因為觸控殘留 hover 態而卡在抬起狀態。 */
@media (hover: hover) and (pointer: fine) {
  .hs-glance {
    transition: transform 0.25s ease, box-shadow 0.25s ease;
  }

  .hs-glance:hover {
    transform: translateY(-2px);
    box-shadow:
      0 2px 4px rgba(0, 0, 0, 0.24),
      0 26px 54px -26px rgba(0, 0, 0, 0.7),
      inset 0 1px 0 color-mix(in srgb, white 20%, transparent);
  }
}

/* 手機單欄、夠寬才並排（正本 §4）——但判準是**這張卡自己有多寬**，不是視窗
   有多寬（B27「擠壓 bug 先算最小寬幾何」）：互動頁的分數卡活在 AI 分析中心
   的三欄網格裡，1280px 視窗下那一欄只有約 330px。用 `@media (min-width:768px)`
   判斷的話，最寬的桌機反而會把圓環與橫條硬擠成一排（實測 2026-08-23 首版就是
   這個症狀）。改用 flex-wrap ＋ 主區塊 240px 的 flex-basis：容器寬度不足
   圓環 112 ＋ 間距 12 ＋ 240 ≈ 364px 時，主區塊自動掉到下一行變單欄；夠寬
   （手機橫放、平板、全寬版面）就自然並排。一條規則吃掉所有寬度，零機型客製。 */
.hs-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

.hs-main {
  flex: 1 1 240px;
  min-width: 0;
}

/* ---- SVG 圓環（viewBox 120、r 44、stroke 16 → 環身 36~52，環外 54~59 留給
   刻度；dasharray 2πr ≈ 276.46、rotate −90）----
   二版把半徑從 52 縮到 44 是為了「粗度 16 ＋ 環外刻度」兩件事同時放得下：
   52 + 8（半個粗度）= 60 已經頂到 viewBox 邊界，刻度會被切掉。 */
.hs-ring {
  position: relative;
  flex: 0 0 auto;
  width: 112px;            /* 手機 112px */
  height: 112px;
  border-radius: 50%;
  /* 玻璃感內底：中心亮、邊緣暗，圓環看起來像嵌在一片玻璃上而不是印在平面上；
     外陰影讓整顆離開卡面。 */
  background:
    radial-gradient(
      circle at 50% 34%,
      color-mix(in srgb, white 10%, transparent),
      transparent 62%
    ),
    radial-gradient(
      circle at 50% 50%,
      transparent 56%,
      color-mix(in srgb, black 10%, transparent) 98%
    );
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.55);
  /* 內凹軌道的兩個端色：SVG `<stop>` 靠繼承拿到（stop 是 defs 的子孫、defs 又
     在這個容器底下），所以定義在這裡而不是 .hs-ring-track 上。 */
  --hs-track-hi: color-mix(in srgb, var(--text) 18%, transparent);
  --hs-track-lo: color-mix(in srgb, var(--text) 5%, transparent);
}

@media (min-width: 768px) {
  .hs-ring { width: 128px; height: 128px; }   /* 電腦 128px */
}

@media (max-width: 320px) {
  .hs-ring { width: 96px; height: 96px; }     /* ≤320 極窄 96px */
}

.hs-ring-svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* 底環＝內凹軌道：上暗下亮的線性漸層（凹槽的受光方向與凸起相反），JS 以
   inline style 換成 `url(#…)` 漸層；這裡的純色是漸層取不到時的退路。 */
.hs-ring-track {
  fill: none;
  stroke: color-mix(in srgb, var(--text) 12%, transparent);
  stroke-width: 16;
}

/* 軌道的內外緣各一條 1px 細線：內側亮（凹槽的受光唇邊）、外側暗（背光唇邊）。
   兩條加起來才讓 16px 的粗帶讀起來像「挖進去」而不是「貼上去」。 */
.hs-ring-edge {
  fill: none;
  stroke-width: 1;
}

.hs-ring-edge-in {
  stroke: color-mix(in srgb, white 18%, transparent);
}

.hs-ring-edge-out {
  stroke: color-mix(in srgb, black 24%, transparent);
}

/* 環外刻度（純裝飾、低對比）：36 根、每 10° 一根；落在 90° 整數倍的四根
   （0/25/50/75 分位）加長加亮當主刻度。資訊仍由弧長與圓心數字承擔。 */
.hs-ring-tick {
  stroke: color-mix(in srgb, var(--text) 20%, transparent);
  stroke-width: 1.1;
  stroke-linecap: round;
}

.hs-ring-tick-major {
  stroke: color-mix(in srgb, var(--text) 36%, transparent);
  stroke-width: 1.7;
}

.hs-ring-arc {
  fill: none;
  stroke: currentColor;          /* JS 以 inline style 換成 url(#…) 金屬漸層 */
  stroke-width: 16;
  stroke-linecap: round;
  stroke-dasharray: 276.46;
  stroke-dashoffset: 276.46;     /* 預設空環；JS 寫入目標值後靠 transition 走完 */
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
  transition: stroke-dashoffset 0.7s cubic-bezier(0.22, 0.9, 0.28, 1);
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--hs-tone) 42%, transparent));
}

/* 弧末端的「指針頭」：外圈光暈 ＋ 內圈亮點，像儀表指針落在刻度上。
   位置由 JS 依分數算好（cx/cy），這裡只負責上色與淡入。 */
.hs-ring-head-glow {
  fill: var(--hs-tone);
  opacity: 0.34;
}

/* 亮點的**外框走暗階**（不是亮階）：四個亮色主題的軌道本身就是淺灰，白心配
   淺色框會整顆糊在軌道上看不出來；暗階的細框在五個主題上都咬得住邊界。 */
.hs-ring-head {
  fill: color-mix(in srgb, var(--hs-tone) 16%, white);
  stroke: var(--hs-deep);
  stroke-width: 1.6;
  filter: drop-shadow(0 0 4px var(--hs-tone));
}

.hs-ring-head,
.hs-ring-head-glow {
  /* 延遲 0.45s＝等值弧掃到位再亮起來（弧本身 0.7s，人眼在 0.45s 已看清方向）。 */
  animation: hs-head-in 0.45s ease-out 0.45s both;
}

@keyframes hs-head-in {
  from { opacity: 0; }
}

/* 圓心的「68 分」：**基線對齊**（數字大、單位小，兩者要坐在同一條基線上，
   不是各自置中）。所以不用 `inset:0` ＋ `align-items:center`——那會讓
   `align-self:flex-end` 的單位掉到整個 112px 圓框的最底下、被弧線蓋掉
   （2026-08-23 首版實測「分」不見了就是這個）。改成「先把這一行垂直置中，
   行內再基線對齊」。
   二版加 drop-shadow：作用在「已經上完漸層的字」上，比 text-shadow 乾淨
   （text-shadow 會從 background-clip 的鏤空邊緣透出來變成一圈髒邊）。 */
.hs-ring-center {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 2px;
  line-height: 1;
  pointer-events: none;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.26));
}

.hs-ring-num {
  font-size: clamp(2rem, 5.6vw, 2.5rem);   /* 32 → 40px */
  font-weight: 900;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.hs-ring-unit {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-muted);
}

@media (max-width: 320px) {
  .hs-ring-num { font-size: 1.75rem; }
}

/* ---- SSR 頁的標題數字（那一頁沒有圓環，數字本身就是主角） ---- */
.hs-headline {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 9px;
}

.hs-headline-label {
  font-size: 0.9rem;
  color: var(--text-muted);
}

.hs-headline-num {
  font-size: clamp(2.25rem, 7vw, 2.6rem);   /* 36 → 41.6px */
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.22));
}

.hs-headline-unit {
  font-size: 0.9rem;
  color: var(--text-muted);
}

/* 兩處大數字的金屬漸層填色。刻意**不用 --hs-lite 當最亮端**：那一階是
   「本色摻 42% 白」，在四個亮色主題的白底上會掉到 3:1 以下（大字也只是
   剛好卡在 WCAG 大字門檻）。文字用的是「本色摻 14% 白」的微高光帶
   （--hs-sheen），對比不比原本的純色差，金屬感靠下緣的 --hs-deep 做出來。 */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .hs-ring-num,
  .hs-headline-num {
    background: linear-gradient(
      175deg,
      var(--hs-sheen) 0%,
      var(--hs-tone) 44%,
      var(--hs-deep) 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* ---- 四條橫條 ---- */
.hs-bars {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 6px 0 12px;
}

/* 色階代幣的預設值掛在**列**上（不是填色條上）：二版有三個子孫要吃同一顆
   色（4px 標籤色柱、填色條漸層、右側數字膠囊），掛在共同祖先才一次到位。
   沒有分數的「未收錄」列不帶 hs-tone-*，就落在這組灰階預設上。 */
.hs-bar-row {
  display: flex;
  align-items: center;
  gap: 9px;
  --hs-tone: var(--text-faint);
  --hs-sheen: var(--text-muted);
  --hs-lite: var(--text-muted);
  --hs-deep: var(--text-faint);
}

.hs-bar-label {
  flex: 0 0 auto;
  width: 5.6em;                 /* 4px 色柱＋「波段結構」四字，中文字級驅動不寫死 px */
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-muted);
}

/* 標籤前的 4px 色柱：不畫圖示、只用一根與該面向同色階的短柱，讓四條在讀到
   數字之前就先分得出誰高誰低。 */
.hs-bar-label::before {
  content: "";
  flex: 0 0 auto;
  width: 4px;
  height: 1.05em;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--hs-lite), var(--hs-deep));
  box-shadow: 0 0 6px -1px color-mix(in srgb, var(--hs-tone) 60%, transparent);
}

/* 內凹軌道：上暗下亮的底色漸層 ＋ 上緣 inset 暗影 ＋ 下緣 inset 亮線
   ＝「挖進卡面的一道溝」。 */
.hs-bar-track {
  flex: 1 1 auto;
  min-width: 0;
  height: 10px;
  border-radius: 999px;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--text) 17%, transparent),
    color-mix(in srgb, var(--text) 6%, transparent)
  );
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.35),
    inset 0 -1px 0 color-mix(in srgb, white 12%, transparent);
  overflow: hidden;
}

/* 填色條＝一根打過光的圓柱：左深右亮的橫向漸層（光從右上來）、頂部 1px
   白色高光線、底部一道暗影收邊。 */
.hs-bar-fill {
  position: relative;
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    var(--hs-deep) 0%,
    var(--hs-tone) 55%,
    var(--hs-lite) 100%
  );
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, white 45%, transparent),
    inset 0 -2px 3px -1px rgba(0, 0, 0, 0.3);
  animation: hs-bar-in 0.7s cubic-bezier(0.22, 0.9, 0.28, 1) both;
}

/* 末端亮點：跟圓環的指針頭同一個語彙（「值走到這裡」）。 */
.hs-bar-fill::after {
  content: "";
  position: absolute;
  right: 1px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: color-mix(in srgb, white 72%, var(--hs-tone));
  box-shadow: 0 0 6px color-mix(in srgb, var(--hs-tone) 85%, transparent);
}

/* 逐條 stagger：四條同時長出來看起來像一塊色塊在閃，錯開才讀得出「四個
   面向各自是多少」。延遲寫在 nth-child 上而不是 inline style，渲染端就
   不必為了動效多帶一個屬性。 */
.hs-bar-row:nth-child(1) .hs-bar-fill { animation-delay: 0s; }
.hs-bar-row:nth-child(2) .hs-bar-fill { animation-delay: 0.08s; }
.hs-bar-row:nth-child(3) .hs-bar-fill { animation-delay: 0.16s; }
.hs-bar-row:nth-child(4) .hs-bar-fill { animation-delay: 0.24s; }

/* 二版改用 clip-path 揭露而不是 scaleX：scaleX 會把末端亮點與頂部高光線
   一起橫向壓扁（動畫全程是一顆橢圓在長大），clip-path 是「拉開簾子」，
   亮點從頭到尾都是正圓。 */
@keyframes hs-bar-in {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}

/* 右側數字：一版是裸數字，二版收進同色階的小膠囊（淡底＋細框＋內緣高光），
   讓「四個面向各自幾分」讀起來是四顆可比較的徽章而不是四個浮字。 */
.hs-bar-num {
  flex: 0 0 auto;
  min-width: 2.2em;
  text-align: center;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--hs-tone);
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--hs-tone) 20%, transparent),
    color-mix(in srgb, var(--hs-tone) 9%, transparent)
  );
  border: 1px solid color-mix(in srgb, var(--hs-tone) 30%, transparent);
  box-shadow: inset 0 1px 0 color-mix(in srgb, white 24%, transparent);
}

/* 缺料只寫「未收錄」，不畫 0% 條（正本 §4／原則④）。 */
.hs-bar-na {
  flex: 1 1 auto;
  font-size: 0.82rem;
  color: var(--text-faint);
}

/* ≤320 極窄：標籤縮一格、間距收緊，讓軌道還留得住可讀長度。 */
@media (max-width: 320px) {
  .hs-bar-row { gap: 7px; }
  .hs-bar-label { width: 5.2em; font-size: 0.8rem; }
  .hs-bar-num { padding: 2px 5px; font-size: 0.75rem; }
}

/* ---- 三段色階（正本 §4：>=70 --up、45~70 --watch-fg、<45 --down） ----
   除了 `color`（給 currentColor 的舊路徑）之外，二版同時發一顆 `--hs-tone`
   自訂屬性。理由是漸層要被三種取不到 currentColor 的子孫吃到：
     (a) SVG `<stop style="stop-color:var(--hs-tone)">`——defs 在弧的**旁邊**
         不是底下，拿不到弧的 currentColor，但拿得到共同祖先 .hs-ring 的變數；
     (b) `background-clip:text` 的大數字——它自己的 `color` 被設成 transparent，
         currentColor 會跟著變透明；
     (c) 橫條的標籤色柱與數字膠囊——它們是填色條的**兄弟**不是子孫。
   本區塊必須排在 .hs-bar-row 之後：兩者同為單一 class（specificity 相同），
   靠「後者勝」讓有分數的列覆蓋掉灰階預設。 */
.hs-tone-high { color: var(--up); --hs-tone: var(--up); }
.hs-tone-mid { color: var(--watch-fg); --hs-tone: var(--watch-fg); }
.hs-tone-low { color: var(--down); --hs-tone: var(--down); }

/* 金屬感＝同色相的三階（亮階／本色／暗階）。退回純色的分支寫在前面：不支援
   `color-mix()` 的瀏覽器三個變數都等於本色，漸層退化成單色，資訊一個位元不少。 */
.hs-tone-high,
.hs-tone-mid,
.hs-tone-low {
  --hs-sheen: var(--hs-tone);
  --hs-lite: var(--hs-tone);
  --hs-deep: var(--hs-tone);
}

@supports (color: color-mix(in srgb, red 50%, white)) {
  .hs-tone-high,
  .hs-tone-mid,
  .hs-tone-low {
    --hs-sheen: color-mix(in srgb, var(--hs-tone) 86%, white);
    --hs-lite: color-mix(in srgb, var(--hs-tone) 58%, white);
    --hs-deep: color-mix(in srgb, var(--hs-tone) 70%, black);
  }
}

/* ---- 膠囊列 ----
   底座沿用 .env-score-light-chip（正本 §4 指定的家族）：那一組的疊色比例
   代幣（--envchip-a1/a2/border/glow/gloss）已經有四個亮色主題的覆寫，這裡
   只要接上去就自動跟著五主題走，不必再寫一份亮色覆寫。

   **風險膠囊刻意不吃紅綠**：同一張卡上的橫條已經用「紅＝分數高」的台股慣例
   色階，風險再用紅綠就會出現「紅色＝分數高（好）」與「紅色＝風險高（壞）」
   同色反義。所以風險走 --watch-fg 一條琥珀強弱軸（琥珀＝注意，全站既有語意，
   同 .market-light.yellow），三階只差濃度：高＝實色、中＝淡、中低＝素面。

   二版把三階一起玻璃化：內緣 1px 高光（受光面）＋外側一道低擴散投影（讓膠囊
   離開卡面）。三個變體各自寫一次 box-shadow 而不是靠 .hs-chip 繼承——它們
   排在 .hs-chip 之後、specificity 相同，寫在 .hs-chip 上會被整條覆蓋掉。 */
.hs-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.hs-chip {
  font-size: 0.8rem;
  font-weight: 600;
  padding: 5px 11px;
  color: var(--text);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, white 24%, transparent),
    0 2px 8px -4px rgba(0, 0, 0, 0.45);
}

/* 發光點：中心偏左上打一顆高光＝球體而不是圓片，外加兩層同色光暈。 */
.hs-chip-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: radial-gradient(
    circle at 34% 30%,
    color-mix(in srgb, white 78%, currentColor),
    currentColor 68%
  );
  box-shadow:
    0 0 7px color-mix(in srgb, currentColor 85%, transparent),
    0 0 2px color-mix(in srgb, currentColor 90%, transparent);
  flex: 0 0 auto;
}

.hs-risk-high {
  color: var(--watch-fg);
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--watch-fg) var(--envchip-a1), transparent),
    color-mix(in srgb, var(--watch-fg) var(--envchip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--watch-fg) var(--envchip-border), transparent);
  box-shadow:
    0 4px 14px -7px color-mix(in srgb, var(--watch-fg) 80%, transparent),
    0 2px 8px -4px rgba(0, 0, 0, 0.42),
    inset 0 1px 0 color-mix(in srgb, var(--watch-fg) var(--envchip-gloss), white);
}

.hs-risk-mid {
  color: var(--watch-fg);
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--watch-fg) var(--envchip-a1), transparent),
    color-mix(in srgb, var(--watch-fg) var(--envchip-a2), transparent)
  );
  border-color: color-mix(in srgb, var(--watch-fg) 26%, transparent);
  box-shadow:
    0 2px 8px -4px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 color-mix(in srgb, white 26%, transparent);
}

.hs-risk-low,
.hs-chip-flat {
  color: var(--text-muted);
  background: linear-gradient(
    180deg,
    color-mix(in srgb, white 7%, var(--bg-2)),
    var(--bg-2)
  );
  border-color: var(--border);
  box-shadow:
    0 2px 8px -5px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 color-mix(in srgb, white 20%, transparent);
}

/* 一致性提醒：左緣一根琥珀色柱＝「這是註記不是內容」的既有語彙。 */
.hs-note {
  margin: 10px 0 0;
  padding: 8px 10px 8px 11px;
  border-radius: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-left: 3px solid color-mix(in srgb, var(--watch-fg) 55%, transparent);
  color: var(--text-muted);
  font-size: 0.82rem;
  line-height: 1.6;
}

.hs-hint {
  margin: 10px 0 0;
  color: var(--text-faint);
  font-size: 0.8rem;
  line-height: 1.6;
}

.hs-asof {
  margin-top: 8px;
  color: var(--text-faint);
  font-size: 0.8rem;
}

/* 動效關閉（正本 §4）：圓環、橫條、指針頭都只是把終值一步到位，資訊一個
   位元不少；hover 抬升也一併關掉。 */
@media (prefers-reduced-motion: reduce) {
  .hs-ring-arc { transition: none; }
  .hs-bar-fill { animation: none; }
  .hs-ring-head,
  .hs-ring-head-glow { animation: none; }
  .hs-glance { transition: none; }
  .hs-glance:hover { transform: none; }
}
