/* Taiwan Stock Scanner — 視覺系統（B1：dark navy financial dashboard）
   ============================================================================
   沒有前端框架、沒有 CSS framework、沒有 CDN、沒有外部字型（MVP §22）。

   **所有可重複使用的視覺值都集中在 :root。** 元件規則裡不得出現裸色碼——
   改版前有 9 個色碼散落在元件中，於是「換一個主題」等於翻遍整份檔案。

   **每個選擇器只宣告一次。** 改版前 `.panel h2` 被宣告兩次，
   Phase 10 的規則把 Phase 9 的設計悄悄蓋掉，沒有人發現。

   以上兩件事都由 `tests/test_design_system.py` 守住——
   實作 B1 的過程中，那兩條測試各抓到一次我自己犯的同樣錯誤。

   深藍色系的每一組前景/背景都經過對比度量測（數字寫在各 token 旁），
   不是憑感覺挑的；低於 AA 的組合在套用前就被換掉了。
   ========================================================================== */

:root {
  /* ---- 表面 ------------------------------------------------------------
     層級刻意很淺（1.04–1.12:1）：分隔靠**邊框**，不靠陰影或大幅明度落差。
     陰影一多就變成消費型 App 的卡片堆，不是金融/資料介面。 */
  --color-bg:                 #0b1220;   /* 頁面底 */
  --color-surface:            #111a2b;   /* 面板 */
  --color-surface-raised:     #18243a;   /* 表頭、hover、標籤 */
  --color-surface-subtle:     #0e1626;   /* 內嵌區塊、行內程式碼 */

  /* ---- 邊框 ------------------------------------------------------------
     分隔線刻意低對比（裝飾性，WCAG 1.4.11 不適用）——結構由對齊承擔。
     **互動元件**的邊框才必須 >= 3.0。 */
  --color-border:             #233047;
  --color-border-strong:      #2c3b56;
  --color-border-interactive: #4e6595;   /* 3.00 on surface（AA-UI） */

  /* ---- 文字 ------------------------------------------------------------ */
  --color-text:               #e6edf7;   /* 15.89 on bg */
  --color-text-muted:         #9aa9c0;   /*  7.86 on bg */
  --color-text-faint:         #8296b4;   /*  6.21 on bg，5.15 連最亮表面也達 AA */

  /* ---- 互動 ------------------------------------------------------------
     ⚠️ accent 上必須用**深色字**：白字在 #4f9cf5 上只有 2.84:1（不合格），
     深色字是 6.60:1。這是量測逼出來的決定，不是偏好。 */
  --color-accent:             #4f9cf5;   /* 6.60 on bg */
  --color-accent-hover:       #6cb0ff;
  --color-accent-ink:         #0b1220;   /* 6.60 ON accent */

  /* ---- 語意 ------------------------------------------------------------
     台股慣例：漲紅跌綠。
     ⚠️ 「漲」與「錯誤」都是紅的，兩者色相只差 1.22:1——**無法靠顏色區分**。
     因此靠**元件形態**分開：漲跌只以帶正負號的裸數字出現在表格與報價；
     錯誤只以有標題、有左邊框的區塊出現。兩者不會被混淆。
     漲跌也永遠不只靠顏色：百分比一律帶 +/- 號（app.js 的 pct()）。 */
  --color-positive:           #f2555a;   /* 漲 5.55 on bg */
  --color-negative:           #2fbf71;   /* 跌 7.86 on bg */
  --color-warning:            #e0a33e;   /*    8.45 on bg */
  --color-success:            #2fbf71;   /*    7.86 on bg */
  --color-danger:             #ff6b6b;   /*    6.75 on bg */
  --color-neutral:            #9aa9c0;   /*    7.86 on bg */

  /* ---- 圖表（B3.1）------------------------------------------------------
     成交量長條需要自己的 token：借用 --color-border-strong 只有 **1.55:1**，
     而長條是「資料」不是分隔線——WCAG 1.4.11 對有意義的圖形要求 >= 3.0。
     3.49 讓它讀得到，同時仍然明顯低於收盤線的 14.77，維持「價格為主、
     量能為輔」的階層。（實測值，非估計） */
  --color-chart-volume:       #55709f;   /* 3.49 on surface（AA-UI） */

  --color-warning-bg:         #2a2113;
  --color-danger-bg:          #2b1519;
  --color-success-bg:         #10271c;
  --color-info-bg:            #12233c;

  /* ---- 停用（改版前是白字在淺藍上，只有 2.11:1）------------------------ */
  --color-disabled-bg:        #1c2942;
  --color-disabled-border:    #24334f;
  --color-disabled-ink:       #8193b0;   /* 4.66 on disabled-bg */

  /* ---- 程式碼區塊 ------------------------------------------------------ */
  --color-code-bg:            #0e1626;
  --color-code-ink:           #e6edf7;   /* 15.34 */

  /* ---- Focus -----------------------------------------------------------
     兩段式：外圈與底色相同的 offset + 內圈亮環。
     亮環單獨壓在 accent 按鈕上只有 1.57:1，深色 offset 才把它分開（6.60）。 */
  --color-focus:              #8fc5ff;   /* 10.34 on bg */
  --focus-offset:             #0b1220;
  --focus-ring: 0 0 0 2px var(--focus-offset), 0 0 0 4px var(--color-focus);

  /* ---- 間距（取代改版前 26 個臨時 rem 值）------------------------------ */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;

  /* ---- 版面 ------------------------------------------------------------ */
  --content-width:      1100px;   /* 文字與狀態類內容 */
  --content-width-wide: 1560px;   /* 資料密集區塊（掃描結果） */
  --section-gap:        var(--space-5);
  --cell-pad-y:         0.4rem;
  --cell-pad-x:         0.7rem;

  /* ---- 形狀 ------------------------------------------------------------ */
  --radius-sm:   3px;
  --radius-md:   6px;
  --radius-pill: 999px;
  --border-width:        1px;
  --border-width-accent: 3px;

  /* ---- 效果（克制：邊框做事，陰影不做事）------------------------------- */
  --transition: 120ms ease;

  /* ---- 字體 ------------------------------------------------------------ */
  --font-sans: system-ui, "Segoe UI", "Microsoft JhengHei", sans-serif;
  --font-mono: ui-monospace, Consolas, "Cascadia Mono", monospace;

  --text-xs:      0.78rem;
  --text-sm:      0.85rem;
  --text-base:    0.9rem;
  --text-body:    15px;
  --text-md:      1rem;
  --text-lg:      1.1rem;
  --text-xl:      1.35rem;
  --text-display: 2rem;

  --leading-tight:  1.3;
  --leading-normal: 1.6;

  --weight-medium: 500;
  --weight-bold:   600;

  --numeric: tabular-nums;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  margin-inline: auto;
  padding: 0 var(--space-4) var(--space-7);
  max-width: var(--content-width);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background: var(--color-bg);
}

/* --- 鍵盤 focus -----------------------------------------------------------
   改版前整份 CSS **沒有任何 focus 規則**，完全依賴瀏覽器預設環——
   而那正是深色底上最容易消失的東西。 */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

/* --- 連結的基礎樣式 --------------------------------------------------------
   ⚠️ 改版前**完全沒有基礎的 `a` 規則**：只有 `.site-header a`、`.crumb a`
   等特定位置有樣式，內文裡的連結（例如錯誤頁的「錯誤紀錄」）沿用瀏覽器
   預設的 #0000EE。在淺色底上勉強可讀，換成深藍底之後只剩 **1.85:1**——
   幾乎看不見。這是 QA 時實際在畫面上發現的，不是讀程式碼看出來的。 */
a {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
a:hover { color: var(--color-accent-hover); }
a:visited { color: var(--color-accent); }

/* --- 行內程式碼 ------------------------------------------------------------ */
code {
  font-family: var(--font-mono);
  font-size: 0.94em;
  background: var(--color-surface-subtle);
  padding: 0 0.3em;
  border-radius: var(--radius-sm);
}
pre code { background: none; padding: 0; }

/* --- 頁首：目前頁面用「字重 + 底線」標示，不只靠顏色 ---------------------- */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-5);
  padding: var(--space-4) 0 var(--space-3);
  border-bottom: var(--border-width) solid var(--color-border-strong);
}
.site-header h1 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}
.site-header nav a {
  color: var(--color-text-muted);
  text-decoration: none;
  padding: var(--space-1) 0;
  border-bottom: 2px solid transparent;
}
.site-header nav a:hover { color: var(--color-accent); }
.site-header nav a[aria-current="page"] {
  color: var(--color-text);
  font-weight: var(--weight-medium);
  border-bottom-color: var(--color-accent);
}
.site-header nav a + a { margin-left: var(--space-4); }

/* --- 代號查詢（B5）：全站頁首的查詢框 --------------------------------------
   ⚠️ 這一區**刻意不設 box-shadow、也不設 outline**。上面那條 focus 規則
      （`:where(a, button, input, …):focus-visible`）用的是 `:where()`，
      特異性是 **0**——只要在這裡給 input 或 button 一個自己的 box-shadow，
      那個兩段式 focus 環就會被安靜地蓋掉，鍵盤使用者從此看不到自己在哪裡。
      這裡只動邊框、背景與內距，focus 環是免費繼承來的。

   邊框用 --color-border-interactive 而不是 --color-border：輸入框與按鈕是
   **互動元件**，WCAG 1.4.11 要求它們的邊界 >= 3.0（P44）。實測（本階段）：

     border-interactive / 頁面底 #0b1220        3.23
     border-interactive / surface-subtle #0e1626 3.12   ← 輸入框的填色
     border-interactive / surface #111a2b        3.00   ← 按鈕的填色
     border-interactive / surface-raised #18243a 2.68   ← **不合格，所以沒用它**

   最後那一行是實際擋下來的選擇：按鈕原本想借頁首慣用的 surface-raised，
   量出來只有 2.68，於是換成 surface。這不是偏好問題。

   **本區沒有新增任何 design token。** */
.symbol-lookup {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;   /* 靠右；nav 與 h1 的位置完全不動 */
}
.symbol-lookup__input {
  font: inherit;
  /* 20ch 不是隨手挑的：placeholder「輸入代號，例如 2330」有 7 個全形字，
     每個約佔 2ch，加上空格與 4 位數字約需 19ch。15ch 時瀏覽器把
     「例如 2330」整段截掉——placeholder 裡最有用的那半截看不見。
     這是 QA 時在畫面上看到的，不是讀 CSS 推出來的（F-B5-8）。 */
  width: 20ch;
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border-interactive);
  border-radius: var(--radius-sm);
  background: var(--color-surface-subtle);
  color: var(--color-text);            /* 15.34 on surface-subtle */
  transition: border-color var(--transition);
}
.symbol-lookup__input::placeholder {
  color: var(--color-text-faint);      /* 6.00 on surface-subtle */
  opacity: 1;   /* Firefox 預設把 placeholder 再壓暗一次，會把 6.00 拉到不合格 */
}
.symbol-lookup__input:hover { border-color: var(--color-accent); }
.symbol-lookup__submit {
  font: inherit;
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border-interactive);
  border-radius: var(--radius-sm);
  background: var(--color-surface);    /* 3.00 對邊框；surface-raised 只有 2.68 */
  color: var(--color-text);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.symbol-lookup__submit:hover {
  border-color: var(--color-accent);
  background: var(--color-surface-raised);
}

/* 視覺上藏起來，但**留給螢幕閱讀器**。
   `display: none` 或 `visibility: hidden` 會把 label 一起藏掉，
   輸入框就退回只剩 placeholder——而 placeholder 不是 label。 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 400 頁回音的那一段：等寬字，讓「我到底打了什麼」一眼看得出來
   （尤其是全形／半形、前後空白這種肉眼難分的差別）。 */
.lookup-error .submitted {
  font-family: var(--font-mono);
  padding: 0 0.3em;
  border-radius: var(--radius-sm);
  background: var(--color-surface-subtle);
  color: var(--color-text);
  word-break: break-all;   /* 貼進來一長串時不要把版面撐開 */
}

/* --- 面板 ---------------------------------------------------------------- */
.panel {
  border: var(--border-width) solid var(--color-border-strong);
  background: var(--color-surface);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  margin-top: var(--section-gap);
}
/* 改版前這個選擇器被宣告兩次（Phase 9 + Phase 10），後者蓋掉前者。現在只有一條。 */
.panel h2 {
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: var(--border-width) solid var(--color-border);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  letter-spacing: 0.01em;
  color: var(--color-text);
}
.panel h2 .symbol {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  color: var(--color-text);
}

.muted { color: var(--color-text-muted); font-size: var(--text-base); }

/* --- 狀態徽章 ------------------------------------------------------------- */
.state-line { margin: var(--space-1) 0 var(--space-3); }

.badge {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  margin-right: var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  color: var(--color-accent-ink);
}
.badge-ready        { background: var(--color-success); }   /* 深字 7.86 */
.badge-insufficient { background: var(--color-warning); }   /* 深字 8.45 */
/* 空資料庫是**正常狀態**（畫面上的文字也這麼說），所以用中性色。
   改版前這裡是錯誤紅，與旁邊「這不是錯誤」那句話直接矛盾。 */
.badge-empty        { background: var(--color-neutral); }   /* 深字 7.86 */

/* --- 提示 / 通知區塊 ------------------------------------------------------- */
.hint {
  border-left: var(--border-width-accent) solid var(--color-warning);
  background: var(--color-warning-bg);
  padding: 0.6rem 0.9rem;
  margin: var(--space-3) 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.hint pre {
  background: var(--color-code-bg);
  color: var(--color-code-ink);
  padding: 0.6rem var(--space-2);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  margin: var(--space-2) 0;
}

.notice {
  border-left: var(--border-width-accent) solid var(--color-accent);
  background: var(--color-info-bg);
  padding: 0.6rem 0.9rem;
  margin: var(--space-3) 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.notice-blocked { border-left-color: var(--color-warning); background: var(--color-warning-bg); }
.notice-error   { border-left-color: var(--color-danger);  background: var(--color-danger-bg); }

/* --- 鍵值表 --------------------------------------------------------------- */
.kv { border-collapse: collapse; margin-top: var(--space-3); }
.kv th, .kv td { text-align: left; padding: 0.2rem var(--space-5) 0.2rem 0; }
.kv th { color: var(--color-text-muted); font-weight: var(--weight-medium); }
.kv td.num {
  text-align: right;
  font-variant-numeric: var(--numeric);
  padding-right: 2.5rem;
  min-width: 6ch;
}

/* 抓取狀態總覽：0 個失敗與 12 個失敗不該長得一樣 */
.stat-value { font-variant-numeric: var(--numeric); font-weight: var(--weight-bold); }
.stat-ok        .stat-value { color: var(--color-success); }
.stat-neutral   .stat-value { color: var(--color-text-muted); }
.stat-attention .stat-value { color: var(--color-warning); }
.stat-clear     .stat-value { color: var(--color-text-muted); }

/* --- 按鈕 ---------------------------------------------------------------- */
button.primary {
  font: inherit;
  font-weight: var(--weight-bold);
  letter-spacing: 0.01em;
  padding: var(--space-2) 1.1rem;
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-accent-ink);
  cursor: pointer;
  /* color 也要一起過渡：只讓背景過渡的話，切換到停用狀態的那 120ms 內
     文字色已經跳到淺灰、背景卻還停在 accent，對比會短暫掉到 1.1。 */
  transition: background var(--transition), border-color var(--transition),
              color var(--transition);
}
button.primary:hover:not(:disabled) {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}
button.primary:active:not(:disabled) { transform: translateY(1px); }
button.primary:disabled {
  background: var(--color-disabled-bg);
  border-color: var(--color-disabled-border);
  color: var(--color-disabled-ink);   /* 4.66（改版前 2.11） */
  cursor: not-allowed;
}

.inline-state { margin-left: var(--space-3); font-size: var(--text-base); color: var(--color-text-muted); }
.inline-state.busy  { color: var(--color-accent); }
.inline-state.error { color: var(--color-danger); font-weight: var(--weight-bold); }
.inline-state.done  { color: var(--color-success); }

/* --- 規則選擇：整列可點，選中的那一列看得出來 ----------------------------- */
.rule-list { list-style: none; padding: 0; margin: 0 0 var(--space-4); }
.rule-list li {
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-width) solid var(--color-border);
  border-left: var(--border-width-accent) solid transparent;
  transition: background var(--transition), border-color var(--transition);
}
.rule-list li:hover:not(:has(input:disabled)) { background: var(--color-surface-raised); }
.rule-list li:has(input:checked) {
  background: var(--color-surface-raised);
  border-left-color: var(--color-accent);
}
.rule-list label { display: block; cursor: pointer; }
.rule-list label:has(input:disabled) { cursor: not-allowed; }
.rule-name {
  margin-left: var(--space-1);
  font-weight: var(--weight-bold);
  color: var(--color-text);
}
.rule-list input:disabled + .rule-name { color: var(--color-text-muted); }
.rule-id {
  margin-left: var(--space-2);
  padding: 0 var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  background: var(--color-surface-subtle);
  border-radius: var(--radius-sm);
}
.rule-desc {
  display: block;
  margin-left: 1.6rem;
  font-size: var(--text-base);
  color: var(--color-text-muted);
}
.rule-list input:disabled ~ .rule-desc { color: var(--color-text-faint); }

/* --- 更新結果 ------------------------------------------------------------- */
.result-box {
  margin-top: var(--space-3);
  padding: 0.6rem 0.9rem;
  border-left: var(--border-width-accent) solid var(--color-success);
  background: var(--color-success-bg);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.result-box.error { border-left-color: var(--color-danger); background: var(--color-danger-bg); }
.result-box dl {
  display: grid;
  grid-template-columns: max-content auto;
  gap: 0.1rem var(--space-4);
  margin: var(--space-1) 0 0;
}
.result-box dt { color: var(--color-text-muted); }
.result-box dd { margin: 0; font-variant-numeric: var(--numeric); }
.result-box a { color: var(--color-accent); }

/* ==========================================================================
   表格系統 —— 本應用的主要介面
   ========================================================================== */
.table-scroll { overflow-x: auto; overscroll-behavior-x: contain; }

/* `position: sticky` 需要一個**會垂直捲動**的祖先才有作用。
   改版前 thead 寫了 sticky，但容器沒有高度上限、從不垂直捲動，
   捲到第 40 列就看不到欄位名稱——等於死碼。 */
.table-scroll--tall {
  max-height: 70vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

table#results-table,
table.history,
table.log {
  border-collapse: collapse;
  width: 100%;
  margin-top: var(--space-2);
  font-size: var(--text-base);
}
.table-scroll--tall table.history { margin-top: 0; }

table#results-table th, table#results-table td,
table.history th,      table.history td,
table.log th,          table.log td {
  padding: var(--cell-pad-y) var(--cell-pad-x);
  text-align: left;
  white-space: nowrap;
  border-bottom: var(--border-width) solid var(--color-border);
}

table#results-table thead th,
table.history thead th,
table.log thead th {
  background: var(--color-surface-raised);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: 0.02em;
  border-bottom: 2px solid var(--color-border-strong);
}
.table-scroll--tall thead th { position: sticky; top: 0; z-index: 1; }

table#results-table tbody tr,
table.history tbody tr,
table.log tbody tr { transition: background var(--transition); }

/* 289 列 × 7 欄的表格改版前沒有任何列追蹤 */
table#results-table tbody tr:hover,
table.history tbody tr:hover,
table.log tbody tr:hover { background: var(--color-surface-raised); }

/* 數字一律右對齊 + 等寬數字，位數可以直接目視比較 */
table#results-table td.num, table#results-table th.num,
table.history td.num,      table.history th.num,
table.indicators td.num,   table.indicators th.num {
  text-align: right;
  font-variant-numeric: var(--numeric);
  font-feature-settings: "tnum";
}

/* 佐證欄：可追溯性的實際載體（MVP §25.7）。
   改版前有 885px 寬卻只看得到 463px，其餘要橫向捲動——
   偏偏它正是「這筆命中憑什麼成立」的證據。改成可換行並給定上限。 */
/* ⚠️ 選擇器必須比 `table#results-table td` 更明確：那條規則帶一個 id，
   權重高於 `td.evidence`，所以 `white-space: nowrap` 會贏——
   實際畫面上佐證欄因此完全不換行，仍然被裁掉。 */
table#results-table td.evidence {
  line-height: var(--leading-tight);
  white-space: normal;
  min-width: 26ch;
  max-width: 52ch;
}

/* 佐證上半：由實際數據推導出來的說法（B2）。
   改版前這一格只有 `volume=44229818.00 · vol_ma10=23094891.00`——
   數字全在，但沒有回答「所以這是什麼情況」。
   句子由伺服器產生（唯一一份文案，見 routes.py），這裡只負責排版。 */
.highlights {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--color-text);
}
.highlights li { margin: 0 0 var(--space-1) 0; }
.highlights li::before {
  content: "·";
  color: var(--color-text-faint);
  margin-right: var(--space-2);
}

/* 佐證下半：原始數值。**補充而非取代**——使用者要能直接拿它對 daily_prices
   驗算（MVP §25.7），所以它一直在畫面上，不藏在需要點擊的地方。 */
.evidence-raw {
  margin: var(--space-2) 0 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: var(--leading-tight);
  color: var(--color-text-faint);
}

/* 「符合規則」欄：這一檔同時符合哪幾條規則（B2）。 */
table#results-table td.matches {
  white-space: normal;
  min-width: 18ch;
  max-width: 30ch;
}

.rule-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  align-items: baseline;
}

/* ⚠️ chip 刻意**不用綠色**。本專案是台股慣例「漲紅跌綠」，綠色在這張表裡
   已經有明確意思（下跌）——同一列出現綠色的「✓ 符合」與紅色的 +2.06%，
   會把「符合規則」讀成「下跌」。accent 藍是資訊性的，兩邊都不衝突（P43
   的延伸：語意衝突時換元件形態或換色相，不要硬塞第三個意思進既有顏色）。 */
.rule-chip {
  display: inline-block;
  padding: 0 var(--space-2);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-info-bg);
  color: var(--color-accent);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}

/* 命中數：**計數，不是評分**（B2 核准決定）。刻意做成最不顯眼的一個元素，
   而且不參與排序——做得像徽章就會被讀成評等。 */
.match-count {
  /* 永遠自己一行。讓 chip 換行決定它的位置，計數就會時而跟在最後一個 chip
     後面、時而自己一行——同一欄裡位置浮動，眼睛就得每列重新找一次。
     這一欄的列高本來就由「佐證」欄的 4–5 行決定，多這一行不佔實際空間。 */
  flex-basis: 100%;
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  font-variant-numeric: var(--numeric);
  white-space: nowrap;
}

/* ==========================================================================
   今日規則檢查（B3.2，個股頁）
   ==========================================================================
   ⚠️ 這個面板呈現的是**規則檢查**，不是對股票的評分。

   1,983 檔裡有 1,451 檔一條規則都沒中，所以「未符合」是**最常見**的狀態——
   它必須是這一頁最安靜的東西。做成紅色或叉叉，多數個股頁就會像收到三張
   負評，而規則只是在描述今天的價量型態。

   三個狀態刻意做成**同樣大小、同樣形狀**的標籤，差別只在輕重與線條：
   眼睛先讀到的是「這裡有一欄狀態」，而不是「這裡有三個叉」。
   全部沿用既有 token，本節**沒有新增任何 token**。 */
.rule-checks {
  margin: var(--space-4) 0 var(--space-3);
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.rule-check {
  display: flex;
  flex-wrap: wrap;          /* 窄螢幕時狀態標籤自己一行，不壓縮說明文字 */
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3);
  background: var(--color-surface-subtle);
  border-radius: var(--radius-md);
}

/* 固定寬度讓三個狀態對齊成一欄。對齊本身就是「這是一組檢查」的訊號。 */
.rule-status {
  flex: 0 0 auto;
  min-width: 5.5em;
  text-align: center;
  padding: 0 var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}

/* 符合：與掃描結果的 chip 同一套視覺語言（accent 藍，刻意不用綠——
   本專案是台股慣例「漲紅跌綠」，見 .rule-chip 的說明）。 */
.rule-status--matched {
  background: var(--color-info-bg);
  border-color: var(--color-border-strong);
  color: var(--color-accent);
}

/* 未符合：**最安靜的狀態**。沒有底色、沒有符號、不是紅色——
   它只是說「今天沒有出現這個型態」。 */
.rule-status--unmatched {
  background: transparent;
  color: var(--color-text-muted);
}

/* 資料不足：與「未符合」明確不同，但同樣不是負面。
   虛線邊框讓它在不依賴顏色的情況下也能被區分出來（同 MA20 用虛線的理由）。

   ⚠️ 邊框刻意用 --color-border-interactive 而不是預設的 --color-border：
      實測 --color-border 在這個面板底色（--color-surface-subtle）上只有
      **1.36:1**，那條虛線幾乎看不見——而它正是「不靠顏色也能區分」的那個訊號，
      看不見就等於這個保證是空的。--color-border-interactive 實測 **3.12:1**，
      通過 WCAG 1.4.11 非文字對比的 3:1 門檻，而且仍是中性藍灰、不帶警告意味。
      （這是瀏覽器實測才發現的：離線測試看得到 `dashed` 這個字，
        看不到它有沒有對比。） */
.rule-status--undecidable {
  background: transparent;
  border-style: dashed;
  border-color: var(--color-border-interactive);
  color: var(--color-text-faint);
}

.rule-check__body {
  flex: 1 1 20ch;           /* 20ch 以下就換行，不把說明擠成一字一行 */
  min-width: 0;
}

.rule-check__name {
  margin: 0;
  font-weight: var(--weight-medium);
  color: var(--color-text);
}

.rule-check__desc {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  line-height: var(--leading-tight);
  color: var(--color-text-muted);
}

/* 「為什麼判定不出來」——比說明再輕一階，但仍然要讀得到。 */
.rule-check__note {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  line-height: var(--leading-tight);
  color: var(--color-text-faint);
}

/* 原始佐證：沿用 .evidence-raw 的字體與顏色，只調整這裡的間距。
   命中與未命中的規則**都有**——「為什麼不符合」同樣要能被驗算（MVP §25.7）。 */
.rule-check .evidence-raw {
  margin-top: var(--space-2);
  word-break: break-word;   /* 窄螢幕時長字串換行，不撐破面板 */
}

/* 漲跌：顏色只是輔助，百分比本身帶 +/- 號 */
td.up,   .quote-change.up   { color: var(--color-positive); font-weight: var(--weight-medium); }
td.down, .quote-change.down { color: var(--color-negative); font-weight: var(--weight-medium); }

/* 結果表的股票代號連結。
   改版前由 app.js 產生但 CSS 沒有對應規則，於是使用瀏覽器預設的 #0000EE
   （已瀏覽變紫色）——與 accent 完全不同的藍，在資料表裡特別明顯。 */
.symbol-link {
  font-family: var(--font-mono);
  font-weight: var(--weight-medium);
  color: var(--color-accent);
  text-decoration: none;
}
.symbol-link:hover { color: var(--color-accent-hover); text-decoration: underline; }
.symbol-link:visited { color: var(--color-accent); }

/* ==========================================================================
   個股頁圖表（B3.1）
   --------------------------------------------------------------------------
   伺服器端產生的 inline SVG。**顏色只在這裡決定**——幾何模組與樣板都不碰
   顏色，否則 SVG 的 stroke="#…" 屬性會繞過「元件內不得有裸色碼」那條測試。

   刻意**不用漲紅跌綠**：在這個專案裡紅=漲、綠=跌（P43），一條紅色的價格線
   在下跌日會直接說謊。三條線用「亮/藍/琥珀」，都沒有既有的方向性含意，
   與 B2 的規則 chip 用 accent 藍是同一個理由。
   ========================================================================== */
.chart-scroll {
  /* 窄螢幕時圖表在自己的容器裡橫向捲動（與歷史表格同一個模式）。
     低於這個寬度，viewBox 會把 18 單位的標籤縮到看不清楚。 */
  margin-top: var(--space-2);
}

.chart {
  display: block;
  width: 100%;
  min-width: 640px;
  height: auto;
}

.chart-grid line {
  stroke: var(--color-border);
  stroke-width: 1;
}

/* 座標文字。18 個 viewBox 單位 ≈ 顯示寬 1020px 時的 18px、
   縮到 640px 時的 11.5px——兩端都還讀得到。 */
.chart-label {
  fill: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: 18px;
  font-variant-numeric: var(--numeric);
}
/* 對齊方式由 chart.py 逐個刻度決定：兩端的日期必須靠邊，
   置中對齊會讓最後一個標籤有一半跑到 viewBox 之外被裁掉。 */
.chart-label--start  { text-anchor: start; }
.chart-label--middle { text-anchor: middle; }
.chart-label--end    { text-anchor: end; }

.chart-bar { fill: var(--color-chart-volume); }

/* ---- K 線（B4）--------------------------------------------------------
   方向是「收盤 vs 開盤」（決定 D2），所以這裡**可以**用漲紅跌綠——
   K 線的實體本身就有方向，而且畫的就是開盤與收盤。上面那三條折線不行，
   是因為一條線沒有方向，紅色的收盤線在下跌日會直接說謊。

   ⚠️ **中空／實心是必要的，不是風格。** --color-positive 對 --color-negative
      只有 **1.42:1**（實測），純靠顏色分不出漲跌；灰階列印與各種色覺條件下
      都一樣。形狀才是真正把兩者分開的東西——與 MA20 用虛線同一個理由。

   對比（實測，非估計，對 --color-surface #111a2b）：
     positive 5.16 · negative 7.30 · neutral 7.30 —— 三者都達 WCAG 1.4.11 的 3.0。

   ⚠️ **body 的 stroke-width 與 chart.py 的 MIN_BODY_HEIGHT 是綁在一起的。**
      SVG 的 stroke 以邊線為中心、往內外各吃一半，所以漲 K 看得見的中空高度是
      `MIN_BODY_HEIGHT - stroke-width`。初版 2.0 配 1.5 → 中空只剩 0.5 單位，
      在 `.chart { min-width: 640px }` 的下限上是 **0.32 CSS px**——那根漲 K
      畫出來就是實心紅方塊，「漲＝中空」因此失效（實測 8.74 % 的漲 K 踩到）。
      現在是 3.0 配 **1.0** → 中空 2.0 單位 = 1.28 CSS px。
      改任一邊都要讓 test_a_minimum_height_up_candle_still_reads_as_hollow 重算。
      影線維持 1.5：它不圍出中空，細一格反而看不見。
   ---------------------------------------------------------------------- */
.chart-wick  { stroke-width: 1.5; }
.chart-candle { stroke-width: 1; }

/* 漲：中空。實體只有外框，所以與實心的跌 K 在灰階下也分得開。 */
.chart-candle--up   { stroke: var(--color-positive); fill: none; }
.chart-candle--down { stroke: var(--color-negative); fill: var(--color-negative); }
/* 平盤（實測 8.0 % 的交易日）：不宣稱方向，用中性色。

   ⚠️ **灰階下把平盤與跌分開的是高度，不是顏色。** --color-negative 與
      --color-neutral 的相對亮度**完全一樣**（實測 1.00:1），而且兩者都是實心的。
      平盤的實體固定夾在 MIN_FLAT_BODY_HEIGHT（方向 K 的 1/3），畫出來約是
      跌 K 下限的一半高——那個落差是唯一不靠顏色的區分。
      換顏色救不了：與 --color-negative 達 3.0:1 的顏色，對 --color-surface
      最多只有 2.43:1，達不到 WCAG 1.4.11 的 3.0。 */
.chart-candle--flat { stroke: var(--color-neutral);  fill: var(--color-neutral); }

.chart-line {
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* B4：收盤折線已移除（決定 D1）——K 線的實體上下緣就是開盤與收盤，
   再疊一條 2.5 寬的亮白線只會蓋住實體，而且是同一個數字講兩次。 */
.chart-line--ma5   { stroke: var(--color-accent); stroke-width: 1.75; }

/* MA20 用虛線：顏色不是唯一的區分方式，灰階列印與各種色覺都分得開。 */
.chart-line--ma20 {
  stroke: var(--color-warning);
  stroke-width: 1.75;
  stroke-dasharray: 7 5;
}

/* 判定區塊本身看不見，只負責承載原生 <title> 提示。 */
.chart-hotspot { fill: transparent; }
.chart-hotspot:hover { fill: var(--color-surface-raised); fill-opacity: 0.35; }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin: 0 0 var(--space-2) 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
}
.chart-legend__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* 圖例的線段樣本用 border-top 畫，才能真的呈現實線／虛線的差別。 */
.chart-legend__swatch {
  display: inline-block;
  width: 22px;
  border-top-style: solid;
  border-top-width: 3px;
}
.chart-legend__swatch.chart-line--ma5   { border-top-color: var(--color-accent); }
.chart-legend__swatch.chart-line--ma20 {
  border-top-color: var(--color-warning);
  border-top-style: dashed;
}
/* K 線的圖例樣本是一個小方塊，不是線段——中空與實心的差別要看得出來。 */
.chart-legend__swatch--candle {
  width: 10px;
  height: 16px;
  border: 2px solid var(--color-neutral);
}
.chart-legend__swatch--up   { border-color: var(--color-positive); background: none; }
.chart-legend__swatch--down { border-color: var(--color-negative); background: var(--color-negative); }
/* 平盤的樣本是一條扁的橫槓，不是方塊——圖例要畫的是圖上真的看得到的形狀，
   而圖上的平盤實體就是矮的那一種。兩個實心方塊只差顏色的圖例，等於沒有圖例
   （negative 與 neutral 的亮度實測 1.00:1）。 */
.chart-legend__swatch--flat {
  border-color: var(--color-neutral);
  background: var(--color-neutral);
  height: 6px;
}

.chart-legend__swatch--volume {
  border-top-color: var(--color-chart-volume);
  border-top-width: 10px;
}

.chart-legend__label { color: var(--color-text-muted); }

/* 「資料不足」必須有文字，不能只是把線拿掉——線消失了沒有人知道為什麼。 */
.chart-legend__note {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}

/* 錯誤紀錄表格：改版前借用 table.history，改個股頁會連帶改到這裡 */
table.log td a {
  font-family: var(--font-mono);
  color: var(--color-accent);
  text-decoration: none;
}
table.log td a:hover { text-decoration: underline; }
td.message {
  white-space: normal;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  max-width: 60ch;
}

/* --- 指標表：價格與量能是兩個量級 ----------------------------------------- */
table.indicators { border-collapse: collapse; margin-top: var(--space-2); }
table.indicators th, table.indicators td {
  padding: var(--cell-pad-y) 1.25rem var(--cell-pad-y) 0;
  text-align: left;
  border-bottom: var(--border-width) solid var(--color-border);
}
table.indicators thead th { color: var(--color-text-muted); font-weight: var(--weight-medium); }
table.indicators tbody th {
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}
table.indicators td.na { color: var(--color-text-faint); }

/* ==========================================================================
   個股明細
   ========================================================================== */
.crumb { margin: var(--space-4) 0 0; }
.crumb a { color: var(--color-accent); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }

.tag {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 0.05rem var(--space-2);
  border: var(--border-width) solid var(--color-border-interactive);
  border-radius: var(--radius-sm);
  background: var(--color-surface-raised);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}
.tag-warn { border-color: var(--color-warning); color: var(--color-warning); }

.quote { margin: var(--space-2) 0 var(--space-4); }
.quote-main { display: flex; align-items: baseline; gap: var(--space-3); }
.quote-close {
  font-size: var(--text-display);
  font-weight: var(--weight-bold);
  font-variant-numeric: var(--numeric);
  letter-spacing: -0.02em;
  line-height: var(--leading-tight);
}
.quote-change { font-size: var(--text-lg); font-variant-numeric: var(--numeric); }

.provenance {
  margin-top: var(--space-4);
  padding: 0.6rem 0.9rem;
  border-left: var(--border-width-accent) solid var(--color-border-interactive);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--color-surface-subtle);
  font-size: 0.88rem;
  color: var(--color-text-muted);
}

/* --- 頁尾（A3 / A6 出處註記）---------------------------------------------- */
.site-footer {
  margin-top: var(--space-6);
  padding-top: var(--space-3);
  border-top: var(--border-width) solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.site-footer p { margin: 0.2rem 0; }

/* ==========================================================================
   響應式（改版前整份 CSS 沒有任何 @media）
   桌機優先，但任何寬度下**頁面本身都不得橫向捲動**。
   ========================================================================== */

/* 寬螢幕：讓掃描結果掙脫 1100px 的文章寬度。
   改版前結果表需要 1449px 卻被關在 1027px 容器裡，佐證欄被裁掉 422px。 */
@media (min-width: 1600px) {
  #results-panel {
    margin-inline: calc((var(--content-width) - var(--content-width-wide)) / 2);
  }
}

/* 中等寬度：代號欄釘住，橫向捲動時仍知道自己在看哪一檔 */
@media (max-width: 1599px) {
  table#results-table thead th:first-child,
  table#results-table tbody td:first-child {
    position: sticky;
    left: 0;
    border-right: var(--border-width) solid var(--color-border);
  }
  table#results-table tbody td:first-child { background: var(--color-surface); }
  table#results-table thead th:first-child { background: var(--color-surface-raised); }
  table#results-table tbody tr:hover td:first-child { background: var(--color-surface-raised); }
}

@media (max-width: 1023px) {
  :root {
    --cell-pad-x: 0.5rem;
    --cell-pad-y: 0.35rem;
  }
  body { padding-inline: var(--space-3); }
  .site-header { gap: var(--space-3); }
  .panel { padding: var(--space-3) var(--space-4); }

  /* 改版前這兩張表沒有捲動容器，窄螢幕時會把版面撐開 */
  .kv, table.indicators {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .result-box dl { grid-template-columns: 1fr; }
  .result-box dt { margin-top: var(--space-1); color: var(--color-text-faint); }
  .table-scroll--tall { max-height: 60vh; }
}

@media (max-width: 700px) {
  body { font-size: 14px; }
  .site-header h1 { font-size: var(--text-lg); }
  /* 查詢框在窄螢幕吃滿一整列——375px 下 h1 + nav 已經用掉整個寬度，
     再讓它擠在同一行只會兩邊都變得太小（實測，見 §11 Q12）。
     min-height 44px 是觸控目標下限，不是視覺偏好。 */
  .symbol-lookup { width: 100%; margin-left: 0; }
  .symbol-lookup__input { flex: 1; min-width: 0; min-height: 44px; }
  .symbol-lookup__submit { min-height: 44px; padding-inline: var(--space-4); }
  .quote-close { font-size: 1.6rem; }
  .rule-desc { margin-left: 0; }
  /* 觸控目標 */
  .rule-list li { padding: var(--space-3); }
  button.primary { padding: var(--space-3) var(--space-4); }
}

/* 尊重系統的「減少動態效果」設定 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  button.primary:active:not(:disabled) { transform: none; }
}
